From 12301ecf5d9efc2d1927779f3c60c43ba6d02bd1 Mon Sep 17 00:00:00 2001 From: kkEngine <78795688+kkEngine@users.noreply.github.com> Date: Fri, 26 Jul 2024 17:11:45 +0300 Subject: [PATCH] - Added the possibility to add new js function callbacks --- .../CEF/NirnLabSubprocessCefApp.cpp | 139 +++++++++++------- .../CEF/NirnLabSubprocessCefApp.h | 14 +- src/CEFSubprocess/IPC.h | 1 + src/UIPlatform/CEF/DefaultBrowser.cpp | 41 ++++-- src/UIPlatform/CEF/DefaultBrowser.h | 2 +- src/UIPlatform/CEF/NirnLabCefApp.cpp | 6 + src/UIPlatform/CEF/NirnLabCefClient.cpp | 3 +- src/UIPlatform/JS/JSFunctionStorage.cpp | 25 +++- src/UIPlatform/JS/JSFunctionStorage.h | 1 + src/UIPlatform/Menus/CEFMenu.cpp | 2 +- .../NirnLabUIPlatformAPI/IBrowser.h | 10 +- src/UIPlatform/NirnLabUIPlatformAPI/JSTypes.h | 28 ++++ .../NirnLabUIPlatformAPI/IBrowser.h | 10 +- .../NirnLabUIPlatformAPI/JSTypes.h | 42 ++++++ .../TestCases/LocalTestPage.cpp | 17 ++- 15 files changed, 257 insertions(+), 84 deletions(-) diff --git a/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.cpp b/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.cpp index 1259f4b..31c04bf 100644 --- a/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.cpp +++ b/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.cpp @@ -20,13 +20,71 @@ namespace NL::CEF spdlog::set_default_logger(logger); } + size_t NirnLabSubprocessCefApp::AddFunctionHandlers(CefRefPtr a_browser, + CefRefPtr a_frame, + CefProcessId a_sourceProcess, + CefRefPtr a_funcDict) + { + size_t addedFuncCount = 0; + + const auto v8Context = a_frame->GetV8Context(); + if (!v8Context->Enter()) + { + spdlog::error("{}[{}]: can't enter v8 context", NameOf(NirnLabSubprocessCefApp::AddFunctionHandlers), ::GetCurrentProcessId()); + return addedFuncCount; + } + + CefDictionaryValue::KeyList keyList; + if (!a_funcDict->GetKeys(keyList)) + { + spdlog::error("{}[{}]: can't get keys from function dictionary", NameOf(NirnLabSubprocessCefApp::AddFunctionHandlers), ::GetCurrentProcessId()); + } + else + { + for (const auto& objectName : keyList) + { + auto currentObjectValue = v8Context->GetGlobal(); + const auto funcList = a_funcDict->GetList(objectName); + for (auto i = 0; i < funcList->GetSize(); ++i) + { + const auto& funcName = funcList->GetString(i); + if (funcName.empty()) + { + continue; + } + + ++addedFuncCount; + + if (!objectName.empty() || objectName != IPC_JS_WINDOW_OBJECT_NAME) + { + auto objectValue = currentObjectValue->GetValue(objectName); + if (objectValue == nullptr || objectValue->IsNull() || objectValue->IsUndefined()) + { + objectValue = CefV8Value::CreateObject(nullptr, nullptr); + currentObjectValue->SetValue(objectName, objectValue, V8_PROPERTY_ATTRIBUTE_NONE); + } + currentObjectValue = objectValue; + } + + CefRefPtr funcHandler = new NL::JS::CEFFunctionHandler(a_browser, objectName); + CefRefPtr funcValue = CefV8Value::CreateFunction(funcName, funcHandler); + currentObjectValue->SetValue(funcName, funcValue, V8_PROPERTY_ATTRIBUTE_NONE); + } + } + } + + v8Context->Exit(); + return addedFuncCount; + } + void NirnLabSubprocessCefApp::OnBeforeCommandLineProcessing(CefString const& process_type, CefRefPtr command_line) { + m_processType = process_type; InitLog(nullptr); DWORD mainProcessId = std::stoi(command_line->GetSwitchValue(IPC_CL_PROCESS_ID_NAME).ToWString()); - if (mainProcessId) + if (mainProcessId && process_type == RENDER_PROCESS_TYPE) { new std::thread([=]() { const auto procHandle = ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, mainProcessId); @@ -39,6 +97,7 @@ namespace NL::CEF // // log or email to sportloto? // } + std::this_thread::sleep_for(1.42s); ::TerminateProcess(::GetCurrentProcess(), EXIT_SUCCESS); }); } @@ -53,38 +112,12 @@ namespace NL::CEF CefRefPtr extra_info) { m_logSink->SetBrowser(browser); - - if (extra_info != nullptr && extra_info->GetSize() > 0) - { - CefDictionaryValue::KeyList keyList; - if (!extra_info->GetKeys(keyList)) - { - spdlog::error("{}: error format in param {}", NameOf(NirnLabSubprocessCefApp::OnBrowserCreated), NameOf(extra_info)); - } - else - { - for (const auto& key : keyList) - { - const auto funcList = extra_info->GetList(key); - for (auto i = 0; i < funcList->GetSize(); ++i) - { - const auto funcName = funcList->GetValue(i)->GetString(); - if (!funcName.empty()) - { - m_funcQueue.AddFunction(key, funcName); - } - else - { - spdlog::error("{}: error format in param {}, key {}", NameOf(NirnLabSubprocessCefApp::OnBrowserCreated), NameOf(extra_info), key.ToString().c_str()); - } - } - } - } - } + spdlog::info("{}[{}]: browser created with id {}", NameOf(NirnLabSubprocessCefApp), ::GetCurrentProcessId(), browser->GetIdentifier()); } void NirnLabSubprocessCefApp::OnBrowserDestroyed(CefRefPtr browser) { + spdlog::info("{}[{}]: browser destroyed with id {}", NameOf(NirnLabSubprocessCefApp), ::GetCurrentProcessId(), browser->GetIdentifier()); m_logSink->SetBrowser(nullptr); } @@ -92,42 +125,36 @@ namespace NL::CEF CefRefPtr frame, CefRefPtr context) { - if (!frame->IsMain()) + if (frame->IsMain()) { - return; + auto message = CefProcessMessage::Create(IPC_JS_CONTEXT_CREATED); + frame->SendProcessMessage(PID_BROWSER, message); } + } - std::uint32_t functionsCount = 0; - auto currentObjectValue = context->GetGlobal(); + void NirnLabSubprocessCefApp::OnContextReleased(CefRefPtr browser, + CefRefPtr frame, + CefRefPtr context) + { + } - auto addFuncInfo = m_funcQueue.PopNext(); - while (addFuncInfo != nullptr) + bool NirnLabSubprocessCefApp::OnProcessMessageReceived(CefRefPtr browser, + CefRefPtr frame, + CefProcessId source_process, + CefRefPtr message) + { + if (message->GetName() == IPC_JS_FUNCION_ADD_EVENT) { - ++functionsCount; - if (!addFuncInfo->objectName.empty() || addFuncInfo->objectName != IPC_JS_WINDOW_OBJECT_NAME) + const auto funcDict = message->GetArgumentList()->GetDictionary(0); + if (funcDict == nullptr) { - auto objectValue = currentObjectValue->GetValue(addFuncInfo->objectName); - if (objectValue == nullptr || objectValue->IsNull() || objectValue->IsUndefined()) - { - objectValue = CefV8Value::CreateObject(nullptr, nullptr); - currentObjectValue->SetValue(addFuncInfo->objectName, objectValue, V8_PROPERTY_ATTRIBUTE_NONE); - } - currentObjectValue = objectValue; + return true; } - CefRefPtr funcHandler = new NL::JS::CEFFunctionHandler(browser, addFuncInfo->objectName); - CefRefPtr funcValue = CefV8Value::CreateFunction(addFuncInfo->functionName, funcHandler); - currentObjectValue->SetValue(addFuncInfo->functionName, funcValue, V8_PROPERTY_ATTRIBUTE_NONE); - - addFuncInfo = m_funcQueue.PopNext(); + const auto addedFuncCount = AddFunctionHandlers(browser, frame, source_process, funcDict); + spdlog::info("{}[{}]: registered {} functions for the browser with id {}", NameOf(NirnLabSubprocessCefApp::OnProcessMessageReceived), ::GetCurrentProcessId(), addedFuncCount, browser->GetIdentifier()); } - spdlog::info("{}: registered {} functions for the browser with id {}", NameOf(OnContextCreated), functionsCount, browser->GetIdentifier()); - } - - void NirnLabSubprocessCefApp::OnContextReleased(CefRefPtr browser, - CefRefPtr frame, - CefRefPtr context) - { + return false; } } diff --git a/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.h b/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.h index d43a4c0..905605c 100644 --- a/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.h +++ b/src/CEFSubprocess/CEF/NirnLabSubprocessCefApp.h @@ -1,5 +1,7 @@ #pragma once +#define RENDER_PROCESS_TYPE "renderer" + #include "PCH.h" #include "Log/IPCLogSink.hpp" #include "JS/CEFFunctionQueue.h" @@ -13,14 +15,18 @@ namespace NL::CEF IMPLEMENT_REFCOUNTING(NirnLabSubprocessCefApp); private: - NL::JS::CEFFunctionQueue m_funcQueue; - std::shared_ptr m_logSink = nullptr; + CefString m_processType; void InitLog(CefRefPtr a_browser); public: NirnLabSubprocessCefApp() = default; + size_t AddFunctionHandlers(CefRefPtr a_browser, + CefRefPtr a_frame, + CefProcessId a_sourceProcess, + CefRefPtr a_funcDict); + // CefApp void OnBeforeCommandLineProcessing(CefString const& process_type, CefRefPtr command_line) override; CefRefPtr GetRenderProcessHandler() override; @@ -35,5 +41,9 @@ namespace NL::CEF void OnContextReleased(CefRefPtr browser, CefRefPtr frame, CefRefPtr context) override; + bool OnProcessMessageReceived(CefRefPtr browser, + CefRefPtr frame, + CefProcessId source_process, + CefRefPtr message) override; }; } diff --git a/src/CEFSubprocess/IPC.h b/src/CEFSubprocess/IPC.h index e23eb95..3ef575b 100644 --- a/src/CEFSubprocess/IPC.h +++ b/src/CEFSubprocess/IPC.h @@ -4,5 +4,6 @@ #define IPC_LOG_EVENT "log-event" #define IPC_JS_WINDOW_OBJECT_NAME "window" +#define IPC_JS_CONTEXT_CREATED "js-context-created" #define IPC_JS_FUNCTION_CALL_EVENT "js-function-call" #define IPC_JS_FUNCION_ADD_EVENT "js-function-add" diff --git a/src/UIPlatform/CEF/DefaultBrowser.cpp b/src/UIPlatform/CEF/DefaultBrowser.cpp index 6ff478b..7df01cc 100644 --- a/src/UIPlatform/CEF/DefaultBrowser.cpp +++ b/src/UIPlatform/CEF/DefaultBrowser.cpp @@ -50,24 +50,35 @@ namespace NL::CEF // load url if (m_isUrlCached) { - LoadBrowserURL(m_urlCache.c_str(), m_urlClearJSCache); + LoadBrowserURL(m_urlCache.c_str(), m_clearJSFunctions); } }); m_onMainFrameLoadStart_Connection = m_cefClient->onMainFrameLoadStart.connect([&]() { - std::lock_guard locker(m_urlMutex); - m_isPageLoaded = false; - }); - - m_onMainFrameLoadEnd_Connection = m_cefClient->onMainFrameLoadEnd.connect([&]() { std::lock_guard locker(m_urlMutex); m_isPageLoaded = true; + + // JS funcs callback + if (m_clearJSFunctions) + { + m_jsFuncStorage->ClearFunctionCallback(); + } + else + { + const auto browser = m_cefClient->GetBrowser(); + if (browser != nullptr && m_jsFuncStorage->GetSize() > 0) + { + auto cefMessage = CefProcessMessage::Create(IPC_JS_FUNCION_ADD_EVENT); + cefMessage->GetArgumentList()->SetDictionary(0, m_jsFuncStorage->ConvertToCefDictionary()); + browser->GetMainFrame()->SendProcessMessage(CefProcessId::PID_RENDERER, cefMessage); + } + } - // JS funcs for (auto& funcInfo : m_jsFuncCallbackInfoCache) { AddFunctionCallbackAndSendMessage(funcInfo); } + m_jsFuncCallbackInfoCache.clear(); // JS exec scripts if (!m_jsExecCache.empty()) @@ -219,8 +230,12 @@ namespace NL::CEF if (browser != nullptr) { auto cefMessage = CefProcessMessage::Create(IPC_JS_FUNCION_ADD_EVENT); - cefMessage->GetArgumentList()->SetDictionary(0, m_jsFuncStorage->ConvertToCefDictionary()); - + auto dictValue = CefDictionaryValue::Create(); + auto listValue = CefListValue::Create(); + listValue->SetSize(1); + listValue->SetString(0, CefString(a_callbackInfo.funcName)); + dictValue->SetList(CefString(a_callbackInfo.objectName), listValue); + cefMessage->GetArgumentList()->SetDictionary(0, dictValue); browser->GetMainFrame()->SendProcessMessage(CefProcessId::PID_RENDERER, cefMessage); } } @@ -303,18 +318,18 @@ namespace NL::CEF void __cdecl DefaultBrowser::LoadBrowserURL(const char* a_url, bool a_clearJSFunctions) { std::lock_guard locker(m_urlMutex); - if (!IsBrowserReady()) + m_clearJSFunctions = a_clearJSFunctions; + if (!IsPageLoaded()) { m_isUrlCached = true; m_urlCache = a_url; - m_urlClearJSCache = a_clearJSFunctions; return; } const auto frame = m_cefClient->GetBrowser()->GetMainFrame(); if (frame) { - + m_isPageLoaded = false; frame->LoadURL(CefString(a_url)); } else @@ -354,7 +369,7 @@ namespace NL::CEF std::lock_guard locker(m_urlMutex); if (!IsPageLoaded()) { - m_jsFuncCallbackInfoCache.push_back(NL::JS::JSFuncInfoString(a_callbackInfo)); + m_jsFuncCallbackInfoCache.push_back(a_callbackInfo); return; } diff --git a/src/UIPlatform/CEF/DefaultBrowser.h b/src/UIPlatform/CEF/DefaultBrowser.h index e10e5a4..de43204 100644 --- a/src/UIPlatform/CEF/DefaultBrowser.h +++ b/src/UIPlatform/CEF/DefaultBrowser.h @@ -24,7 +24,7 @@ namespace NL::CEF std::recursive_mutex m_urlMutex; bool m_isUrlCached = false; bool m_isPageLoaded = false; - bool m_urlClearJSCache = true; + bool m_clearJSFunctions = false; std::string m_urlCache = ""; // Focus diff --git a/src/UIPlatform/CEF/NirnLabCefApp.cpp b/src/UIPlatform/CEF/NirnLabCefApp.cpp index 68c0c68..3c13a82 100644 --- a/src/UIPlatform/CEF/NirnLabCefApp.cpp +++ b/src/UIPlatform/CEF/NirnLabCefApp.cpp @@ -23,6 +23,12 @@ namespace NL::CEF // tell Chromium to autoplay