diff --git a/CHANGELOG.md b/CHANGELOG.md index 755b629..61928a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,30 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [2.0.1](https://github.com/rdkcentral/rdkNativeScript/compare/2.0...2.0.1) + +- RDKEMW-11507: Viper IPA not working with rdknative widget [`#100`](https://github.com/rdkcentral/rdkNativeScript/pull/100) +- Merge tag '2.0' into develop [`51a0410`](https://github.com/rdkcentral/rdkNativeScript/commit/51a04109cb17643687722ed8b96da89929791cfb) + +#### [2.0](https://github.com/rdkcentral/rdkNativeScript/compare/1.0.10...2.0) + +- RDKEMW-9355: Add Support to run app widgets in different contexts wit… [`#90`](https://github.com/rdkcentral/rdkNativeScript/pull/90) +- RDKEMW-8844: Analyse and Improve L1 coverage [`#79`](https://github.com/rdkcentral/rdkNativeScript/pull/79) +- RDKEMW-9785: Increasing Test Coverage for L1 test [`#95`](https://github.com/rdkcentral/rdkNativeScript/pull/95) +- RDKEMW-11265: Migrate L1 and native build workflow to rdk-e [`#93`](https://github.com/rdkcentral/rdkNativeScript/pull/93) +- RDKEMW-9172: L2testcase for rdkNativeScript [`#91`](https://github.com/rdkcentral/rdkNativeScript/pull/91) +- RDKEMW-9461:Nativescript Minimal build for Coverity [`#84`](https://github.com/rdkcentral/rdkNativeScript/pull/84) +- RDKEMW-9355: Add Support to run app widgets in different contexts within a single process [`f2fbbe9`](https://github.com/rdkcentral/rdkNativeScript/commit/f2fbbe9eec146be3b91a8aa550dddb26ff43d2ff) +- RDKEMW-8844: Improve L1 coverage [`605e0ad`](https://github.com/rdkcentral/rdkNativeScript/commit/605e0ad2b4a9241aeceb5311ac4eaa53dd7b17fd) +- Update src/linux/KeyInput.cpp [`3e0f65c`](https://github.com/rdkcentral/rdkNativeScript/commit/3e0f65cf6a9d560b26e5a0ee6c26350d48046ded) + #### [1.0.10](https://github.com/rdkcentral/rdkNativeScript/compare/1.0.9...1.0.10) -- RDKEMW-9765 : [BUG_FIX]UserAgent string need to be aligned with browser for diff… [`#77`](https://github.com/rdkcentral/rdkNativeScript/pull/77) -- RDKEMW-9765 : [BUG_FIX]UserAgent string need to be aligned with browser for different agents [`881b332`](https://github.com/rdkcentral/rdkNativeScript/commit/881b332528ae114f0a9c2f767c8a1436154d380c) +> 31 October 2025 + +- RDKEMW-9765 : UserAgent string need to be aligned with browser for diff… [`#77`](https://github.com/rdkcentral/rdkNativeScript/pull/77) +- RDKEMW-9765 : UserAgent string need to be aligned with browser for different agents [`881b332`](https://github.com/rdkcentral/rdkNativeScript/commit/881b332528ae114f0a9c2f767c8a1436154d380c) +- 1.0.10 release changelog updates [`6233823`](https://github.com/rdkcentral/rdkNativeScript/commit/62338232511edac45b4aa7c1a0c1622909c29098) - Merge tag '1.0.9' into develop [`b60efc0`](https://github.com/rdkcentral/rdkNativeScript/commit/b60efc01bf49975196c7a55aa3e6736af753916b) #### [1.0.9](https://github.com/rdkcentral/rdkNativeScript/compare/1.0.8...1.0.9) @@ -32,13 +52,11 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). > 30 September 2025 -- DELIA-68967 : Switching between Xumo Fast Channels and Vipa activated… [`#68`](https://github.com/rdkcentral/rdkNativeScript/pull/68) - RDKEMW-5610 : L1 test cases for jsruntime [`#66`](https://github.com/rdkcentral/rdkNativeScript/pull/66) - Deploy fossid_integration_stateless_diffscan_target_repo action [`#67`](https://github.com/rdkcentral/rdkNativeScript/pull/67) - Deploy cla action [`#40`](https://github.com/rdkcentral/rdkNativeScript/pull/40) - Update CODEOWNERS [`#63`](https://github.com/rdkcentral/rdkNativeScript/pull/63) - 1.0.7 release changelog updates [`0f3be4f`](https://github.com/rdkcentral/rdkNativeScript/commit/0f3be4fecad9213a4d86c828e978c29199e5d190) -- DELIA-68967 : Switching between Xumo Fast Channels and Vipa activated Channels [`228cf8b`](https://github.com/rdkcentral/rdkNativeScript/commit/228cf8bfdde6d7f7d991805193038b392bc0e89b) - Merge tag '1.0.6' into develop [`afdf341`](https://github.com/rdkcentral/rdkNativeScript/commit/afdf341c4f81e7019d76f207c7b428dbd0ffc00d) #### [1.0.6](https://github.com/rdkcentral/rdkNativeScript/compare/1.0.5...1.0.6) @@ -115,6 +133,4 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). - RDKEMW-2469 : Merging latest changes of rdknativescript [`#4`](https://github.com/rdkcentral/rdkNativeScript/pull/4) - RDKEMW-2469 : Merging latest changes of javascriptcore and rdknativescript for rdke build [`#3`](https://github.com/rdkcentral/rdkNativeScript/pull/3) - Bring latest changes till 2024 [`#2`](https://github.com/rdkcentral/rdkNativeScript/pull/2) -- RDK-56154 Merging all rdknativescript latest changes to rdkcentral github from comcast rdke github [`2542b7c`](https://github.com/rdkcentral/rdkNativeScript/commit/2542b7cac0c0c0dd1aef7d8b158e5dd63b56347e) - Import of Comcast source (develop) [`dfc9b89`](https://github.com/rdkcentral/rdkNativeScript/commit/dfc9b89df42fb0b844e04624b13808333afb19ce) -- RDK-56154: Merging all rdknativescript latest changes [`0d8189e`](https://github.com/rdkcentral/rdkNativeScript/commit/0d8189e76bdfa9f2cf619af300d95e5ec8f4def9) diff --git a/CMakeLists.txt b/CMakeLists.txt index df6acc3..35ffbc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,8 +118,8 @@ set(JSRUNTIME_APP_FILES if ( ENABLE_JSRUNTIME_SERVER ) add_definitions("-DENABLE_JSRUNTIME_SERVER") - add_definitions("-DWS_SERVER_PORT=9112") - set (JSRUNTIME_APP_FILES ${JSRUNTIME_APP_FILES} + add_definitions("-DWS_SERVER_PORT=5000") + set (JSRUNTIME_COMMON_FILES ${JSRUNTIME_COMMON_FILES} ${JSRUNTIME_COMMON_SOURCE_DIRECTORY}/JSRuntimeServer.cpp ) endif ( ENABLE_JSRUNTIME_SERVER ) @@ -134,6 +134,16 @@ add_library(${JSRUNTIME_LIBRARY_NAME} SHARED ${JSRUNTIME_ENGINE_FILES} ) +#JSRUNTIMECLIENTCONTAINER CHANGES +option(BUILD_JSRUNTIME_CONTAINER "BUILD_JSRUNTIME_CONTAINER" ON) +set(JSRUNTIME_CONTAINER_FILES + ${JSRUNTIME_COMMON_SOURCE_DIRECTORY}/JSRuntimeClientContainer.cpp +) +set(JSRUNTIME_FILES + ${JSRUNTIME_COMMON_SOURCE_DIRECTORY}/JSRuntimeContainer.cpp + ${JSRUNTIME_COMMON_SOURCE_DIRECTORY}/NativeJSLogger.cpp +) + set(JSRUNTIME_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/${JSRUNTIME_ENGINE_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/include/linux ${CMAKE_CURRENT_SOURCE_DIR}/src/jsc/jsc_lib ${JSRUNTIME_ENGINE_INCLUDE_DIRECTORIES}) set(JSRUNTIME_LIBRARY_LINK_DIRECTORIES ${JSRUNTIME_ENGINE_LIBRARY_LINK_DIRECTORIES}) @@ -192,6 +202,21 @@ if (BUILD_JSRUNTIME_CLIENT) target_link_libraries(jsruntime_client ${JSRUNTIME_LIBRARY_LINK_DIRECTORIES} ${JSRUNTIME_LINK_ETHANLIB} -lpthread) endif (BUILD_JSRUNTIME_CLIENT) +set(JSRUNTIMECONTAINER_LIBRARY_NAME "JSRuntimeContainer") + +if (BUILD_JSRUNTIME_CONTAINER) + add_library(${JSRUNTIMECONTAINER_LIBRARY_NAME} SHARED ${JSRUNTIME_FILES}) + target_include_directories(${JSRUNTIMECONTAINER_LIBRARY_NAME} PRIVATE ${JSRUNTIME_INCLUDE_DIRECTORIES}) + target_link_libraries(${JSRUNTIMECONTAINER_LIBRARY_NAME} ${JSRUNTIME_LIBRARY_LINK_DIRECTORIES} -lpthread) + + add_executable(jsruntime_container ${JSRUNTIME_CONTAINER_FILES}) + add_dependencies(jsruntime_container ${JSRUNTIMECONTAINER_LIBRARY_NAME}) + target_include_directories(jsruntime_container PRIVATE ${JSRUNTIME_INCLUDE_DIRECTORIES}) + set_target_properties(jsruntime_container PROPERTIES OUTPUT_NAME "JSRuntimeContainer") + target_link_libraries(jsruntime_container ${JSRUNTIME_LIBRARY_LINK_DIRECTORIES} -l${JSRUNTIMECONTAINER_LIBRARY_NAME} ${JSRUNTIME_LINK_ETHANLIB} -lpthread) + +endif (BUILD_JSRUNTIME_CONTAINER) + set(UWEBSOCKETS_TARGET "Linux") if (APPLE) set(UWEBSOCKETS_TARGET "Darwin") diff --git a/include/JSRuntimeContainer.h b/include/JSRuntimeContainer.h new file mode 100644 index 0000000..7a0d6cf --- /dev/null +++ b/include/JSRuntimeContainer.h @@ -0,0 +1,43 @@ +#ifndef JSRUNTIMECONTAINER_H +#define JSRUNTIMECONTAINER_H + +#include +#include +#include + +class JSRuntimeContainer +{ +public: + enum Namespace { + NetworkNamespace = 0x01, + MountNamespace = 0x02, + IpcNamespace = 0x04, + PidNamespace = 0x08, + UserNamespace = 0x10, + UtsNamespace = 0x20 + }; + + // Get container IP address + static std::string getContainerIpAddress(const std::string& containerId); + + // Check if container exists + static bool isContainer(const std::string& containerId); + + // Execute function in container namespace + static bool nsEnter(const std::string& containerId, Namespace type, const std::function& func); + + // WebSocket client functions + static bool connectAndSend(const std::string& ip, const std::string& message); + static std::string buildLaunchMessage(const std::string& url, const std::string& options); + static std::string parseAppConfig(const std::string& configPath); + +private: + // Internal implementation functions + static bool nsEnterImpl(const std::string& containerId, Namespace type, const std::function& func); + static pid_t findContainerPid(const std::string& containerId); + static bool nsEnterWithPid(pid_t pid, int nsType, const std::function& func); + static void nsThread(int newNsFd, int nsType, bool* success, const std::function& func); +}; + +#endif // JSRUNTIMECONTAINER_H + diff --git a/include/JSRuntimeServer.h b/include/JSRuntimeServer.h index d9f0616..b56690c 100644 --- a/include/JSRuntimeServer.h +++ b/include/JSRuntimeServer.h @@ -19,6 +19,7 @@ #pragma once #include +#include #ifdef USE_WEBSOCKET_MOCK #include "websocketpp.hpp" @@ -40,7 +41,7 @@ class JSRuntimeServer static JSRuntimeServer *getInstance(); ~JSRuntimeServer() = default; - void initialize(int serverport, std::shared_ptr renderer); + void initialize(int serverport, std::shared_ptr renderer, std::shared_ptr externalHandler = nullptr); bool start(); bool stop(); @@ -77,4 +78,5 @@ class JSRuntimeServer ConnectionSet mConnections; int mServerPort; std::shared_ptr mRenderer; + std::shared_ptr mExternalHandler; }; diff --git a/src/JSRuntimeClientContainer.cpp b/src/JSRuntimeClientContainer.cpp new file mode 100644 index 0000000..8382be2 --- /dev/null +++ b/src/JSRuntimeClientContainer.cpp @@ -0,0 +1,31 @@ +#include "JSRuntimeContainer.h" +#include +#include +#include +#include +#include "NativeJSLogger.h" +int main() +{ + std::string containerId = "com.sky.as.apps_TestApp"; + const std::string basePath = "/opt/twocontext"; // constant base path + const std::vector apps = {"app1", "app2"}; + + std::string ipAddress = JSRuntimeContainer::getContainerIpAddress(containerId); + if (ipAddress.empty()) { + NativeJSLogger::log(ERROR, "Failed to retrieve IP address for container"); + return 1; + } + + for (const auto &app : apps) { + std::string url = basePath + std::string("/") + app + std::string("/index.html"); + if (access(url.c_str(), F_OK) == 0) { + std::string pathAppConfig = basePath + std::string("/") + app + std::string("/app.config"); + std::string options = JSRuntimeContainer::parseAppConfig(pathAppConfig); + std::string message = JSRuntimeContainer::buildLaunchMessage(url, options); + JSRuntimeContainer::connectAndSend(ipAddress, message); + } + } + + return 0; +} + diff --git a/src/JSRuntimeContainer.cpp b/src/JSRuntimeContainer.cpp new file mode 100644 index 0000000..4952eda --- /dev/null +++ b/src/JSRuntimeContainer.cpp @@ -0,0 +1,302 @@ +// JSRuntimeContainer.cpp +#include "JSRuntimeContainer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rapidjson/document.h" +#ifndef USE_WEBSOCKET_MOCK +#include +#include +#endif + +using namespace rapidjson; + +#ifndef USE_WEBSOCKET_MOCK +typedef websocketpp::client SimpleClient; +#endif + +void JSRuntimeContainer::nsThread(int newNsFd, int nsType, bool* success, const std::function& func) +{ + if (setns(newNsFd, nsType) != 0) + { + std::cerr << "Failed to switch into new namespace: " << strerror(errno) << std::endl; + *success = false; + return; + } + + func(); + *success = true; +} + +// Enter namespace using PID +bool JSRuntimeContainer::nsEnterWithPid(pid_t pid, int nsType, const std::function& func) +{ + const char* nsName; + + switch (nsType) + { + case CLONE_NEWIPC: + nsName = "ipc"; + break; + case CLONE_NEWNET: + nsName = "net"; + break; + case CLONE_NEWNS: + nsName = "mnt"; + break; + case CLONE_NEWPID: + nsName = "pid"; + break; + case CLONE_NEWUSER: + case CLONE_NEWUTS: + std::cerr << "Unsupported namespace type: " << nsType << std::endl; + return false; + default: + std::cerr << "Invalid namespace type: " << nsType << std::endl; + return false; + } + + char nsPath[64]; + snprintf(nsPath, sizeof(nsPath), "/proc/%d/ns/%s", pid, nsName); + + int newNsFd = open(nsPath, O_RDONLY | O_CLOEXEC); + if (newNsFd < 0) + { + std::cerr << "Failed to open container namespace: " << nsPath << " - " << strerror(errno) << std::endl; + return false; + } + + bool success = false; + + std::thread thread([=, &success, &func]() { + nsThread(newNsFd, nsType, &success, func); + }); + thread.join(); + + close(newNsFd); + + return success; +} + +// Find a PID inside the container +pid_t JSRuntimeContainer::findContainerPid(const std::string& containerId) +{ + std::string cgroupPath = "/sys/fs/cgroup/memory/" + containerId + "/cgroup.procs"; + + std::ifstream file(cgroupPath); + if (!file.is_open()) + { + return -1; + } + + std::string line; + if (!std::getline(file, line) || line.empty()) + { + return -1; + } + + long pid = std::strtol(line.c_str(), nullptr, 10); + if (pid >= INT32_MAX || pid <= 0) + { + return -1; + } + + return static_cast(pid); +} + +bool JSRuntimeContainer::nsEnterImpl(const std::string& containerId, Namespace type, const std::function& func) +{ + pid_t containerPid = findContainerPid(containerId); + if (containerPid <= 0) + { + return false; + } + + switch (type) + { + case NetworkNamespace: + return nsEnterWithPid(containerPid, CLONE_NEWNET, func); + case MountNamespace: + return nsEnterWithPid(containerPid, CLONE_NEWNS, func); + case IpcNamespace: + return nsEnterWithPid(containerPid, CLONE_NEWIPC, func); + default: + std::cerr << "Unknown namespace type" << std::endl; + return false; + } +} + +bool JSRuntimeContainer::nsEnter(const std::string& containerId, Namespace type, const std::function& func) +{ + return nsEnterImpl(containerId, type, func); +} + +std::string JSRuntimeContainer::getContainerIpAddress(const std::string& containerId) +{ + std::string ipAddress = ""; + + auto getIpAddress = [&ipAddress]() { + int sock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); + if (sock < 0) + { + return; + } + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, "eth0"); + + if (ioctl(sock, SIOCGIFADDR, &ifr) < 0) + { + close(sock); + return; + } + + close(sock); + + struct sockaddr_in* ifaceAddr = reinterpret_cast(&ifr.ifr_addr); + char* ip = inet_ntoa(ifaceAddr->sin_addr); + if (ip != nullptr) + { + ipAddress = std::string(ip); + } + }; + + if (nsEnterImpl(containerId, NetworkNamespace, getIpAddress) && !ipAddress.empty()) + { + return ipAddress; + } + + return ""; +} + +bool JSRuntimeContainer::isContainer(const std::string& containerId) +{ + std::string cgroupPath = "/sys/fs/cgroup/memory/" + containerId + "/cgroup.procs"; + return (access(cgroupPath.c_str(), F_OK) == 0); +} + +bool JSRuntimeContainer::connectAndSend(const std::string& ip, const std::string& message) +{ +#ifdef USE_WEBSOCKET_MOCK + // In mock builds, just return true + return true; +#else + websocketpp::lib::error_code ec; + SimpleClient c; + c.clear_access_channels(websocketpp::log::alevel::all); + c.clear_error_channels(websocketpp::log::elevel::all); + c.init_asio(); + + std::string uri = std::string("ws://") + ip + std::string(":") + std::to_string(WS_SERVER_PORT); + SimpleClient::connection_ptr con = c.get_connection(uri, ec); + if (ec) { + return false; + } + + websocketpp::connection_hdl hdl = con->get_handle(); + c.connect(con); + + std::thread t(&SimpleClient::run, &c); + + // Wait briefly for open + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + try { + c.send(hdl, message, websocketpp::frame::opcode::text); + } catch (...) {} + + c.close(hdl, websocketpp::close::status::going_away, "bye", ec); + t.join(); + return true; +#endif +} + +// Build launchApplication JSON payload for a given URL and options +std::string JSRuntimeContainer::buildLaunchMessage(const std::string &url, const std::string& options) +{ + std::ostringstream oss; + oss << "{\"method\": \"launchApplication\", \"params\":{\"url\":\"" << url << "\",\"moduleSettings\":\"" << options << "\"}}"; + std::string message = oss.str(); + return message; +} + +std::string JSRuntimeContainer::parseAppConfig(const std::string& configPath) +{ + + std::string optionsStr; + std::ifstream fd(configPath); + if (!fd.is_open()) { + return optionsStr; + } + + std::stringstream buffer; + buffer << fd.rdbuf(); + std::string configData = buffer.str(); + fd.close(); + + Document configDoc; + if (configDoc.Parse(configData.c_str()).HasParseError()) { + return optionsStr; + } + + if (!configDoc.IsObject()) { + return optionsStr; + } + + if (configDoc.HasMember("features") && configDoc["features"].IsArray()) + { + const Value& flagsarr = configDoc["features"]; + for (SizeType i = 0; i < flagsarr.Size(); i++) { + const Value& flagOption = flagsarr[i]; + if (!flagOption.IsObject()) + continue; + + if (flagOption.HasMember("name") && flagOption.HasMember("enable")) { + const Value& name = flagOption["name"]; + const Value& enable = flagOption["enable"]; + + if (enable == true) { + std::string featureName = name.GetString(); + std::cout << "[DEBUG] parseAppConfig - processing enabled feature: " << featureName << std::endl; + + if (name == "player") + optionsStr += "player,"; + else if (name == "xhr") + optionsStr += "xhr,"; + else if (name == "websocket") + optionsStr += "ws,"; + else if (name == "http") + optionsStr += "http,"; + else if (name == "websocketenhanced") + optionsStr += "wsenhanced,"; + else if (name == "fetch") + optionsStr += "fetch,"; + else if (name == "jsdom") + optionsStr += "jsdom,"; + else if (name == "window") + optionsStr += "window,"; + + } + } + } + } + + if (!optionsStr.empty() && optionsStr.back() == ',') + optionsStr.pop_back(); + + return optionsStr; +} + + diff --git a/src/JSRuntimeServer.cpp b/src/JSRuntimeServer.cpp index 340a070..342f386 100644 --- a/src/JSRuntimeServer.cpp +++ b/src/JSRuntimeServer.cpp @@ -114,12 +114,15 @@ JSRuntimeServer::JSRuntimeServer() : mServerPort(0) { } -void JSRuntimeServer::initialize(int serverport, std::shared_ptr renderer) +void JSRuntimeServer::initialize(int serverport, std::shared_ptr renderer, std::shared_ptr externalHandler) { - NativeJSLogger::log(INFO, "Enter: %s\n", __func__); + NativeJSLogger::log(INFO, "JSRuntimeServer::initialize - port=%d, externalHandler=%p\n", serverport, externalHandler.get()); mServerPort = serverport; mRenderer = renderer; + mExternalHandler = externalHandler; + + NativeJSLogger::log(INFO, "JSRuntimeServer initialized - mExternalHandler=%p\n", mExternalHandler.get()); } bool JSRuntimeServer::start() @@ -202,7 +205,40 @@ void JSRuntimeServer::onMessage(websocketpp::connection_hdl hdl, message_ptr msg { break; } - if (method == "launchApplication") + if (method == "runExternalApplication") + { + JsonWrap jParams(jRoot, "params"); + if (jParams.get() == nullptr) + { + result = "error: missing params"; + break; + } + uint32_t id = jParams.getUint32("id", error); + if (error) + { + result = "error: invalid or missing id"; + break; + } + + std::string url = jParams.getString("url", error); + if (error) + { + result = "error: invalid or missing url"; + break; + } + + if (!mExternalHandler) + { + result = "error: external handler not available"; + NativeJSLogger::log(ERROR, "External handler not initialized\n"); + break; + } + + mExternalHandler->runExternalApplication(url, id); + result = "ok"; + NativeJSLogger::log(INFO, "Queued external application: id=%d, url=%s\n", id, url.c_str()); + } + else if (method == "launchApplication") { JsonWrap jParams(jRoot, "params"); if (jParams.get() == nullptr) @@ -217,13 +253,26 @@ void JSRuntimeServer::onMessage(websocketpp::connection_hdl hdl, message_ptr msg std::string options = jParams.getString("moduleSettings", error); ModuleSettings moduleSettings; moduleSettings.fromString(options); - uint32_t id = mRenderer->createApplication(moduleSettings); - mRenderer->runApplication(id, url); + uint32_t id = mRenderer->createApplication(moduleSettings); + + NativeJSLogger::log(INFO, "launchApplication: checking URL=%s for HTML extension\n", url.c_str()); + if (url.find(".html") != std::string::npos || url.find(".htm") != std::string::npos) + { + NativeJSLogger::log(INFO, "Detected HTML file, mExternalHandler=%p\n", mExternalHandler.get()); + if (mExternalHandler) + { + mExternalHandler->runExternalApplication(url, id); + } + } + else + { + mRenderer->runApplication(id, url); + } std::ostringstream oss; - oss<< "ID : " << id; - result = oss.str(); + oss<< "ID : " << id; + result = oss.str(); } - if (method == "createApplication") + else if (method == "createApplication") { JsonWrap jParams(jRoot, "params"); if (jParams.get() == nullptr) @@ -242,7 +291,7 @@ void JSRuntimeServer::onMessage(websocketpp::connection_hdl hdl, message_ptr msg oss<< "ID : " << id; result = oss.str(); } - if (method == "runApplication") + else if (method == "runApplication") { JsonWrap jParams(jRoot, "params"); if (jParams.get() == nullptr) diff --git a/src/JavaScriptContextBase.cpp b/src/JavaScriptContextBase.cpp index 086b7c9..3128195 100644 --- a/src/JavaScriptContextBase.cpp +++ b/src/JavaScriptContextBase.cpp @@ -77,7 +77,7 @@ void JavaScriptContextBase::registerCommonUtils() } } -std::string JavaScriptContextBase::readFile(const char *file) +/*std::string JavaScriptContextBase::readFile(const char *file) { bool isModule = true; std::ifstream src_file; @@ -97,6 +97,47 @@ std::string JavaScriptContextBase::readFile(const char *file) src_script << src_file.rdbuf(); } return src_script.str(); +}*/ +std::string JavaScriptContextBase::readFile(const char *file) +{ + bool isModule = true; + std::ifstream src_file; + std::stringstream src_script; + struct stat path; + + // Try CWD first + if(stat(file, &path) == 0){ + isModule = false; + } + if(!isModule){ + src_file.open(file); + src_script << src_file.rdbuf(); + return src_script.str(); // <--- Early return if found in CWD! + } + + // Try sModulesPath + file + std::string fileName = sModulesPath + std::string(file); + std::cout << "[DEBUG] JS module loader: Trying " << fileName << std::endl; + src_file.open(fileName); + if(src_file.is_open()) { + src_script << src_file.rdbuf(); + return src_script.str(); + } + + // If not found, and not ending with '.js', try adding '.js' + std::string fileStr(file); + if(fileStr.size() < 3 || fileStr.substr(fileStr.size()-3) != ".js") { + std::string fileNameJs = sModulesPath + fileStr + ".js"; + std::cout << "[DEBUG] JS module loader: Trying " << fileNameJs << std::endl; + src_file.open(fileNameJs); + if(src_file.is_open()) { + src_script << src_file.rdbuf(); + return src_script.str(); + } + } + + std::cout << "[ERROR] JS module loader: Could not find " << file << " as " << fileName << " or " << fileName << ".js" << std::endl; + return src_script.str(); } bool JavaScriptContextBase::runFile(const char *file, const char* args, bool isApplication) diff --git a/src/jsc/modules/windowwrapper.js b/src/jsc/modules/windowwrapper.js index dd87e0a..f281c4c 100755 --- a/src/jsc/modules/windowwrapper.js +++ b/src/jsc/modules/windowwrapper.js @@ -23,7 +23,7 @@ try { window = jsdom.window; window.location = {"href":"", "host":"127.0.0.1", "protocol":"http"} - /* + window.frames = [] window.screen = { "width":1920, @@ -32,7 +32,79 @@ try "availHeight":1080 } screen = window.screen; - */ + + var BlobPolyfill = function(parts, options) + { + parts = parts || []; + options = options || {}; + this.size = 0; + this.type = options.type || ''; + this._parts = parts; + + for (var i = 0; i < parts.length; i++) + { + if (typeof parts[i] === 'string') + { + this.size += parts[i].length; + } + else if (parts[i] && parts[i].byteLength) + { + this.size += parts[i].byteLength; + } + } + }; + + BlobPolyfill.prototype.slice = function(start, end, contentType) + { + return new BlobPolyfill(this._parts, { type: contentType || this.type }); + }; + + BlobPolyfill.prototype.text = function() + { + var text = ''; + for (var i = 0; i < this._parts.length; i++) + { + if (typeof this._parts[i] === 'string') + { + text += this._parts[i]; + } + } + return Promise.resolve(text); + }; + + BlobPolyfill.prototype.arrayBuffer = function() + { + return Promise.resolve(new ArrayBuffer(0)); + }; + + if (typeof global.Blob === 'undefined') { + global.Blob = BlobPolyfill; + } + if (typeof window !== 'undefined' && typeof window.Blob === 'undefined') { + window.Blob = BlobPolyfill; + } + if (typeof self !== 'undefined' && typeof self.Blob === 'undefined') { + self.Blob = BlobPolyfill; + } + if (typeof this !== 'undefined' && typeof this.Blob === 'undefined') { + this.Blob = BlobPolyfill; + } + if (typeof window !== 'undefined') { + + if (!window.top) window.top = window; + if (!window.parent) window.parent = window; + + if (!window.__tcfapi) { + window.__tcfapi = function(cmd, ver, callback) { + if (callback) callback({gdprApplies: false}, true); + }; + } + if (!window.__uspapi) { + window.__uspapi = function(cmd, ver, callback) { + if (callback) callback({uspString: '1---'}, true); + }; + } + } } } catch(err) diff --git a/src/jsruntime.cpp b/src/jsruntime.cpp index 2198a53..9824b49 100644 --- a/src/jsruntime.cpp +++ b/src/jsruntime.cpp @@ -17,6 +17,7 @@ * limitations under the License. **/ +//Test pull-request #include #include #if defined(ENABLE_JSRUNTIME_SERVER) @@ -122,7 +123,7 @@ int main(int argc, char* argv[]) if (runServer == true) { JSRuntimeServer *server = JSRuntimeServer::getInstance(); - server->initialize(WS_SERVER_PORT, renderer); + server->initialize(WS_SERVER_PORT, renderer, nullptr); server->start(); } #endif