1- #pragma warning(disable : 4251)
2-
31#include " main/NodeJsHelper.h"
42
5- #include " api/EventAPI.h"
6- #include " engine/EngineManager.h"
73#include " engine/EngineOwnData.h"
8- #include " engine/RemoteCall.h"
94#include " fmt/format.h"
105#include " ll/api/Expected.h"
116#include " ll/api/base/Containers.h"
127#include " ll/api/chrono/GameChrono.h"
138#include " ll/api/coro/CoroTask.h"
14- #include " ll/api/io/FileUtils.h"
15- #include " ll/api/io/LogLevel.h"
9+ #include " ll/api/io/Logger.h"
1610#include " ll/api/memory/Hook.h"
1711#include " ll/api/service/GamingStatus.h"
18- #include " ll/api/service/ServerInfo.h"
1912#include " ll/api/thread/ServerThreadExecutor.h"
13+ #include " ll/api/utils/ErrorUtils.h"
2014#include " ll/api/utils/StringUtils.h"
2115#include " lse/Entry.h"
22- #include " main/Global.h "
16+ #include " nlohmann/json.hpp "
2317#include " utils/Utils.h"
2418#include " uv/uv.h"
25- #include " v8/v8.h"
19+ #include " v8/v8.h" // IWYU pragma: keep
2620
2721#define NODE_LIBRARY_NAME_W L" libnode.dll"
2822#define NODE_HOST_BINARY_NAME " node.exe"
@@ -43,7 +37,7 @@ std::unordered_map<script::ScriptEngine*, node::Environment*>
4337std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmentSetup>>* setups =
4438 new std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmentSetup>>();
4539std::unordered_map<node::Environment*, bool > isRunning;
46- std::vector <node::Environment*> uvLoopTask;
40+ std::set <node::Environment*> uvLoopTask;
4741
4842ll::Expected<> PatchDelayImport (HMODULE hAddon, HMODULE hLibNode) {
4943 BYTE* base = (BYTE*)hAddon;
@@ -125,10 +119,16 @@ bool initNodeJs() {
125119 char * cPath = (char *)path.c_str ();
126120 uv_setup_args (1 , &cPath);
127121 auto full_args = std::vector<std::string>{path};
128- auto result = node::InitializeOncePerProcess (
122+ #if defined(LSE_DEBUG) || defined(LSE_TEST)
123+ full_args.insert (
124+ full_args.end (),
125+ {" --experimental-strip-types" , " --enable-source-maps" , " --disable-warning=ExperimentalWarning" }
126+ );
127+ #endif
128+ auto result = node::InitializeOncePerProcess (
129129 full_args,
130130 {node::ProcessInitializationFlags::kNoInitializeV8 ,
131- node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
131+ node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
132132 );
133133 if (result->exit_code () != 0 ) {
134134 lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (
@@ -237,25 +237,25 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
237237 using namespace v8 ;
238238 EngineScope enter (engine);
239239
240- string compiler = R"(
240+ std:: string compiler = R"(
241241 ll.import=ll.imports;
242242 ll.export=ll.exports;)" ;
243243
244244 if (esm) {
245245 compiler += fmt::format (
246246 R"(
247- Promise.all([import("url"), import("util")])
248- .then(([url, util]) => {{
249- const moduleUrl = url.pathToFileURL("{1}").href;
250- import(moduleUrl).catch((error) => {{
251- logger.error(`Failed to load ESM module: `, util.inspect(error));
252- process.exit(1);
253- }});
254- }})
247+ const moduleUrl = require("url").pathToFileURL("{1}").href;
248+ const {{ promise, resolve, reject }} = Promise.withResolvers();
249+ let timeout = false;
250+ import(moduleUrl)
251+ .then(() => resolve())
255252 .catch((error) => {{
256- console.error(`Failed to import "url" or "util" module:`, error);
257- process.exit(1);
253+ const msg = `Failed to load ESM module: ${{require("util").inspect(error)}}`;
254+ if (timeout) logger.error(msg), process.exit(1);
255+ else resolve(msg);
258256 }});
257+ const timer = setTimeout(() => (timeout = true) && resolve(), 900);
258+ return promise.finally(() => clearTimeout(timer));
259259 )" ,
260260 pluginDirPath,
261261 entryScriptPath
@@ -282,7 +282,12 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
282282 }};
283283 require = PublicModule.createRequire(__PluginPath);
284284 }})();
285- require("{1}");
285+ try{{
286+ require("{1}");
287+ }}catch(error){{
288+ return require("util").inspect(error);
289+ }};
290+ return;
286291 )" ,
287292 pluginDirPath,
288293 entryScriptPath
@@ -303,23 +308,45 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
303308
304309 // Load code
305310 MaybeLocal<v8::Value> loadenv_ret = node::LoadEnvironment (env, compiler);
306- if (loadenv_ret.IsEmpty ()) // There has been a JS exception.
307- {
311+ bool loadFailed = loadenv_ret.IsEmpty ();
312+
313+ auto & logger = lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ();
314+
315+ if (!loadFailed) {
316+ v8::Local<v8::Value> errorMsg = loadenv_ret.ToLocalChecked ();
317+ if (loadenv_ret.ToLocalChecked ()->IsPromise ()) {
318+ // wait for module loaded
319+ auto promise = loadenv_ret.ToLocalChecked ().As <v8::Promise>();
320+ auto deadline = std::chrono::steady_clock::now () + std::chrono::seconds{1 };
321+ while (promise->State () == v8::Promise::kPending && std::chrono::steady_clock::now () <= deadline) {
322+ uv_run (it->second ->event_loop (), UV_RUN_ONCE);
323+ it->second ->isolate ()->PerformMicrotaskCheckpoint ();
324+ }
325+ if (promise->State () == v8::Promise::kFulfilled ) {
326+ errorMsg = promise->Result ();
327+ }
328+ }
329+ if (errorMsg->IsString ()) {
330+ v8::String::Utf8Value value{it->second ->isolate (), errorMsg};
331+ logger.error (std::string_view{*value, static_cast <size_t >(value.length ())});
332+ loadFailed = true ;
333+ }
334+ }
335+ if (loadFailed) {
308336 node::Stop (env);
309337 uv_stop (it->second ->event_loop ());
310338 return false ;
311339 }
312-
313340 // Start libuv event loop
314- uvLoopTask.push_back (env);
341+ uvLoopTask.insert (env);
315342 ll::coro::keepThis (
316343 [engine,
317344 env,
318345 isolate{it->second ->isolate ()},
319346 isRunningMap{&isRunning},
320347 eventLoop{it->second ->event_loop ()}]() -> ll::coro::CoroTask<> {
321348 using namespace ll ::chrono_literals;
322- while (std::find ( uvLoopTask.begin (), uvLoopTask. end (), env) != uvLoopTask. end ( )) {
349+ while (uvLoopTask.contains ( env)) {
323350 co_await 2_tick;
324351 if (!(ll::getGamingStatus () != ll::GamingStatus::Running) && (*isRunningMap)[env]) {
325352 EngineScope enter (engine);
@@ -365,7 +392,7 @@ bool stopEngine(node::Environment* env) {
365392 node::Stop (env);
366393
367394 // Stop libuv event loop
368- auto it = std::find ( uvLoopTask.begin (), uvLoopTask. end (), env);
395+ auto it = uvLoopTask.find ( env);
369396 if (it != uvLoopTask.end ()) {
370397 uvLoopTask.erase (it);
371398 }
0 commit comments