Skip to content

Commit ebf942c

Browse files
committed
fix: fix onServerStarted event for nodejs engine
1 parent fa4f42d commit ebf942c

File tree

2 files changed

+60
-34
lines changed

2 files changed

+60
-34
lines changed

src/legacy/main/NodeJsHelper.cpp

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,22 @@
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*>
4337
std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmentSetup>>* setups =
4438
new std::unordered_map<script::ScriptEngine*, std::unique_ptr<node::CommonEnvironmentSetup>>();
4539
std::unordered_map<node::Environment*, bool> isRunning;
46-
std::vector<node::Environment*> uvLoopTask;
40+
std::set<node::Environment*> uvLoopTask;
4741

4842
ll::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
}

src/legacy/main/NodeJsHelper.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#pragma once
22
#pragma warning(disable : 4251)
3-
#include "legacy/main/Global.h"
3+
#include "legacy/main/Global.h" // IWYU pragma: keep
4+
#include "node.h"
45

56
#include <ScriptX/ScriptX.h>
6-
#include <map>
7-
#include <node.h>
87
#include <string>
98

109
namespace NodeJsHelper {

0 commit comments

Comments
 (0)