From 2e18ed3efaf72126322bc148e6ea4ebee4f88b33 Mon Sep 17 00:00:00 2001 From: Sidhanth B H Date: Wed, 12 Nov 2025 11:16:08 +0530 Subject: [PATCH 01/19] RDK-59281:Modifying JSRuntime Widget for VIPA playback in 8.2_VIPA branch Reason for change: Resolve VIPA playback issue Test Procedure: Build should be successful Risk:low Priority:P2 --- src/jsc/modules/lib/URLSearchParams.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jsc/modules/lib/URLSearchParams.js b/src/jsc/modules/lib/URLSearchParams.js index 7729b0b..d724f26 100644 --- a/src/jsc/modules/lib/URLSearchParams.js +++ b/src/jsc/modules/lib/URLSearchParams.js @@ -2,7 +2,8 @@ const urlencoded = require("./urlencoded"); exports.implementation = class URLSearchParamsImpl { - constructor(globalObject, constructorArgs, { doNotStripQMark = false }) { + constructor(globalObject, constructorArgs = [""], options = {}) { + const { doNotStripQMark = false } = options || {}; let init = constructorArgs[0]; this._list = []; this._url = null; From 94444b486d00dd88cf669be43dbc4a3a97b3cd36 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Mon, 1 Dec 2025 23:53:24 -0600 Subject: [PATCH 02/19] Update URLSearchParams.js --- src/jsc/modules/lib/URLSearchParams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsc/modules/lib/URLSearchParams.js b/src/jsc/modules/lib/URLSearchParams.js index d724f26..d604c14 100644 --- a/src/jsc/modules/lib/URLSearchParams.js +++ b/src/jsc/modules/lib/URLSearchParams.js @@ -3,7 +3,7 @@ const urlencoded = require("./urlencoded"); exports.implementation = class URLSearchParamsImpl { constructor(globalObject, constructorArgs = [""], options = {}) { - const { doNotStripQMark = false } = options || {}; + const { doNotStripQMark = false } = options || {}; let init = constructorArgs[0]; this._list = []; this._url = null; From 43147a50242b64242783e5445a7f6e3b9c6f902f Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Tue, 2 Dec 2025 00:05:57 -0600 Subject: [PATCH 03/19] Update URLSearchParams.js Rewriting the doNotStripQMark --- src/jsc/modules/lib/URLSearchParams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsc/modules/lib/URLSearchParams.js b/src/jsc/modules/lib/URLSearchParams.js index d604c14..6cdc5d4 100644 --- a/src/jsc/modules/lib/URLSearchParams.js +++ b/src/jsc/modules/lib/URLSearchParams.js @@ -3,7 +3,7 @@ const urlencoded = require("./urlencoded"); exports.implementation = class URLSearchParamsImpl { constructor(globalObject, constructorArgs = [""], options = {}) { - const { doNotStripQMark = false } = options || {}; + var doNotStripQMark = options && typeof options.doNotStripQMark === "boolean" ? options.doNotStripQMark : false; let init = constructorArgs[0]; this._list = []; this._url = null; From 14f1c9e5523b2f519ba61bd6c75de163cc1259ee Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Tue, 2 Dec 2025 00:07:17 -0600 Subject: [PATCH 04/19] Update URLSearchParams.js --- src/jsc/modules/lib/URLSearchParams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsc/modules/lib/URLSearchParams.js b/src/jsc/modules/lib/URLSearchParams.js index 6cdc5d4..d724f26 100644 --- a/src/jsc/modules/lib/URLSearchParams.js +++ b/src/jsc/modules/lib/URLSearchParams.js @@ -3,7 +3,7 @@ const urlencoded = require("./urlencoded"); exports.implementation = class URLSearchParamsImpl { constructor(globalObject, constructorArgs = [""], options = {}) { - var doNotStripQMark = options && typeof options.doNotStripQMark === "boolean" ? options.doNotStripQMark : false; + const { doNotStripQMark = false } = options || {}; let init = constructorArgs[0]; this._list = []; this._url = null; From 961988eb5e1a2214ed917fa8afafe906d0e17fff Mon Sep 17 00:00:00 2001 From: trupthi1403 Date: Wed, 3 Dec 2025 10:43:15 +0530 Subject: [PATCH 05/19] RDKEMW-9172: L2testcase for rdkNativeScript Reason for change: Changes to run L2 test cases Test Procedure: Able to build and run test cases in CI Risks: low Priority: P2 --- CMakeLists.txt | 20 ++++++++++++++++++++ include/NativeJSRenderer.h | 1 + src/NativeJSRenderer.cpp | 7 ++++++- src/jsruntime.cpp | 21 +++++++++++++++++++-- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f888133..df6acc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ option(BUILD_JSRUNTIME_APP "BUILD_JSRUNTIME_APP" ON) option(ENABLE_JSRUNTIME_SERVER "ENABLE_JSRUNTIME_SERVER" OFF) option(BUILD_JSRUNTIME_CLIENT "BUILD_JSRUNTIME_CLIENT" OFF) option(NATIVEJS_DEVELOPER_MODE "NATIVEJS_DEVELOPER_MODE" OFF) +option(NATIVEJS_L2_BUILD "NATIVEJS_L2_BUILD" OFF) #can be jsc or node or v8 or quickjs option(JSRUNTIME_ENGINE_NAME "JSRUNTIME_ENGINE_NAME" "jsc") @@ -39,6 +40,7 @@ option(ENABLE_JSRUNTIME_PLAYER "ENABLE_JSRUNTIME_PLAYER" OFF) option(ENABLE_JSRUNTIME_THUNDER_SECURITYAGENT "ENABLE_JSRUNTIME_THUNDER_SECURITYAGENT" OFF) option(BUILD_JSRUNTIME_DESKTOP "BUILD_JSRUNTIME_DESKTOP" ON) option(USE_ETHANLOG "USE_ETHANLOG" OFF) +option(ENABLE_COVERAGE "ENABLE_COVERAGE" OFF) option(PKG_CONFIG_SYSROOT_DIR "PKG_CONFIG_SYSROOT_DIR" "${CMAKE_CURRENT_SOURCE_DIR}/externals/extlibs") if(JSRUNTIME_ENGINE_NAME STREQUAL "jsc") @@ -101,6 +103,14 @@ if (ENABLE_JSRUNTIME_THUNDER_SECURITYAGENT) add_definitions("-DENABLE_JSRUNTIME_THUNDER_SECURITYAGENT") endif (ENABLE_JSRUNTIME_THUNDER_SECURITYAGENT) +if (NATIVEJS_DEVELOPER_MODE) + add_definitions("-DNATIVEJS_DEVELOPER_MODE") +endif (NATIVEJS_DEVELOPER_MODE) + +if (NATIVEJS_L2_BUILD) + add_definitions("-DNATIVEJS_L2_BUILD") +endif (NATIVEJS_L2_BUILD) + include (${JSRUNTIME_SOURCE_DIRECTORY}/include.cmake) set(JSRUNTIME_APP_FILES ${JSRUNTIME_COMMON_SOURCE_DIRECTORY}/jsruntime.cpp @@ -188,6 +198,16 @@ if (APPLE) endif (APPLE) add_definitions("-std=c++17 -DUSE_LIBUV") + +# Coverage support +if (ENABLE_COVERAGE) + message("Enabling code coverage support") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 --coverage -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 --coverage -fprofile-arcs -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage") +endif (ENABLE_COVERAGE) + set_target_properties(${JSRUNTIME_LIBRARY_NAME} PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) diff --git a/include/NativeJSRenderer.h b/include/NativeJSRenderer.h index 51fde0f..796594a 100644 --- a/include/NativeJSRenderer.h +++ b/include/NativeJSRenderer.h @@ -31,6 +31,7 @@ #include #include #include +#include namespace JsRuntime { diff --git a/src/NativeJSRenderer.cpp b/src/NativeJSRenderer.cpp index a7b71e6..4657e4b 100644 --- a/src/NativeJSRenderer.cpp +++ b/src/NativeJSRenderer.cpp @@ -571,7 +571,12 @@ void NativeJSRenderer::runDeveloperConsole(ModuleSettings moduleSettings) // Short-cirtuit: in case consoleLoop was altered by signal handler we shouldn't execute lines below if (!consoleLoop || input == "exit") { delete mConsoleState->consoleContext; - break; + + #ifdef NATIVEJS_L2_BUILD + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + terminate(); + #endif + break; } mConsoleState->inputMutex.lock(); diff --git a/src/jsruntime.cpp b/src/jsruntime.cpp index 0f6390c..2859880 100644 --- a/src/jsruntime.cpp +++ b/src/jsruntime.cpp @@ -140,8 +140,25 @@ int main(int argc, char* argv[]) #if defined(NATIVEJS_DEVELOPER_MODE) std::this_thread::sleep_for(std::chrono::milliseconds(500)); renderer->getApplications(); - sleep(10); - renderer->terminateApplication(id); + + #ifdef NATIVEJS_L2_BUILD + int waitTime = 10; + if (moduleSettings.enableWebSocket || moduleSettings.enableWebSocketEnhanced) { + waitTime = 30; + NativeJSLogger::log(INFO, "WebSocket enabled - using extended wait time: %d seconds\n", waitTime); + } + sleep(waitTime); + #else + sleep(10) ; + #endif + + renderer->terminateApplication(id); + + #ifdef NATIVEJS_L2_BUILD + std::this_thread::sleep_for(std::chrono::milliseconds(2000)); + renderer->terminate(); + #endif + #endif }); } From fddbc2110fd35c6a05eb9b802382a47ac6f78d1d Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Tue, 9 Dec 2025 01:52:21 -0600 Subject: [PATCH 06/19] Update src/NativeJSRenderer.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/NativeJSRenderer.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NativeJSRenderer.cpp b/src/NativeJSRenderer.cpp index 4657e4b..5a5d740 100644 --- a/src/NativeJSRenderer.cpp +++ b/src/NativeJSRenderer.cpp @@ -573,10 +573,10 @@ void NativeJSRenderer::runDeveloperConsole(ModuleSettings moduleSettings) delete mConsoleState->consoleContext; #ifdef NATIVEJS_L2_BUILD - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - terminate(); - #endif - break; + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + terminate(); + #endif + break; } mConsoleState->inputMutex.lock(); From 896f2dbd6a393d2966dc15eba05041b4e2316e21 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Tue, 9 Dec 2025 01:52:34 -0600 Subject: [PATCH 07/19] Update src/jsruntime.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/jsruntime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jsruntime.cpp b/src/jsruntime.cpp index 2859880..2198a53 100644 --- a/src/jsruntime.cpp +++ b/src/jsruntime.cpp @@ -149,7 +149,7 @@ int main(int argc, char* argv[]) } sleep(waitTime); #else - sleep(10) ; + sleep(10); #endif renderer->terminateApplication(id); From 37b83bafdb56351dc03907bc3a436a5b2623354d Mon Sep 17 00:00:00 2001 From: trupthi1403 Date: Tue, 9 Dec 2025 19:47:06 +0530 Subject: [PATCH 08/19] RDKEMW-11265: Migrate L1 and native build workflow to rdk-e Reason for change: Removed L1 and native build yml Test Procedure: build should be successful. Risks: low Priority: P2 --- .github/workflows/jsruntime_L1tests.yml | 106 ------------------------ .github/workflows/native-full-build.yml | 89 -------------------- 2 files changed, 195 deletions(-) delete mode 100644 .github/workflows/jsruntime_L1tests.yml delete mode 100644 .github/workflows/native-full-build.yml diff --git a/.github/workflows/jsruntime_L1tests.yml b/.github/workflows/jsruntime_L1tests.yml deleted file mode 100644 index fd7d3c4..0000000 --- a/.github/workflows/jsruntime_L1tests.yml +++ /dev/null @@ -1,106 +0,0 @@ -name: L1 Unit Tests for rdkNativeScript -permissions: - contents: read - checks: write - -on: - push: - branches: [develop] - pull_request: - branches: [develop] - workflow_dispatch: - -env: - AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} - AUTOMATICS_PASSCODE: ${{ secrets.AUTOMATICS_PASSCODE }} - -jobs: - build-and-test-l1: - runs-on: ubuntu-latest - - steps: - - name: Checkout source repository - uses: actions/checkout@v3 - - - name: Checkout rdkNativeScript_tests repository - uses: actions/checkout@v3 - with: - repository: rdk-e/rdkNativeScript_tests - ref: topic/RDKEMW-5610 - path: rdkNativeScript_tests - token: ${{ secrets.GH_PAT }} - - - name: Install dependencies - run: | - sudo apt-get update && sudo apt-get install -y \ - g++ \ - cmake \ - build-essential \ - libcurl4-openssl-dev \ - libcjson-dev \ - libgtest-dev \ - libssl-dev \ - zlib1g-dev \ - libuv1-dev \ - lcov \ - libglib2.0-dev - - - name: Build Google Test and Google Mock - run: | - cd /usr/src/googletest - sudo cmake -S . -B build - sudo cmake --build build - sudo cp build/lib/libgmock.a /usr/lib - sudo cp build/lib/libgmock_main.a /usr/lib - sudo cp build/lib/libgtest.a /usr/lib - sudo cp build/lib/libgtest_main.a /usr/lib - - - name: Configure and Build L1 - run: | - mkdir -p build_l1 - cd build_l1 - cmake -DCMAKE_BUILD_TYPE=Debug \ - -DRUN_L1=ON \ - -DRUN_L2=OFF \ - -DENABLE_JSRUNTIME_ESSOS=ON \ - -DENABLE_JSRUNTIME_PLAYER=ON \ - -DENABLE_AAMP_JSBINDINGS=ON \ - -DENABLE_AAMP_JSBINDINGS_DYNAMIC=ON \ - -DENABLE_AAMP_JSBINDINGS_STATIC=OFF \ - -DJSRUNTIME_ENGINE_NAME=jsc \ - -Djsruntime_source=.. ../rdkNativeScript_tests - make -j$(nproc) - - - name: Run L1 Tests and Generate JUnit Results - run: | - cd build_l1 - #ctest -R RunL1Tests --output-on-failure --no-compress-output --output-junit ctest-results.xml - ./L1_tests --gtest_output=xml:ctest-results.xml - - - name: Publish L1 test results - uses: dorny/test-reporter@v1 - with: - name: Unit Test Results - path: build_l1/ctest-results.xml - reporter: java-junit - - - name: Generate coverage report - run: | - cd build_l1 - lcov --capture --directory . --output-file coverage.info --ignore-errors mismatch --rc geninfo_unexecuted_blocks=1 - lcov --remove coverage.info '/usr/*' '*/test/*' '*/tests/*' '*/L1/*' '*/mocks/*' '*/gtest/*' '*/gmock/*' '*/googletest/*' '*/include/*' --output-file coverage.cleaned.info --ignore-errors unused - lcov --extract coverage.cleaned.info '*/src/*' --output-file coverage.final.info - genhtml coverage.final.info --output-directory html_coverage_report - - - name: Upload test result file (JUnit XML) - uses: actions/upload-artifact@v4 - with: - name: ctest-results-l1-${{ github.run_id }} - path: build_l1/ctest-results.xml - - - name: Upload coverage report - uses: actions/upload-artifact@v4 - with: - name: l1-html-coverage-report - path: build_l1/html_coverage_report - if-no-files-found: warn diff --git a/.github/workflows/native-full-build.yml b/.github/workflows/native-full-build.yml deleted file mode 100644 index f8137e6..0000000 --- a/.github/workflows/native-full-build.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: Build Component in Native Environment -permissions: - contents: read - checks: write - -on: - workflow_dispatch: - push: - branches: [develop] - pull_request: - branches: [develop] - -env: - AUTOMATICS_UNAME: ${{ secrets.AUTOMATICS_UNAME }} - AUTOMATICS_PASSCODE: ${{ secrets.AUTOMATICS_PASSCODE }} - -jobs: - build-nativescript: - runs-on: ubuntu-latest - - steps: - - name: Checkout main source repository - uses: actions/checkout@v3 - - - name: Install dependencies - run: | - sudo apt-get update && sudo apt-get install -y \ - git cmake gperf ruby-dev libglew-dev libglut-dev \ - libglib2.0-dev libglib2.0-0 g++ meson bison libjpeg-dev libpng-dev \ - libfreetype6-dev libicu-dev autoconf libtool libxml2-dev \ - libcurl4-openssl-dev libexpat1-dev doxygen vim libcjson-dev \ - libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ - libwayland-bin libwayland-dev wayland-protocols \ - libreadline-dev net-tools libmount1 libpcre3 libselinux1 zlib1g \ - libunwind-dev libboost-dev libboost-system-dev libboost-thread-dev libboost-chrono-dev libwebsocketpp-dev jq - - - name: Get asset ID for externals.zip - id: asset - run: | - ASSET_ID=$(curl -s -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ - https://api.github.com/repos/rdk-e/rdkNativeScript_tests/releases/tags/extlibs | \ - jq '.assets[] | select(.name=="externals.zip") | .id') - echo "ASSET_ID=$ASSET_ID" >> $GITHUB_ENV - - - name: Download externals.zip using asset ID - run: | - curl -L \ - -H "Authorization: Bearer ${{ secrets.GH_PAT }}" \ - -H "Accept: application/octet-stream" \ - -o externals.zip \ - https://api.github.com/repos/rdk-e/rdkNativeScript_tests/releases/assets/$ASSET_ID - - - name: Check externals.zip download - run: | - file externals.zip - ls -lh externals.zip - unzip -l externals.zip | head -20 - - - name: Extract externals.zip - run: | - unzip -o externals.zip - - - name: Set LD_LIBRARY_PATH for ICU 66 - run: echo "LD_LIBRARY_PATH=$(pwd)/externals/extlibs/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV - - - name: Configure and build nativescript - run: | - mkdir -p build - cd build - cmake .. \ - -DENABLE_JSRUNTIME_ESSOS=ON \ - -DJSRUNTIME_ENGINE_NAME=jsc \ - -DENABLE_JSRUNTIME_PLAYER=ON \ - -DENABLE_AAMP_JSBINDINGS_DYNAMIC=ON \ - -DBUILD_JSRUNTIME_CLIENT=ON \ - -DENABLE_JSRUNTIME_SERVER=ON \ - -DCMAKE_CXX_FLAGS="-I../externals/extlibs/include/rtcore" - cmake --build . - - - name: Upload build outputs to artifact - uses: actions/upload-artifact@v4 - with: - name: jsruntime-build-artifacts - path: | - build/JSRuntimeClient - build/JSRuntimeJSC - build/libjsclib.so - build/libJSRuntimeJSC.so - if-no-files-found: error From 605e0ad2b4a9241aeceb5311ac4eaa53dd7b17fd Mon Sep 17 00:00:00 2001 From: trupthi1403 Date: Wed, 15 Oct 2025 14:41:24 +0530 Subject: [PATCH 09/19] RDKEMW-8844: Improve L1 coverage Reason for change: Changes done to compile newly added test cases Test Procedure: Able to build and run test cases in CI Risks: low Priority: P2 --- include/EssosInstance.h | 4 +-- include/NativeJSRenderer.h | 13 ++++--- include/jsc/JavaScriptContext.h | 2 +- include/jsc/JavaScriptUtils.h | 42 ++++++++++++++++++++++ src/NativeJSRenderer.cpp | 55 +++++++++++++++++++++-------- src/jsc/JavaScriptUtils.cpp | 62 ++++++++++----------------------- src/linux/KeyInput.cpp | 28 +++++++++++++++ 7 files changed, 139 insertions(+), 67 deletions(-) diff --git a/include/EssosInstance.h b/include/EssosInstance.h index 7b94e28..abf4e73 100644 --- a/include/EssosInstance.h +++ b/include/EssosInstance.h @@ -38,11 +38,11 @@ class EssosInstance void onKeyRelease(struct JavaScriptKeyDetails& details); void update(); void registerKeyListener(JavaScriptKeyListener*); - + private: EssosInstance(); static EssosInstance* mInstance; - EssCtx * mEssosContext; + EssCtx * mEssosContext; bool mUseWayland; JavaScriptKeyListener* mJavaScriptKeyListener; }; diff --git a/include/NativeJSRenderer.h b/include/NativeJSRenderer.h index 796594a..42e1ec4 100644 --- a/include/NativeJSRenderer.h +++ b/include/NativeJSRenderer.h @@ -126,7 +126,10 @@ namespace JsRuntime { bool terminate(); void run(); void setEnvForConsoleMode(ModuleSettings& moduleSettings); - bool runApplication(uint32_t id, std::string url); + static std::atomic_bool consoleLoop; + std::atomic_bool mShutdownConsole{false}; + std::thread mConsoleThread; + bool runApplication(uint32_t id, std::string url); bool runJavaScript(uint32_t id, std::string code); uint32_t createApplication(ModuleSettings& moduleSettings, std::string userAgent = DEFAULT_USER_AGENT) ; bool terminateApplication(uint32_t id); @@ -135,18 +138,18 @@ namespace JsRuntime { std::string getBaseUserAgent(); private: bool downloadFile(std::string& url, MemoryStruct& chunk); - void processDevConsoleRequests(); + void processDevConsoleRequests(); void runDeveloperConsole(ModuleSettings moduleSettings); - void createApplicationInternal(ApplicationRequest& appRequest); + void createApplicationInternal(ApplicationRequest& appRequest); void runApplicationInternal(ApplicationRequest& appRequest); void terminateApplicationInternal(ApplicationRequest& appRequest); void runJavaScriptInternal(ApplicationRequest& appRequest); uint32_t createApplicationIdentifier(); static size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream); - IJavaScriptEngine* mEngine; + IJavaScriptEngine* mEngine; bool mRunning; std::string mTestFileName; - std::unique_ptr mConsoleState; + std::unique_ptr mConsoleState; bool mEnableTestFileDOMSupport; bool mEmbedThunderJS; bool mEmbedRdkWebBridge; diff --git a/include/jsc/JavaScriptContext.h b/include/jsc/JavaScriptContext.h index a97c6d3..c4d474a 100644 --- a/include/jsc/JavaScriptContext.h +++ b/include/jsc/JavaScriptContext.h @@ -86,7 +86,7 @@ class JavaScriptContext: public JavaScriptContextBase, public NetworkMetricsList void setCreateApplicationStartTime(double time); void setCreateApplicationEndTime(double time,uint32_t id); - void setPlaybackStartTime(double time); + virtual void setPlaybackStartTime(double time); void setAppdata(uint32_t id, const std::string& url); double getExecutionDuration() const; diff --git a/include/jsc/JavaScriptUtils.h b/include/jsc/JavaScriptUtils.h index 9eb6747..dde6464 100644 --- a/include/jsc/JavaScriptUtils.h +++ b/include/jsc/JavaScriptUtils.h @@ -21,6 +21,7 @@ #define JAVASCRIPTMISC_H #include +#include "rtHttpRequest.h" #include "rtString.h" #include "rtAtomic.h" #include @@ -31,6 +32,10 @@ #include #include #include +#include +#include +#include + namespace jsruntime { template @@ -51,6 +56,42 @@ class RefCounted: public T virtual ~RefCounted() {} }; } + +class rtHttpRequestEx : public rtHttpRequest +{ +public: + rtDeclareObject(rtHttpRequestEx, rtHttpRequest); + rtHttpRequestEx(const rtString& url); + rtHttpRequestEx(const rtObjectRef& options); + void onDownloadProgressImpl(double progress) final; + void onDownloadCompleteImpl(rtFileDownloadRequest* downloadRequest) final; +}; + +struct TimeoutInfo +{ + std::function callback; + std::chrono::time_point fireTime; + std::chrono::milliseconds interval; + bool repeat; + uint32_t tag; + bool canceled; +}; + +struct TimeoutInfoComparator +{ + constexpr bool operator()(const TimeoutInfo *lhs, const TimeoutInfo *rhs) const { + return !((lhs->fireTime < rhs->fireTime) || + ((lhs->fireTime == rhs->fireTime) && (lhs->tag < rhs->tag))); + } +}; + +class TimeoutQueue : public std::priority_queue, TimeoutInfoComparator> +{ +public: + void pushTimeouts(const std::vector& timerVec); + bool updateForInfo(const TimeoutInfo* info); +}; + void dispatchOnMainLoop(std::function&& fun); void dispatchPending(); void dispatchTimeouts(); @@ -73,6 +114,7 @@ rtError rtSetVideoStartTimeBinding(int numArgs, const rtValue* args, rtValue* re rtError rtJSRuntimeDownloadMetrics(int numArgs, const rtValue* args, rtValue* result, void* context); rtError rtSetExternalAppHandlerBinding(int numArgs, const rtValue* args, rtValue* result, void* context); rtError rtGetRandomValuesBinding(int numArgs, const rtValue* args, rtValue* result, void* context); +rtError rtInstallTimeout(int numArgs, const rtValue* args, rtValue* result, bool repeat); JSValueRef requireCallback(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception); #endif /* JAVASCRIPTMISC_H */ diff --git a/src/NativeJSRenderer.cpp b/src/NativeJSRenderer.cpp index 5a5d740..bee81b9 100644 --- a/src/NativeJSRenderer.cpp +++ b/src/NativeJSRenderer.cpp @@ -179,19 +179,32 @@ NativeJSRenderer::NativeJSRenderer(std::string waylandDisplay): mEngine(nullptr) NativeJSRenderer::~NativeJSRenderer() { - gPendingRequests.clear(); - if (mEngine) - { - delete mEngine; - mEngine = nullptr; + mShutdownConsole = true; + if (mConsoleThread.joinable()) { + mConsoleThread.join(); } + gPendingRequests.clear(); + if (mConsoleState && mConsoleState->consoleContext) { delete mConsoleState->consoleContext; + mConsoleState->consoleContext = nullptr; + } + if (mEngine){ + delete mEngine; + mEngine = nullptr; } + } void NativeJSRenderer::setEnvForConsoleMode(ModuleSettings& moduleSettings) { + + if (mConsoleThread.joinable()) { + mShutdownConsole = true; + mConsoleThread.join(); + } + + mShutdownConsole = false; mConsoleState = std::make_unique(); mConsoleState->moduleSettings = moduleSettings; @@ -205,8 +218,7 @@ void NativeJSRenderer::setEnvForConsoleMode(ModuleSettings& moduleSettings) mConsoleState->consoleContext = context; NativeJSLogger::log(INFO, "Running developer console...\n"); - std::thread consoleThread(&JsRuntime::NativeJSRenderer::runDeveloperConsole, this, std::ref(mConsoleState->moduleSettings)); - consoleThread.detach(); + mConsoleThread = std::thread(&JsRuntime::NativeJSRenderer::runDeveloperConsole, this, std::ref(mConsoleState->moduleSettings)); mConsoleMode = true; } @@ -542,12 +554,10 @@ void NativeJSRenderer::processDevConsoleRequests() mConsoleState->inputMutex.unlock(); } -namespace { - bool consoleLoop = true; - void handleDevConsoleSigInt(int /*sig*/){ - consoleLoop = false; - } -} // namespace +std::atomic_bool NativeJSRenderer::consoleLoop = true; +void handleDevConsoleSigInt(int /*sig*/) { + NativeJSRenderer::consoleLoop = false; +} void NativeJSRenderer::runDeveloperConsole(ModuleSettings moduleSettings) { @@ -557,7 +567,17 @@ void NativeJSRenderer::runDeveloperConsole(ModuleSettings moduleSettings) NativeJSLogger::log(INFO, "Type 'exit' or press CTRL+C and ENTER to quit.\n"); signal(SIGINT, handleDevConsoleSigInt); - while (consoleLoop) { + + #ifdef UNIT_TEST_BUILD + input = "exit"; + NativeJSLogger::log(INFO, "[UNIT_TEST_BUILD] Auto-exiting developer console"); + delete mConsoleState->consoleContext; + mConsoleState->consoleContext = nullptr; + signal(SIGINT, SIG_DFL); + return; + #else + + while (consoleLoop && !mShutdownConsole) { // Don't display another input prompt until previous code is processed (prevents) { std::unique_lock lk(mConsoleState->isProcessing_cv_m); @@ -566,16 +586,20 @@ void NativeJSRenderer::runDeveloperConsole(ModuleSettings moduleSettings) mConsoleState->isProcessing = true; } + if (mShutdownConsole) break; std::getline(std::cin, input); + if (mShutdownConsole) break; // Short-cirtuit: in case consoleLoop was altered by signal handler we shouldn't execute lines below if (!consoleLoop || input == "exit") { delete mConsoleState->consoleContext; - + mConsoleState->consoleContext = nullptr; + #ifdef NATIVEJS_L2_BUILD std::this_thread::sleep_for(std::chrono::milliseconds(200)); terminate(); #endif + break; } @@ -585,6 +609,7 @@ void NativeJSRenderer::runDeveloperConsole(ModuleSettings moduleSettings) } signal(SIGINT, SIG_DFL); + #endif } bool NativeJSRenderer::downloadFile(std::string& url, MemoryStruct& chunk) diff --git a/src/jsc/JavaScriptUtils.cpp b/src/jsc/JavaScriptUtils.cpp index 60dc124..5476746 100644 --- a/src/jsc/JavaScriptUtils.cpp +++ b/src/jsc/JavaScriptUtils.cpp @@ -70,45 +70,25 @@ static std::list> gPendingFun; static std::mutex gDispatchMutex; static const char* envValue = std::getenv("NATIVEJS_DUMP_NETWORKMETRIC"); -struct TimeoutInfo +void TimeoutQueue::pushTimeouts(const std::vector& timerVec) { - std::function callback; - std::chrono::time_point fireTime; - std::chrono::milliseconds interval; - bool repeat; - uint32_t tag; - bool canceled; -}; - -struct TimeoutInfoComparator -{ - constexpr bool operator()(const TimeoutInfo *lhs, const TimeoutInfo *rhs) const { - return !((lhs->fireTime < rhs->fireTime) || - ((lhs->fireTime == rhs->fireTime) && (lhs->tag < rhs->tag))); - } -}; + if (!timerVec.size()) + return; + this->c.reserve(this->c.size() + timerVec.size()); + this->c.insert(this->c.end(), timerVec.begin(), timerVec.end()); + std::make_heap(this->c.begin(), this->c.end(), this->comp); +} -class TimeoutQueue : public std::priority_queue, TimeoutInfoComparator> +bool TimeoutQueue::updateForInfo(const TimeoutInfo* info) { -public: - void pushTimeouts(const std::vector& timerVec) - { - if (!timerVec.size()) - return; - c.reserve(c.size() + timerVec.size()); - c.insert(c.end(),timerVec.begin(), timerVec.end()); - std::make_heap(c.begin(), c.end(), comp); - } - bool updateForInfo(const TimeoutInfo* info) - { - auto it = std::find(c.begin(), c.end(), info); - if (it != c.end()) { - std::make_heap(c.begin(), c.end(), comp); - return true; + auto it = std::find(this->c.begin(), this->c.end(), info); + if (it != this->c.end()) { + std::make_heap(this->c.begin(), this->c.end(), this->comp); + return true; } return false; - } -}; +} + static std::map gTimeoutMap; static uint32_t gTimeoutIdx = 0; static TimeoutQueue gTimeoutQueue; @@ -179,22 +159,17 @@ void assertIsMainThread() assert(std::this_thread::get_id() == gMainThreadId); } -class rtHttpRequestEx : public rtHttpRequest -{ -public: - rtDeclareObject(rtHttpRequestEx, rtHttpRequest); - - rtHttpRequestEx(const rtString& url) + rtHttpRequestEx::rtHttpRequestEx(const rtString& url) : rtHttpRequest(url) { } - rtHttpRequestEx(const rtObjectRef& options) + rtHttpRequestEx::rtHttpRequestEx(const rtObjectRef& options) : rtHttpRequest(options) { } - void onDownloadProgressImpl(double progress) final + void rtHttpRequestEx::onDownloadProgressImpl(double progress) { AddRef(); @@ -209,7 +184,7 @@ class rtHttpRequestEx : public rtHttpRequest }); } - void onDownloadCompleteImpl(rtFileDownloadRequest* downloadRequest) final + void rtHttpRequestEx::onDownloadCompleteImpl(rtFileDownloadRequest* downloadRequest) { AddRef(); if (!downloadRequest->errorString().isEmpty()) { @@ -275,7 +250,6 @@ class rtHttpRequestEx : public rtHttpRequest }); } } - }; rtDefineObject(rtHttpRequestEx, rtHttpRequest); diff --git a/src/linux/KeyInput.cpp b/src/linux/KeyInput.cpp index 8c566a8..74ab47c 100644 --- a/src/linux/KeyInput.cpp +++ b/src/linux/KeyInput.cpp @@ -144,6 +144,34 @@ std::map> keyMappings = { { WAYLAND_KEY_MUTE, { "AudioVolumeMute", "AudioVolumeMute", "AudioVolumeMute", "AudioVolumeMute" } }, { WAYLAND_KEY_VOLUME_DOWN, { "AudioVolumeDown", "AudioVolumeDown", "AudioVolumeDown", "AudioVolumeDown" } }, { WAYLAND_KEY_VOLUME_UP, { "AudioVolumeUp", "AudioVolumeUp", "AudioVolumeUp", "AudioVolumeUp" } } + + #if defined(UNIT_TEST_BUILD) + #ifdef WAYLAND_KEY_PLAYPAUSE + , { WAYLAND_KEY_PLAYPAUSE, { "PlayPause", "PlayPause", "PlayPause", "PlayPause" } } + #endif + #ifdef WAYLAND_KEY_PLAY + , { WAYLAND_KEY_PLAY, { "Play", "Play", "Play", "Play" } } + #endif + #ifdef WAYLAND_KEY_FASTFORWARD + , { WAYLAND_KEY_FASTFORWARD, { "FastForward", "FastForward", "FastForward", "FastForward" } } + #endif + #ifdef WAYLAND_KEY_REWIND + , { WAYLAND_KEY_REWIND, { "Rewind", "Rewind", "Rewind", "Rewind" } } + #endif + #ifdef WAYLAND_KEY_KPENTER + , { WAYLAND_KEY_KPENTER, { "Enter", "Enter", "Enter", "Enter" } } + #endif + #ifdef WAYLAND_KEY_BACK + , { WAYLAND_KEY_BACK, { "Back", "Back", "Back", "Back" } } + #endif + #ifdef WAYLAND_KEY_MENU + , { WAYLAND_KEY_MENU, { "Menu", "Menu", "Menu", "Menu" } } + #endif + #ifdef WAYLAND_KEY_HOMEPAGE + , { WAYLAND_KEY_HOMEPAGE, { "Homepage", "Homepage", "Homepage", "Homepage" } } + #endif + #endif // UNIT_TEST_BUILD + }; static void getJavaScriptKeyCode(uint32_t waylandKeyCode, std::string& keyCode, uint32_t& keyCodeValue) From 52172c7d23d803f4fb43b682c4fc1675a5bbc61a Mon Sep 17 00:00:00 2001 From: Sidhanth B H Date: Thu, 27 Nov 2025 17:39:20 +0530 Subject: [PATCH 10/19] RDKEMW-9785: Increasing Test Coverage for L1 test Reason for change: Overall test coverage should 75% Test Procedure: Build should be successful Risk:low Priority:P2 --- include/JSRuntimeClient.h | 11 ++ include/JSRuntimeServer.h | 15 +++ include/jsc/JavaScriptContext.h | 9 ++ include/jsc/JavaScriptWrapper.h | 4 + include/jsc/PlayerEventHandler.h | 5 + include/jsc/PlayerWrapper.h | 51 +++++++ include/rtWebSocket.h | 1 + src/jsc/JavaScriptWrapper.cpp | 9 ++ src/jsc/PlayerWrapper.cpp | 26 +++- src/jsc/jsc_lib/jsc_lib.cpp | 220 ++++++++++++++++++++++++++++++- src/jsc/jsc_lib/jsc_lib.h | 23 +++- 11 files changed, 365 insertions(+), 9 deletions(-) diff --git a/include/JSRuntimeClient.h b/include/JSRuntimeClient.h index 586223a..a34588a 100644 --- a/include/JSRuntimeClient.h +++ b/include/JSRuntimeClient.h @@ -90,12 +90,23 @@ class JSRuntimeClient : public CommandInterface std::string getState(); +#ifdef UNIT_TEST_BUILD +protected: + void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); + void setState(const std::string &state); + void onOpen(websocketpp::connection_hdl hdl); + void onFail(websocketpp::connection_hdl hdl); + void onClose(websocketpp::connection_hdl hdl); +#endif + +#ifndef UNIT_TEST_BUILD private: void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); void setState(const std::string &state); void onOpen(websocketpp::connection_hdl hdl); void onFail(websocketpp::connection_hdl hdl); void onClose(websocketpp::connection_hdl hdl); +#endif private: JSRuntimeClient(); diff --git a/include/JSRuntimeServer.h b/include/JSRuntimeServer.h index e6850cc..d9f0616 100644 --- a/include/JSRuntimeServer.h +++ b/include/JSRuntimeServer.h @@ -45,10 +45,25 @@ class JSRuntimeServer bool stop(); private: +#ifdef UNIT_TEST_BUILD +public: + // Expose private methods for testing void send(websocketpp::connection_hdl hdl, const std::string &msg); void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); void onOpen(websocketpp::connection_hdl hdl); void onClose(websocketpp::connection_hdl hdl); + + const std::set>& getConnections() const { return mConnections; } + WsServer& getServer() { return mServer; } +#endif + +#ifndef UNIT_TEST_BUILD +private: + void send(websocketpp::connection_hdl hdl, const std::string &msg); + void onMessage(websocketpp::connection_hdl hdl, message_ptr msg); + void onOpen(websocketpp::connection_hdl hdl); + void onClose(websocketpp::connection_hdl hdl); +#endif private: typedef std::set> ConnectionSet; diff --git a/include/jsc/JavaScriptContext.h b/include/jsc/JavaScriptContext.h index a97c6d3..caf0164 100644 --- a/include/jsc/JavaScriptContext.h +++ b/include/jsc/JavaScriptContext.h @@ -91,8 +91,16 @@ class JavaScriptContext: public JavaScriptContextBase, public NetworkMetricsList double getExecutionDuration() const; void handleExternalApplication(const std::string& url); +#ifdef UNIT_TEST_BUILD + bool evaluateScript(const char *script, const char *name, const char *args = nullptr, bool module = false); + void processKeyEvent(struct JavaScriptKeyDetails& details, bool keyPress); + void registerUtils(); + void loadAAMPJSBindingsLib(); + void unloadAAMPJSBindingsLib(); +#endif private: +#ifndef UNIT_TEST_BUILD bool evaluateScript(const char *script, const char *name, const char *args = nullptr, bool module = false); void processKeyEvent(struct JavaScriptKeyDetails& details, bool keyPress); void registerUtils(); @@ -102,6 +110,7 @@ class JavaScriptContext: public JavaScriptContextBase, public NetworkMetricsList void unloadAAMPJSBindingsLib(); void *jscLibHandle = nullptr; #endif +#endif #endif JSContextGroupRef mContextGroup; JSGlobalContextRef mContext; diff --git a/include/jsc/JavaScriptWrapper.h b/include/jsc/JavaScriptWrapper.h index 298df7b..50546a5 100644 --- a/include/jsc/JavaScriptWrapper.h +++ b/include/jsc/JavaScriptWrapper.h @@ -33,6 +33,9 @@ rtError jsToRt(JSContextRef context, JSValueRef value, rtValue &result, JSValueRef *exception); JSValueRef rtToJs(JSContextRef context, const rtValue &rtval); +#ifdef UNIT_TEST_BUILD +void clearGlobalWrapperCacheForTests(); +#endif class JSObjectWrapper: public jsruntime::RefCounted, public rtJSCWrapperBase { @@ -50,6 +53,7 @@ class JSObjectWrapper: public jsruntime::RefCounted, public rtJSCWrap class JSFunctionWrapper: public jsruntime::RefCounted, public rtJSCWrapperBase { +private: size_t hash() override { return mHash; } void setHash(size_t hash) override { UNUSED_PARAM(hash); } rtError Send(int numArgs, const rtValue* args, rtValue* result) override; diff --git a/include/jsc/PlayerEventHandler.h b/include/jsc/PlayerEventHandler.h index c88a035..578e4f7 100755 --- a/include/jsc/PlayerEventHandler.h +++ b/include/jsc/PlayerEventHandler.h @@ -41,8 +41,13 @@ class PlayerEventHandler : public AAMPEventObjectListener void removeEventListener(AAMPEventType type, JSObjectRef callback); void removeAllEventListeners(); void Event(const AAMPEventPtr& e); +#ifdef UNIT_TEST_BUILD + void sendEvent(AAMPEventType type, JSObjectRef event); +#endif private: +#ifndef UNIT_TEST_BUILD void sendEvent(AAMPEventType type, JSObjectRef event); +#endif JSContextRef mContext; PlayerInstanceAAMP* mPlayer; std::map> mEventListeners; diff --git a/include/jsc/PlayerWrapper.h b/include/jsc/PlayerWrapper.h index 433f9aa..99b9b58 100644 --- a/include/jsc/PlayerWrapper.h +++ b/include/jsc/PlayerWrapper.h @@ -44,12 +44,63 @@ struct PlayerWrapper JSGlobalContextRef ctx; PlayerInstanceAAMP* mPlayer; +#ifdef UNIT_TEST_BUILD + PlayerEventHandler* mPlayerEventHandler; +#endif + private: JSObjectRef getCallbackForAdId(std::string id); std::map mPromiseCallbacks; +#ifndef UNIT_TEST_BUILD PlayerEventHandler* mPlayerEventHandler; +#endif }; void initializePlayer(JSGlobalContextRef context); void deinitializePlayer(JSGlobalContextRef context); + +#ifdef UNIT_TEST_BUILD +std::vector JSStringArrayToCStringArray(JSContextRef context, JSValueRef arrayRef); + +JSValueRef AAMPMediaPlayerJS_initConfig(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_load(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVolume(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_addEventListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_removeEventListener(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_subscribeResponseHeaders(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setSubscribedTags(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_addCustomHTTPHeader(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_removeCustomHTTPHeader(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setClosedCaptionStatus(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVideoMute(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_play(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_detach(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_pause(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_release(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_stop(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_seek(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getAudioTrackInfo(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getTextTrackInfo(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getDurationSec(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getCurrentPosition(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getAudioTrack(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getTextTrack(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getVolume(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setAudioLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setPlaybackRate(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVideoRect(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setVideoZoom(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setPreferredAudioLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setPreferredTextLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setTextStyleOptions(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setAuxiliaryLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_xreSupportedTune(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); + +JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +JSValueRef AAMPMediaPlayerJS_notifyReservationCompletion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception); +#endif + #endif diff --git a/include/rtWebSocket.h b/include/rtWebSocket.h index e0fc057..40133b9 100644 --- a/include/rtWebSocket.h +++ b/include/rtWebSocket.h @@ -106,3 +106,4 @@ class rtWebSocket : public rtObject }; #endif //RT_WEB_SOCKET_H + diff --git a/src/jsc/JavaScriptWrapper.cpp b/src/jsc/JavaScriptWrapper.cpp index c363973..e64eed2 100644 --- a/src/jsc/JavaScriptWrapper.cpp +++ b/src/jsc/JavaScriptWrapper.cpp @@ -969,3 +969,12 @@ rtError JSFunctionWrapper::Send(int numArgs, const rtValue* args, rtValue* resul return RT_OK; } } + +#ifdef UNIT_TEST_BUILD + +void clearGlobalWrapperCacheForTests() +{ + assertIsMainThread(); + globalWrapperCache.clear(); +} +#endif diff --git a/src/jsc/PlayerWrapper.cpp b/src/jsc/PlayerWrapper.cpp index e1a748c..77dfe01 100644 --- a/src/jsc/PlayerWrapper.cpp +++ b/src/jsc/PlayerWrapper.cpp @@ -1128,7 +1128,11 @@ JSValueRef AAMPMediaPlayerJS_setVideoZoom (JSContextRef ctx, JSObjectRef functio return JSValueMakeUndefined(ctx); } +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1163,7 +1167,11 @@ static JSValueRef AAMPMediaPlayerJS_getAvailableAudioTracks(JSContextRef ctx, JS * @param[out] exception pointer to a JSValueRef in which to return an exception, if any * @retval JSValue that is the function's return value */ + #ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1198,7 +1206,11 @@ static JSValueRef AAMPMediaPlayerJS_getAvailableTextTracks(JSContextRef ctx, JSO * @param[out] exception pointer to a JSValueRef in which to return an exception, if any * @retval JSValue that is the function's return value */ +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1221,7 +1233,11 @@ static JSValueRef AAMPMediaPlayerJS_getVideoRectangle(JSContextRef ctx, JSObject * @param[out] exception pointer to a JSValueRef in which to return an exception, if any * @retval JSValue that is the function's return value */ -static JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else +static JSValueRef AAMPMediaPlayerJS_setAlternateContent(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1405,7 +1421,11 @@ JSValueRef AAMPMediaPlayerJS_setPreferredTextLanguage(JSContextRef ctx, JSObject return JSValueMakeUndefined(ctx); } +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_notifyReservationCompletion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_notifyReservationCompletion(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) @@ -1458,7 +1478,11 @@ JSValueRef AAMPMediaPlayerJS_setTextStyleOptions(JSContextRef ctx, JSObjectRef f return JSValueMakeUndefined(ctx); } +#ifdef UNIT_TEST_BUILD +JSValueRef AAMPMediaPlayerJS_setAuxiliaryLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#else static JSValueRef AAMPMediaPlayerJS_setAuxiliaryLanguage(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef *exception) +#endif { PlayerWrapper* privObj = (PlayerWrapper*)JSObjectGetPrivate(thisObject); if (!privObj || !privObj->mPlayer) diff --git a/src/jsc/jsc_lib/jsc_lib.cpp b/src/jsc/jsc_lib/jsc_lib.cpp index 8972922..b759135 100644 --- a/src/jsc/jsc_lib/jsc_lib.cpp +++ b/src/jsc/jsc_lib/jsc_lib.cpp @@ -65,6 +65,7 @@ const GlobalObjectMethodTable s_globalObjectMethodTableMadan = { nullptr, // deriveShadowRealmGlobalObject }; +#ifndef USE_JSCLIB_MOCK struct MemoryStruct { MemoryStruct() @@ -98,6 +99,7 @@ struct MemoryStruct char* contentsBuffer; size_t readSize; }; +#endif // !USE_JSCLIB_MOCK static size_t CallbackHeader(void *contents, size_t size, size_t nmemb, void *userp) { @@ -140,6 +142,11 @@ bool downloadFile(std::string& url, MemoryStruct& chunk) bool ret = false; CURL *curl; CURLcode res; +#ifdef USE_JSCLIB_MOCK + if (MockControl::simulate_curl_init_failure) + curl = nullptr; + else +#endif curl = curl_easy_init(); if (curl) { @@ -178,6 +185,116 @@ bool downloadFile(std::string& url, MemoryStruct& chunk) } return ret; } + +#ifdef USE_JSCLIB_MOCK +// Non-static versions for testing +UChar pathSeparator() +{ +#if OS(WINDOWS) + return '\\'; +#else + return '/'; +#endif +} + +bool isAbsolutePath(StringView path) +{ +#if OS(WINDOWS) + // Just look for local drives like C:\. + return path.length() > 2 && isASCIIAlpha(path[0]) && path[1] == ':' && (path[2] == '\\' || path[2] == '/'); +#else + return path.startsWith('/'); +#endif +} + +bool isDottedRelativePath(StringView path) +{ +#if OS(WINDOWS) + auto length = path.length(); + if (length < 2 || path[0] != '.') + return false; + + if (path[1] == '/' || path[1] == '\\') + return true; + + return length > 2 && path[1] == '.' && (path[2] == '/' || path[2] == '\\'); +#else + return path.startsWith("./"_s) || path.startsWith("../"_s); +#endif +} + +void convertShebangToJSCommentWrapper(char* buffer, size_t size) +{ + if (size >= 2) { + if (buffer[0] == '#' && buffer[1] == '!') + buffer[0] = buffer[1] = '/'; + } +} + +bool fetchScriptFromLocalFileSystemWrapper(const char* fileName, char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + Vector buffer; + FILE* f = fopen(fileName, "rb"); + if (!f) + return false; + +#ifdef USE_JSCLIB_MOCK + if (MockControl::simulate_fseek_failure) { + fclose(f); + return false; + } +#endif + if (fseek(f, 0, SEEK_END) == -1) { + fclose(f); + return false; + } +#ifdef USE_JSCLIB_MOCK + if (MockControl::simulate_ftell_failure) { + fclose(f); + return false; + } +#endif + long bufferCapacity = ftell(f); + if (bufferCapacity == -1) { + fclose(f); + return false; + } + if (fseek(f, 0, SEEK_SET) == -1) { + fclose(f); + return false; + } + buffer.resize(bufferCapacity); +#ifdef USE_JSCLIB_MOCK + size_t readSize; + if (MockControl::simulate_fread_short) { + readSize = 0; // Simulate partial/failed read + } else { + readSize = fread(buffer.data(), 1, bufferCapacity, f); + } +#else + size_t readSize = fread(buffer.data(), 1, bufferCapacity, f); +#endif + fclose(f); + + if (readSize != static_cast(bufferCapacity)) + return false; + + // Convert shebang + if (buffer.size() >= 2) { + if (buffer[0] == '#' && buffer[1] == '!') + buffer[0] = buffer[1] = '/'; + } + + *outSize = buffer.size(); + *outBuffer = (char*)malloc(*outSize + 1); + memcpy(*outBuffer, buffer.data(), *outSize); + (*outBuffer)[*outSize] = 0; + return true; +} + +#endif // USE_JSCLIB_MOCK + template class GlobalObject; @@ -225,13 +342,7 @@ static inline String stringFromUTF(const Vector& utf8) return String::fromUTF8WithLatin1Fallback(utf8.data(), utf8.size()); } -/* -Copyright (C) 1999-2000 Harri Porten ([porten@kde.org](mailto:porten@kde.org)) -Copyright (C) 2004-2020 Apple Inc. All rights reserved. -Copyright (C) 2006 Bjoern Graf ([bjoern.graf@gmail.com](mailto:bjoern.graf@gmail.com)) -Licensed under the LGPL License, Version 2.0 -*/ - +#ifndef USE_JSCLIB_MOCK static UChar pathSeparator() { #if OS(WINDOWS) @@ -240,6 +351,7 @@ static UChar pathSeparator() return '/'; #endif } +#endif // !USE_JSCLIB_MOCK static URL currentWorkingDirectory() { @@ -285,6 +397,7 @@ static URL currentWorkingDirectory() // FIXME: We may wish to support module specifiers beginning with a (back)slash on Windows. We could either: // - align with V8 and SM: treat '/foo' as './foo' // - align with PowerShell: treat '/foo' as 'C:/foo' +#ifndef USE_JSCLIB_MOCK static bool isAbsolutePath(StringView path) { #if OS(WINDOWS) @@ -310,6 +423,7 @@ static bool isDottedRelativePath(StringView path) return path.startsWith("./"_s) || path.startsWith("../"_s); #endif } +#endif // !USE_JSCLIB_MOCK static URL absoluteFileURL(const String& fileName) { @@ -403,6 +517,97 @@ static bool fetchScriptFromLocalFileSystem(const String& fileName, Vector& return true; } +#ifdef USE_JSCLIB_MOCK +// Wrapper functions for testing - must be after static function definitions +String stringFromUTFWrapper(const char* data, size_t size) +{ + Vector vec; + vec.resize(size); + memcpy(vec.data(), data, size); + return stringFromUTF(vec); +} + +bool fillBufferWithContentsOfFileWrapper(const char* fileName, char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + Vector buffer; + + if (!fillBufferWithContentsOfFile(fileNameStr, buffer)) + return false; + + *outSize = buffer.size(); + *outBuffer = (char*)malloc(*outSize + 1); + memcpy(*outBuffer, buffer.data(), *outSize); + (*outBuffer)[*outSize] = 0; + return true; +} + +bool absoluteFileURLWrapper(const char* fileName, char** outURL, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + URL url = absoluteFileURL(fileNameStr); + + if (!url.isValid()) + return false; + + String urlString = url.string(); + CString utf8 = urlString.utf8(); + *outSize = utf8.length(); + *outURL = (char*)malloc(*outSize + 1); + memcpy(*outURL, utf8.data(), *outSize); + (*outURL)[*outSize] = 0; + return true; +} + +bool fetchScriptFromLocalFileSystemVectorWrapper(const char* fileName, char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + Vector buffer; + + if (!fetchScriptFromLocalFileSystem(fileNameStr, buffer)) + return false; + + *outSize = buffer.size(); + *outBuffer = (char*)malloc(*outSize + 1); + memcpy(*outBuffer, buffer.data(), *outSize); + (*outBuffer)[*outSize] = 0; + return true; +} + +bool fillBufferWithContentsOfFileUint8Wrapper(const char* fileName, unsigned char** outBuffer, size_t* outSize) +{ + String fileNameStr = String::fromUTF8(fileName); + RefPtr result = fillBufferWithContentsOfFile(fileNameStr); + + if (!result) { + *outBuffer = nullptr; + *outSize = 0; + return false; + } + + *outSize = result->byteLength(); + *outBuffer = (unsigned char*)malloc(*outSize); + memcpy(*outBuffer, result->data(), *outSize); + return true; +} + +bool currentWorkingDirectoryWrapper(char** outPath, size_t* outSize) +{ + URL cwd = currentWorkingDirectory(); + + if (!cwd.isValid()) + return false; + + String cwdString = cwd.string(); + CString utf8 = cwdString.utf8(); + *outSize = utf8.length(); + *outPath = (char*)malloc(*outSize + 1); + memcpy(*outPath, utf8.data(), *outSize); + (*outPath)[*outSize] = 0; + return true; +} +#endif // USE_JSCLIB_MOCK + class ShellSourceProvider final : public StringSourceProvider { public: static Ref create(const String& source, const SourceOrigin& sourceOrigin, String&& sourceURL, const TextPosition& startPosition, SourceProviderSourceType sourceType) @@ -854,3 +1059,4 @@ void functionLoadModule(JSGlobalContextRef ref, JSObjectRef globalObjectRef, cha //promise->then(exec, nullptr, errorHandler); promise->then(toJS(ref), fulfillHandler, rejectHandler); } + diff --git a/src/jsc/jsc_lib/jsc_lib.h b/src/jsc/jsc_lib/jsc_lib.h index b9f5ccd..6fa9d8e 100644 --- a/src/jsc/jsc_lib/jsc_lib.h +++ b/src/jsc/jsc_lib/jsc_lib.h @@ -111,4 +111,25 @@ #define PATH_MAX 4096 #endif -void functionLoadModule(JSGlobalContextRef ref, JSObjectRef globalObjectRef, char *buffer, int len, char* name); \ No newline at end of file +void functionLoadModule(JSGlobalContextRef ref, JSObjectRef globalObjectRef, char *buffer, int len, char* name); + +#ifdef USE_JSCLIB_MOCK + +typedef unsigned short UChar; +UChar pathSeparator(); +bool isAbsolutePath(JSC::StringView path); +bool isDottedRelativePath(JSC::StringView path); +void convertShebangToJSCommentWrapper(char* buffer, size_t size); +bool fetchScriptFromLocalFileSystemWrapper(const char* fileName, char** outBuffer, size_t* outSize); +JSC::String stringFromUTFWrapper(const char* data, size_t size); +bool fillBufferWithContentsOfFileWrapper(const char* fileName, char** outBuffer, size_t* outSize); +bool absoluteFileURLWrapper(const char* fileName, char** outURL, size_t* outSize); +bool fetchScriptFromLocalFileSystemVectorWrapper(const char* fileName, char** outBuffer, size_t* outSize); +bool fillBufferWithContentsOfFileUint8Wrapper(const char* fileName, unsigned char** outBuffer, size_t* outSize); +bool currentWorkingDirectoryWrapper(char** outPath, size_t* outSize); + + +struct MemoryStruct; + +bool downloadFile(std::string& url, MemoryStruct& chunk); +#endif From a0796dfc9ee9301840842e4c629e29e3f665992a Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 07:32:15 -0600 Subject: [PATCH 11/19] Update include/EssosInstance.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- include/EssosInstance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/EssosInstance.h b/include/EssosInstance.h index abf4e73..345aa1c 100644 --- a/include/EssosInstance.h +++ b/include/EssosInstance.h @@ -42,7 +42,7 @@ class EssosInstance private: EssosInstance(); static EssosInstance* mInstance; - EssCtx * mEssosContext; + EssCtx * mEssosContext; bool mUseWayland; JavaScriptKeyListener* mJavaScriptKeyListener; }; From bad6e9d5ff458c5a97502bb63d524a506a74a4a9 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 07:32:36 -0600 Subject: [PATCH 12/19] Update include/NativeJSRenderer.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- include/NativeJSRenderer.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/NativeJSRenderer.h b/include/NativeJSRenderer.h index 42e1ec4..6fc061e 100644 --- a/include/NativeJSRenderer.h +++ b/include/NativeJSRenderer.h @@ -126,11 +126,11 @@ namespace JsRuntime { bool terminate(); void run(); void setEnvForConsoleMode(ModuleSettings& moduleSettings); - static std::atomic_bool consoleLoop; + static std::atomic_bool consoleLoop; std::atomic_bool mShutdownConsole{false}; - std::thread mConsoleThread; + std::thread mConsoleThread; bool runApplication(uint32_t id, std::string url); - bool runJavaScript(uint32_t id, std::string code); + bool runJavaScript(uint32_t id, std::string code); uint32_t createApplication(ModuleSettings& moduleSettings, std::string userAgent = DEFAULT_USER_AGENT) ; bool terminateApplication(uint32_t id); std::list getApplications(); From 3e0f65cf6a9d560b26e5a0ee6c26350d48046ded Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 07:34:32 -0600 Subject: [PATCH 13/19] Update src/linux/KeyInput.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/linux/KeyInput.cpp | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/linux/KeyInput.cpp b/src/linux/KeyInput.cpp index 74ab47c..7ea4ee2 100644 --- a/src/linux/KeyInput.cpp +++ b/src/linux/KeyInput.cpp @@ -146,30 +146,30 @@ std::map> keyMappings = { { WAYLAND_KEY_VOLUME_UP, { "AudioVolumeUp", "AudioVolumeUp", "AudioVolumeUp", "AudioVolumeUp" } } #if defined(UNIT_TEST_BUILD) - #ifdef WAYLAND_KEY_PLAYPAUSE - , { WAYLAND_KEY_PLAYPAUSE, { "PlayPause", "PlayPause", "PlayPause", "PlayPause" } } - #endif - #ifdef WAYLAND_KEY_PLAY - , { WAYLAND_KEY_PLAY, { "Play", "Play", "Play", "Play" } } - #endif - #ifdef WAYLAND_KEY_FASTFORWARD - , { WAYLAND_KEY_FASTFORWARD, { "FastForward", "FastForward", "FastForward", "FastForward" } } - #endif - #ifdef WAYLAND_KEY_REWIND - , { WAYLAND_KEY_REWIND, { "Rewind", "Rewind", "Rewind", "Rewind" } } - #endif - #ifdef WAYLAND_KEY_KPENTER - , { WAYLAND_KEY_KPENTER, { "Enter", "Enter", "Enter", "Enter" } } - #endif - #ifdef WAYLAND_KEY_BACK - , { WAYLAND_KEY_BACK, { "Back", "Back", "Back", "Back" } } - #endif - #ifdef WAYLAND_KEY_MENU - , { WAYLAND_KEY_MENU, { "Menu", "Menu", "Menu", "Menu" } } - #endif - #ifdef WAYLAND_KEY_HOMEPAGE - , { WAYLAND_KEY_HOMEPAGE, { "Homepage", "Homepage", "Homepage", "Homepage" } } - #endif + #ifdef WAYLAND_KEY_PLAYPAUSE + , { WAYLAND_KEY_PLAYPAUSE, { "PlayPause", "PlayPause", "PlayPause", "PlayPause" } } + #endif + #ifdef WAYLAND_KEY_PLAY + , { WAYLAND_KEY_PLAY, { "Play", "Play", "Play", "Play" } } + #endif + #ifdef WAYLAND_KEY_FASTFORWARD + , { WAYLAND_KEY_FASTFORWARD, { "FastForward", "FastForward", "FastForward", "FastForward" } } + #endif + #ifdef WAYLAND_KEY_REWIND + , { WAYLAND_KEY_REWIND, { "Rewind", "Rewind", "Rewind", "Rewind" } } + #endif + #ifdef WAYLAND_KEY_KPENTER + , { WAYLAND_KEY_KPENTER, { "Enter", "Enter", "Enter", "Enter" } } + #endif + #ifdef WAYLAND_KEY_BACK + , { WAYLAND_KEY_BACK, { "Back", "Back", "Back", "Back" } } + #endif + #ifdef WAYLAND_KEY_MENU + , { WAYLAND_KEY_MENU, { "Menu", "Menu", "Menu", "Menu" } } + #endif + #ifdef WAYLAND_KEY_HOMEPAGE + , { WAYLAND_KEY_HOMEPAGE, { "Homepage", "Homepage", "Homepage", "Homepage" } } + #endif #endif // UNIT_TEST_BUILD }; From f2fbbe9eec146be3b91a8aa550dddb26ff43d2ff Mon Sep 17 00:00:00 2001 From: gurpreet319 Date: Fri, 14 Nov 2025 18:47:43 +0530 Subject: [PATCH 14/19] RDKEMW-9355: Add Support to run app widgets in different contexts within a single process Reason for change: Changes related to client/server Test Procedure: build should be successful. Risks: low Priority: P2 --- CMakeLists.txt | 28 ++- include/JSRuntimeContainer.h | 43 +++++ include/JSRuntimeServer.h | 4 +- src/JSRuntimeClientContainer.cpp | 31 ++++ src/JSRuntimeContainer.cpp | 302 +++++++++++++++++++++++++++++++ src/JSRuntimeServer.cpp | 70 ++++++- src/jsruntime.cpp | 2 +- 7 files changed, 467 insertions(+), 13 deletions(-) create mode 100644 include/JSRuntimeContainer.h create mode 100644 src/JSRuntimeClientContainer.cpp create mode 100644 src/JSRuntimeContainer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df6acc3..de08db5 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,15 @@ 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 +) + 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 +201,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} -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..f68f96e --- /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..c9a827d 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,42 @@ 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 +255,27 @@ 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 +294,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/jsruntime.cpp b/src/jsruntime.cpp index 2198a53..fdbf989 100644 --- a/src/jsruntime.cpp +++ b/src/jsruntime.cpp @@ -122,7 +122,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 From 7e7e35d0d5180306adc7372707db159330d46eb9 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:07:59 -0600 Subject: [PATCH 15/19] Update src/JSRuntimeServer.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/JSRuntimeServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/JSRuntimeServer.cpp b/src/JSRuntimeServer.cpp index c9a827d..670afcb 100644 --- a/src/JSRuntimeServer.cpp +++ b/src/JSRuntimeServer.cpp @@ -270,7 +270,6 @@ void JSRuntimeServer::onMessage(websocketpp::connection_hdl hdl, message_ptr msg { mRenderer->runApplication(id, url); } - std::ostringstream oss; oss<< "ID : " << id; result = oss.str(); From ff8f3e911f4684e54c5b9b0ba71ae0efa4de9700 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:12:12 -0600 Subject: [PATCH 16/19] Update src/JSRuntimeClientContainer.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/JSRuntimeClientContainer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/JSRuntimeClientContainer.cpp b/src/JSRuntimeClientContainer.cpp index f68f96e..8382be2 100644 --- a/src/JSRuntimeClientContainer.cpp +++ b/src/JSRuntimeClientContainer.cpp @@ -12,8 +12,8 @@ int main() std::string ipAddress = JSRuntimeContainer::getContainerIpAddress(containerId); if (ipAddress.empty()) { - NativeJSLogger::log(ERROR, "Failed to retrieve IP address for container"); - return 1; + NativeJSLogger::log(ERROR, "Failed to retrieve IP address for container"); + return 1; } for (const auto &app : apps) { From 62116afbefdf5b9b036f2d0894c47c763990e175 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:17:24 -0600 Subject: [PATCH 17/19] Update src/JSRuntimeServer.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/JSRuntimeServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/JSRuntimeServer.cpp b/src/JSRuntimeServer.cpp index 670afcb..63a5fd3 100644 --- a/src/JSRuntimeServer.cpp +++ b/src/JSRuntimeServer.cpp @@ -205,7 +205,6 @@ void JSRuntimeServer::onMessage(websocketpp::connection_hdl hdl, message_ptr msg { break; } - if (method == "runExternalApplication") { JsonWrap jParams(jRoot, "params"); From 3a565cabb3ebc649cac333ab2993915dffdef3e5 Mon Sep 17 00:00:00 2001 From: Vinod Jain <98183059+vjain008@users.noreply.github.com> Date: Wed, 10 Dec 2025 23:19:35 -0600 Subject: [PATCH 18/19] Update src/JSRuntimeServer.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/JSRuntimeServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/JSRuntimeServer.cpp b/src/JSRuntimeServer.cpp index 63a5fd3..342f386 100644 --- a/src/JSRuntimeServer.cpp +++ b/src/JSRuntimeServer.cpp @@ -213,7 +213,6 @@ void JSRuntimeServer::onMessage(websocketpp::connection_hdl hdl, message_ptr msg result = "error: missing params"; break; } - uint32_t id = jParams.getUint32("id", error); if (error) { From de7bbf39545d91ca8b0fd7c3fca8b9cac9f44eac Mon Sep 17 00:00:00 2001 From: Vinod Kumar Jain Date: Wed, 10 Dec 2025 23:33:37 -0600 Subject: [PATCH 19/19] 2.0 release changelog updates --- CHANGELOG.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 755b629..1f544e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,25 @@ 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](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 +47,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 +128,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)