diff --git a/CHANGELOG.md b/CHANGELOG.md index fd2445f..a080667 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ 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.3](https://github.com/rdkcentral/rdkNativeScript/compare/2.0.2...2.0.3) + +- RDKEMW-13657: Plugin Feature fails on Xione-UK [`#124`](https://github.com/rdkcentral/rdkNativeScript/pull/124) +- RDKEMW-14592: Nativescript widget is not working in support branch wi… [`#125`](https://github.com/rdkcentral/rdkNativeScript/pull/125) +- RDKEMW-13250: Memory Metrics analysis for VIPA [`#123`](https://github.com/rdkcentral/rdkNativeScript/pull/123) +- RDKEMW-14592: Nativescript widget is not working in support branch with VIPA 1.4.2 build [`f842406`](https://github.com/rdkcentral/rdkNativeScript/commit/f842406b6fd114c3a48e7c08292a59b7e84c4936) +- Merge tag '2.0.2' into develop [`7b4569c`](https://github.com/rdkcentral/rdkNativeScript/commit/7b4569c6c31487c0640f5bc9afa3158d83fa1271) + #### [2.0.2](https://github.com/rdkcentral/rdkNativeScript/compare/2.0.1...2.0.2) - Fix High and Medium Level issues [`#110`](https://github.com/rdkcentral/rdkNativeScript/pull/110) diff --git a/include/ModuleSettings.h b/include/ModuleSettings.h index a255182..ba43d2e 100644 --- a/include/ModuleSettings.h +++ b/include/ModuleSettings.h @@ -34,5 +34,6 @@ struct ModuleSettings bool enableJSDOM; bool enableWindow; bool enablePlayer; + bool enableMiniJSDOM; }; #endif diff --git a/include/NativeJSRenderer.h b/include/NativeJSRenderer.h index 6fc061e..ee9f629 100644 --- a/include/NativeJSRenderer.h +++ b/include/NativeJSRenderer.h @@ -95,7 +95,7 @@ namespace JsRuntime { struct ApplicationRequest { - ApplicationRequest(uint32_t id, RequestType requestType, std::string url="", bool enableHttp=false, bool enableXHR=false, bool enableWebSocket=false, bool enableWebSocketEnhanced=false, bool enableFetch=false, bool enableJSDOM=false, bool enableWindow=false, bool enablePlayer=false, std::string userAgent=""): mId(id), mRequestType(requestType), mUrl(url), mEnableHttp(enableHttp), mEnableXHR(enableXHR), mEnableWebSocket(enableWebSocket), mEnableWebSocketEnhanced(enableWebSocketEnhanced), mEnableFetch(enableFetch), mEnableJSDOM(enableJSDOM), mEnableWindow(enableWindow), mEnablePlayer(enablePlayer), mUserAgent(userAgent) + ApplicationRequest(uint32_t id, RequestType requestType, std::string url="", bool enableHttp=false, bool enableXHR=false, bool enableWebSocket=false, bool enableWebSocketEnhanced=false, bool enableFetch=false, bool enableJSDOM=false, bool enableWindow=false, bool enablePlayer=false, bool enableMiniJSDOM=false, std::string userAgent=""): mId(id), mRequestType(requestType), mUrl(url), mEnableHttp(enableHttp), mEnableXHR(enableXHR), mEnableWebSocket(enableWebSocket), mEnableWebSocketEnhanced(enableWebSocketEnhanced), mEnableFetch(enableFetch), mEnableJSDOM(enableJSDOM), mEnableWindow(enableWindow), mEnablePlayer(enablePlayer), mEnableMiniJSDOM(enableMiniJSDOM), mUserAgent(userAgent) { } uint32_t mId; @@ -109,6 +109,7 @@ namespace JsRuntime { bool mEnableJSDOM; bool mEnableWindow; bool mEnablePlayer; + bool mEnableMiniJSDOM; std::string mUserAgent; }; diff --git a/src/JavaScriptContextBase.cpp b/src/JavaScriptContextBase.cpp index 086b7c9..8bee572 100644 --- a/src/JavaScriptContextBase.cpp +++ b/src/JavaScriptContextBase.cpp @@ -154,13 +154,26 @@ void JavaScriptContextBase::populateModulesPath() if(getenv("JSRUNTIME_MODULES_PATH")) { std::cout<<"JSRUNTIME_MODULES_PATH variable is set"< ModuleSettings::ModuleSettings(): enableHttp(false), enableXHR(false), enableWebSocket(false), enableWebSocketEnhanced(false) - , enableFetch(false), enableJSDOM(false), enableWindow(false), enablePlayer(false) + , enableFetch(false), enableJSDOM(false), enableWindow(false), enablePlayer(false), enableMiniJSDOM(false) { } @@ -30,7 +30,8 @@ ModuleSettings::ModuleSettings(ModuleSettings& settings): enableHttp(settings.en enableFetch(settings.enableFetch), enableJSDOM(settings.enableJSDOM), enableWindow(settings.enableWindow), - enablePlayer(settings.enablePlayer) + enablePlayer(settings.enablePlayer), + enableMiniJSDOM(settings.enableMiniJSDOM) { } @@ -56,7 +57,11 @@ void ModuleSettings::fromString(std::string& options) { enableFetch = true; } - if (options.find("jsdom") != std::string::npos) + if (options.find("minijsdom") != std::string::npos) + { + enableMiniJSDOM = true; + } + else if (options.find("jsdom") != std::string::npos) { enableJSDOM = true; } @@ -67,5 +72,5 @@ void ModuleSettings::fromString(std::string& options) if (options.find("player") != std::string::npos) { enablePlayer = true; - } + } } diff --git a/src/NativeJSLogger.cpp b/src/NativeJSLogger.cpp index 212a041..d1024d4 100644 --- a/src/NativeJSLogger.cpp +++ b/src/NativeJSLogger.cpp @@ -86,14 +86,14 @@ void NativeJSLogger::log(LogLevel level, const char* format, ...) vethanlog(ethanLogLevel, "JsRuntime", nullptr, -1, newFormat, args); } -#else - - const char* levelStr = logLevelNames[level]; - char buffer[512]; - vsnprintf(buffer, sizeof(buffer), format, args); - printf("\n[%s] JsRuntime Thread-%d: %s\n", levelStr, threadId, buffer); - -#endif //USE_ETHANLOG + else +#endif //USE_ETHANLOG + { + const char* levelStr = logLevelNames[level]; + char buffer[512]; + vsnprintf(buffer, sizeof(buffer), format, args); + printf("\n[%s] JsRuntime Thread-%d: %s\n", levelStr, threadId, buffer); + } va_end(args); -} + } diff --git a/src/NativeJSRenderer.cpp b/src/NativeJSRenderer.cpp index 4e98f41..ca8fb9e 100644 --- a/src/NativeJSRenderer.cpp +++ b/src/NativeJSRenderer.cpp @@ -235,7 +235,7 @@ uint32_t NativeJSRenderer::createApplication(ModuleSettings& moduleSettings, st uint32_t id=0; mUserMutex.lock(); id = createApplicationIdentifier(); - ApplicationRequest request(id, CREATE, "", moduleSettings.enableHttp, moduleSettings.enableXHR, moduleSettings.enableWebSocket, moduleSettings.enableWebSocketEnhanced, moduleSettings.enableFetch, moduleSettings.enableJSDOM, moduleSettings.enableWindow, moduleSettings.enablePlayer, userAgent); + ApplicationRequest request(id, CREATE, "", moduleSettings.enableHttp, moduleSettings.enableXHR, moduleSettings.enableWebSocket, moduleSettings.enableWebSocketEnhanced, moduleSettings.enableFetch, moduleSettings.enableJSDOM, moduleSettings.enableWindow, moduleSettings.enablePlayer, moduleSettings.enableMiniJSDOM, userAgent); gPendingRequests.push_back(request); mUserMutex.unlock(); return id; @@ -305,6 +305,7 @@ void NativeJSRenderer::createApplicationInternal(ApplicationRequest& appRequest) settings.enableJSDOM = appRequest.mEnableJSDOM; settings.enableWindow = appRequest.mEnableWindow; settings.enablePlayer = appRequest.mEnablePlayer; + settings.enableMiniJSDOM = appRequest.mEnableMiniJSDOM; uint32_t id= appRequest.mId; std::string userAgent = appRequest.mUserAgent; JavaScriptContextFeatures features(mEmbedThunderJS, mEmbedRdkWebBridge, mEnableWebSocketServer, settings); @@ -358,7 +359,7 @@ void NativeJSRenderer::runApplicationInternal(ApplicationRequest& appRequest) } JavaScriptContext* context = (JavaScriptContext*)mContextMap[id].context; context->setUrl(mContextMap[id].url); - if(context->getModuleSettings().enableJSDOM) + if(context->getModuleSettings().enableMiniJSDOM) { std::stringstream window; window<<"window.location = {\"href\":\"" << url << "\"};"; @@ -377,7 +378,7 @@ void NativeJSRenderer::runApplicationInternal(ApplicationRequest& appRequest) NativeJSLogger::log(INFO, "About to launch local app\n"); JavaScriptContext* context = (JavaScriptContext*)mContextMap[id].context; context->setUrl(mContextMap[id].url); - if(context->getModuleSettings().enableJSDOM) + if(context->getModuleSettings().enableMiniJSDOM) { std::stringstream window; window<<"window.location = {\"href\":\"file:/" << url << "\"};"; @@ -509,7 +510,7 @@ void NativeJSRenderer::run() ModuleSettings settings; uint32_t id = createApplicationIdentifier(); settings.enableJSDOM = mEnableTestFileDOMSupport; - ApplicationRequest appRequest(id, RUN, mTestFileName, settings.enableHttp, settings.enableXHR, settings.enableWebSocket, settings.enableWebSocketEnhanced, settings.enableFetch, settings.enableJSDOM, settings.enableWindow, settings.enablePlayer); + ApplicationRequest appRequest(id, RUN, mTestFileName, settings.enableHttp, settings.enableXHR, settings.enableWebSocket, settings.enableWebSocketEnhanced, settings.enableFetch, settings.enableJSDOM, settings.enableWindow, settings.enablePlayer, settings.enableMiniJSDOM); mUserMutex.lock(); NativeJSRenderer::createApplicationInternal(appRequest); NativeJSRenderer::runApplicationInternal(appRequest); diff --git a/src/jsc/JavaScriptContext.cpp b/src/jsc/JavaScriptContext.cpp index 3dd3389..d9fdd8e 100644 --- a/src/jsc/JavaScriptContext.cpp +++ b/src/jsc/JavaScriptContext.cpp @@ -139,16 +139,16 @@ void JavaScriptContext::loadAAMPJSBindingsLib() if (nullptr == gAAMPJSBindings->PlayerLibHandle) { static const char *aampJSBindingsLib = "libaampjsbindings.so"; - // This is required for NativeJS Plugin - #if 0 - static const char *jscLib = "libJavaScriptCore.so"; - jscLibHandle = dlopen(jscLib, RTLD_NOW | RTLD_GLOBAL); - if (!jscLibHandle) + if(!getenv("ETHAN_LOGGING_PIPE")) { - std::cout<<"dlopen error for jsc library " << dlerror() << std::endl; + // This is required for NativeJS Plugin + static const char *jscLib = "libJavaScriptCore.so"; + jscLibHandle = dlopen(jscLib, RTLD_NOW | RTLD_GLOBAL); + if (!jscLibHandle) + { + std::cout<<"dlopen error for jsc library " << dlerror() << std::endl; + } } - #endif - void *aampJSBindingsLibHandle = dlopen(aampJSBindingsLib, RTLD_NOW | RTLD_GLOBAL); if (aampJSBindingsLibHandle) { @@ -174,7 +174,8 @@ void JavaScriptContext::unloadAAMPJSBindingsLib() if (nullptr != gAAMPJSBindings->PlayerLibHandle) { dlclose(gAAMPJSBindings->PlayerLibHandle); - //dlclose(jscLibHandle); + if(!getenv("ETHAN_LOGGING_PIPE")) + dlclose(jscLibHandle); } } @@ -466,6 +467,12 @@ if (mModuleSettings.enablePlayer) runFile("linkedjsdomwrapper.js", nullptr/*, true*/); runFile("windowwrapper.js", nullptr/*, true*/); runFile("url.js", nullptr/*, true*/); + + } + else if (mModuleSettings.enableMiniJSDOM) + { + runFile("minified_linkedjsdom.js", nullptr/*, true*/); + runFile("url.js", nullptr/*, true*/); if(getenv("FIREBOLT_ENDPOINT")!=NULL) { auto FireboltEndpoint = std::string(getenv("FIREBOLT_ENDPOINT")); diff --git a/src/jsc/modules/minified_linkedjsdom.js b/src/jsc/modules/minified_linkedjsdom.js new file mode 100644 index 0000000..830cb0c --- /dev/null +++ b/src/jsc/modules/minified_linkedjsdom.js @@ -0,0 +1,164 @@ +var document = { + createElement: function() { + return { + style: {}, + setAttribute: function() {}, + getAttribute: function() { return null; }, + hasAttribute: function() { return false; }, + appendChild: function(c) { return c; }, + removeChild: function(c) { return c; }, + addEventListener: function() {}, + getBoundingClientRect: function() { return {top:0,left:0,right:0,bottom:0,width:0,height:0,x:0,y:0}; } + }; + }, + createEvent: function(type) { + return { + initEvent: function(t, bubbles, cancelable) { this.type = t; this.bubbles = bubbles; this.cancelable = cancelable; }, + type: '', + bubbles: false, + cancelable: false, + preventDefault: function() {} + }; + }, + getElementById: function(id) { return id === 'videoDiv' ? this.createElement() : null; }, + querySelector: function(s) { return s === '#videoDiv' ? this.getElementById('videoDiv') : null; }, + body: { appendChild: function(c) { return c; } }, + head: { appendChild: function(c) { return c; } } +}; + +function Event(t) { this.type = t; } +Event.prototype.preventDefault = function() {}; + +function HTMLElement() { + this.style = {}; + this.classList = { add: function() {}, remove: function() {}, toggle: function() {}, contains: function() { return false; } }; + this.children = []; + this.childNodes = []; +} +HTMLElement.prototype.setAttribute = function() {}; +HTMLElement.prototype.getAttribute = function() { return null; }; +HTMLElement.prototype.hasAttribute = function() { return false; }; +HTMLElement.prototype.removeAttribute = function() {}; +HTMLElement.prototype.appendChild = function(c) { this.children.push(c); this.childNodes.push(c); return c; }; +HTMLElement.prototype.removeChild = function(c) { return c; }; +HTMLElement.prototype.addEventListener = function() {}; +HTMLElement.prototype.removeEventListener = function() {}; +HTMLElement.prototype.dispatchEvent = function() {}; +HTMLElement.prototype.getBoundingClientRect = function() { return {top:0,left:0,right:0,bottom:0,width:0,height:0,x:0,y:0}; }; +HTMLElement.prototype.focus = function() {}; +HTMLElement.prototype.blur = function() {}; +HTMLElement.prototype.click = function() {}; + +function DOMParser() {} +DOMParser.prototype.parseFromString = function() { return document; }; + +function Blob(parts, options) { this.size = 0; this.type = (options && options.type) || ''; } +Blob.prototype.slice = function() { return new Blob([], {}); }; + +// AbortController for fetch API +function AbortController() { + this.signal = { aborted: false, addEventListener: function() {} }; +} +AbortController.prototype.abort = function() { + this.signal.aborted = true; +}; + +// Minimal fetch stub +function fetch(url, options) { + return new Promise(function(resolve, reject) { + if (options && options.signal && options.signal.aborted) { + var error = new Error('Aborted'); + error.name = 'AbortError'; + reject(error); + return; + } + // Stub response + resolve({ + ok: true, + status: 200, + json: function() { return Promise.resolve({}); }, + text: function() { return Promise.resolve(''); }, + blob: function() { return Promise.resolve(new Blob([], {})); } + }); + }); +} + +// Wrap timer functions to ensure .apply() works +var _setTimeout = setTimeout; +var _setInterval = setInterval; +var _clearTimeout = clearTimeout; +var _clearInterval = clearInterval; + +function wrappedSetTimeout(fn, delay) { + var args = Array.prototype.slice.call(arguments, 2); + return _setTimeout(function() { fn.apply(null, args); }, delay); +} +wrappedSetTimeout.apply = function(thisArg, argArray) { + if (!argArray || argArray.length === 0) return _setTimeout(); + if (argArray.length === 1) return _setTimeout(argArray[0]); + if (argArray.length === 2) return _setTimeout(argArray[0], argArray[1]); + var args = Array.prototype.slice.call(argArray, 2); + return _setTimeout(function() { argArray[0].apply(null, args); }, argArray[1]); +}; + +function wrappedSetInterval(fn, delay) { + var args = Array.prototype.slice.call(arguments, 2); + return _setInterval(function() { fn.apply(null, args); }, delay); +} +wrappedSetInterval.apply = function(thisArg, argArray) { + if (!argArray || argArray.length === 0) return _setInterval(); + if (argArray.length === 1) return _setInterval(argArray[0]); + if (argArray.length === 2) return _setInterval(argArray[0], argArray[1]); + var args = Array.prototype.slice.call(argArray, 2); + return _setInterval(function() { argArray[0].apply(null, args); }, argArray[1]); +}; + +function wrappedClearTimeout(id) { return _clearTimeout(id); } +wrappedClearTimeout.apply = function(thisArg, argArray) { + return _clearTimeout(argArray ? argArray[0] : undefined); +}; + +function wrappedClearInterval(id) { return _clearInterval(id); } +wrappedClearInterval.apply = function(thisArg, argArray) { + return _clearInterval(argArray ? argArray[0] : undefined); +}; + +var window = { + document: document, + location: {href:'',host:'127.0.0.1',hostname:'127.0.0.1'}, + navigator: {userAgent:'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36',platform:'Linux'}, + console: console, + setTimeout: wrappedSetTimeout, + setInterval: wrappedSetInterval, + clearTimeout: wrappedClearTimeout, + clearInterval: wrappedClearInterval, + addEventListener: function() {}, + Event: Event, + HTMLElement: HTMLElement, + DOMParser: DOMParser, + Blob: Blob, + AbortController: AbortController, + fetch: fetch, + Promise: Promise, + frames: { length: 0 } +}; + +window.window = window; +window.self = window; +var navigator = window.navigator; +var location = window.location; +window.top = window; +var tv = window.tv = {}; +var HTMLElement = window.HTMLElement; +var DOMParser = window.DOMParser; +var Event = window.Event; +var Blob = window.Blob; +var AbortController = window.AbortController; +var fetch = window.fetch; +var Promise = window.Promise; +var top = window; +var setTimeout = wrappedSetTimeout; +var setInterval = wrappedSetInterval; +var clearTimeout = wrappedClearTimeout; +var clearInterval = wrappedClearInterval; +var LinkedJSDOMLib = {parseHTML: function() { return {window:window,document:document,defaultView:window}; }}; diff --git a/src/jsruntime.cpp b/src/jsruntime.cpp index cdfe54e..f0e4bf9 100644 --- a/src/jsruntime.cpp +++ b/src/jsruntime.cpp @@ -128,6 +128,10 @@ int main(int argc, char* argv[]) { moduleSettings.enablePlayer = true; } + else if (strcmp(argv[i], "--enableMiniJSDOM") == 0) + { + moduleSettings.enableMiniJSDOM = true; + } else if (strcmp(argv[i], "--console") == 0) { consoleMode = true;