1
- #pragma warning(disable : 4251)
2
-
3
1
#include " main/NodeJsHelper.h"
4
2
5
- #include " api/EventAPI.h"
6
- #include " engine/EngineManager.h"
7
3
#include " engine/EngineOwnData.h"
8
- #include " engine/RemoteCall.h"
9
4
#include " fmt/format.h"
10
5
#include " ll/api/Expected.h"
11
6
#include " ll/api/base/Containers.h"
12
7
#include " ll/api/chrono/GameChrono.h"
13
8
#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"
16
10
#include " ll/api/memory/Hook.h"
17
11
#include " ll/api/service/GamingStatus.h"
18
- #include " ll/api/service/ServerInfo.h"
19
12
#include " ll/api/thread/ServerThreadExecutor.h"
13
+ #include " ll/api/utils/ErrorUtils.h"
20
14
#include " ll/api/utils/StringUtils.h"
21
15
#include " lse/Entry.h"
22
- #include " main/Global.h "
16
+ #include " nlohmann/json.hpp "
23
17
#include " utils/Utils.h"
24
18
#include " uv/uv.h"
25
- #include " v8/v8.h"
19
+ #include " v8/v8.h" // IWYU pragma: keep
26
20
27
21
#define NODE_LIBRARY_NAME_W L" libnode.dll"
28
22
#define NODE_HOST_BINARY_NAME " node.exe"
@@ -43,7 +37,7 @@ std::unordered_map<script::ScriptEngine*, node::Environment*>
43
37
std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmentSetup>>* setups =
44
38
new std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmentSetup>>();
45
39
std::unordered_map<node::Environment*, bool > isRunning;
46
- std::vector <node::Environment*> uvLoopTask;
40
+ std::set <node::Environment*> uvLoopTask;
47
41
48
42
ll::Expected<> PatchDelayImport (HMODULE hAddon, HMODULE hLibNode) {
49
43
BYTE* base = (BYTE*)hAddon;
@@ -125,10 +119,16 @@ bool initNodeJs() {
125
119
char * cPath = (char *)path.c_str ();
126
120
uv_setup_args (1 , &cPath);
127
121
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 (
129
129
full_args,
130
130
{node::ProcessInitializationFlags::kNoInitializeV8 ,
131
- node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
131
+ node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
132
132
);
133
133
if (result->exit_code () != 0 ) {
134
134
lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (
@@ -237,25 +237,25 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
237
237
using namespace v8 ;
238
238
EngineScope enter (engine);
239
239
240
- string compiler = R"(
240
+ std:: string compiler = R"(
241
241
ll.import=ll.imports;
242
242
ll.export=ll.exports;)" ;
243
243
244
244
if (esm) {
245
245
compiler += fmt::format (
246
246
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())
255
252
.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);
258
256
}});
257
+ const timer = setTimeout(() => (timeout = true) && resolve(), 900);
258
+ return promise.finally(() => clearTimeout(timer));
259
259
)" ,
260
260
pluginDirPath,
261
261
entryScriptPath
@@ -282,7 +282,12 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
282
282
}};
283
283
require = PublicModule.createRequire(__PluginPath);
284
284
}})();
285
- require("{1}");
285
+ try{{
286
+ require("{1}");
287
+ }}catch(error){{
288
+ return require("util").inspect(error);
289
+ }};
290
+ return;
286
291
)" ,
287
292
pluginDirPath,
288
293
entryScriptPath
@@ -303,23 +308,45 @@ bool loadPluginCode(script::ScriptEngine* engine, std::string entryScriptPath, s
303
308
304
309
// Load code
305
310
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) {
308
336
node::Stop (env);
309
337
uv_stop (it->second ->event_loop ());
310
338
return false ;
311
339
}
312
-
313
340
// Start libuv event loop
314
- uvLoopTask.push_back (env);
341
+ uvLoopTask.insert (env);
315
342
ll::coro::keepThis (
316
343
[engine,
317
344
env,
318
345
isolate{it->second ->isolate ()},
319
346
isRunningMap{&isRunning},
320
347
eventLoop{it->second ->event_loop ()}]() -> ll::coro::CoroTask<> {
321
348
using namespace ll ::chrono_literals;
322
- while (std::find ( uvLoopTask.begin (), uvLoopTask. end (), env) != uvLoopTask. end ( )) {
349
+ while (uvLoopTask.contains ( env)) {
323
350
co_await 2_tick;
324
351
if (!(ll::getGamingStatus () != ll::GamingStatus::Running) && (*isRunningMap)[env]) {
325
352
EngineScope enter (engine);
@@ -365,7 +392,7 @@ bool stopEngine(node::Environment* env) {
365
392
node::Stop (env);
366
393
367
394
// Stop libuv event loop
368
- auto it = std::find ( uvLoopTask.begin (), uvLoopTask. end (), env);
395
+ auto it = uvLoopTask.find ( env);
369
396
if (it != uvLoopTask.end ()) {
370
397
uvLoopTask.erase (it);
371
398
}
0 commit comments