1
- #include < filesystem>
2
1
#pragma warning(disable : 4251)
3
2
3
+ #include " main/NodeJsHelper.h"
4
+
4
5
#include " api/EventAPI.h"
5
6
#include " engine/EngineManager.h"
6
7
#include " engine/EngineOwnData.h"
15
16
#include " ll/api/thread/ServerThreadExecutor.h"
16
17
#include " ll/api/utils/StringUtils.h"
17
18
#include " main/Global.h"
18
- #include " main/NodeJsHelper .h"
19
+ #include " utils/Utils .h"
19
20
#include " uv/uv.h"
20
21
#include " v8/v8.h"
21
22
22
- #include < functional>
23
-
24
23
using ll::chrono_literals::operator " " _tick;
25
24
26
25
// pre-declare
@@ -41,24 +40,25 @@ std::vector<node::Environment*> uvLoopTask;
41
40
42
41
bool initNodeJs () {
43
42
// Init NodeJs
44
- WCHAR buf[MAX_PATH];
45
- GetCurrentDirectory (MAX_PATH, buf);
46
- auto path = ll::string_utils::wstr2str (buf) + " \\ bedrock_server_mod.exe" ;
43
+ auto path = ll::string_utils::u8str2str (ll::sys_utils::getModulePath (nullptr ).value ().u8string ());
47
44
char * cPath = (char *)path.c_str ();
48
45
uv_setup_args (1 , &cPath);
49
- args = {path};
50
- auto result = node::InitializeOncePerProcess (
51
- args ,
46
+ auto full_args = std::vector<std::string> {path};
47
+ auto result = node::InitializeOncePerProcess (
48
+ full_args ,
52
49
{node::ProcessInitializationFlags::kNoInitializeV8 ,
53
- node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
50
+ node::ProcessInitializationFlags::kNoInitializeNodeV8Platform }
54
51
);
55
- exec_args = result->exec_args ();
56
52
if (result->exit_code () != 0 ) {
57
53
lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (
58
54
" Failed to initialize node! NodeJs plugins won't be loaded"
59
55
);
56
+ for (const std::string& error : result->errors ())
57
+ lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (error);
60
58
return false ;
61
59
}
60
+ args = result->args ();
61
+ exec_args = result->exec_args ();
62
62
63
63
// Init V8
64
64
using namespace v8 ;
@@ -382,8 +382,8 @@ bool isESModulesSystem(const std::string& dirPath) {
382
382
383
383
bool processConsoleNpmCmd (const std::string& cmd) {
384
384
#ifdef LEGACY_SCRIPT_ENGINE_BACKEND_NODEJS
385
- if (cmd.starts_with (" npm " )) {
386
- executeNpmCommand (cmd);
385
+ if (cmd.starts_with (" npm " ) || cmd. starts_with ( " npx " ) ) {
386
+ executeNpmCommand (SplitCmdLine ( cmd) );
387
387
return false ;
388
388
} else {
389
389
return true ;
@@ -393,21 +393,35 @@ bool processConsoleNpmCmd(const std::string& cmd) {
393
393
#endif
394
394
}
395
395
396
- int executeNpmCommand (const std::string& cmd , std::string workingDir) {
396
+ int executeNpmCommand (std::vector<std:: string> npmArgs , std::string workingDir) {
397
397
if (!nodeJsInited && !initNodeJs ()) {
398
398
return -1 ;
399
399
}
400
400
std::string engineDir =
401
401
ll::string_utils::u8str2str (lse::LegacyScriptEngine::getInstance ().getSelf ().getModDir ().u8string ());
402
402
if (workingDir.empty ()) workingDir = engineDir;
403
- std::vector<std::string> errors;
403
+
404
+ auto npmPath = std::filesystem::absolute (engineDir) / " node_modules" / " npm" / " bin" / " npm-cli.js" ;
405
+ std::vector<std::string>& env_args = npmArgs;
406
+ if (!env_args.empty () && (env_args[0 ] == " npm" || env_args[0 ] == " npx" )) {
407
+ if (env_args[0 ] == " npx" ) {
408
+ npmPath = std::filesystem::absolute (engineDir) / " node_modules" / " npm" / " bin" / " npx-cli.js" ;
409
+ }
410
+ env_args.erase (env_args.begin ());
411
+ }
412
+ auto scriptPath = ll::string_utils::replaceAll (ll::string_utils::u8str2str (npmPath.u8string ()), " \\ " , " /" );
413
+ env_args.insert (env_args.begin (), {args[0 ], scriptPath});
414
+
415
+ std::vector<std::string> errors;
416
+
404
417
std::unique_ptr<node::CommonEnvironmentSetup> setup = node::CommonEnvironmentSetup::Create (
405
418
platform.get (),
406
419
&errors,
407
- args ,
420
+ env_args ,
408
421
exec_args,
409
422
node::EnvironmentFlags::kOwnsProcessState
410
423
);
424
+
411
425
// if kOwnsInspector set, inspector_agent.cc:681
412
426
// CHECK_EQ(start_io_thread_async_initialized.exchange(true), false) fail!
413
427
@@ -437,26 +451,40 @@ int executeNpmCommand(const std::string& cmd, std::string workingDir) {
437
451
R"(
438
452
const engineDir = "{0}";
439
453
const workingDir = "{1}";
440
- const command = "{2}";
441
- const oldCwd = process.cwd();
454
+ const scriptPath = "{2}";
442
455
const publicRequire = require("module").createRequire(
443
456
require("path").resolve(engineDir) + require("path").sep
444
457
);
458
+ // Record states and restore at exit
459
+ const oldCwd = process.cwd();
460
+ const oldEnv = Object.entries(process.env).filter(([k]) => k.startsWith("npm_"));
461
+ const oldTitle = process.title;
462
+ process.on("exit", () => {{
463
+ Object.keys(process.env)
464
+ .filter((k) => k.startsWith("npm_"))
465
+ .forEach((k) => delete process.env[k]);
466
+ oldEnv.forEach(([k, v]) => (process.env[k] = v));
467
+ process.title = oldTitle;
468
+ process.chdir(oldCwd);
469
+ }});
470
+
445
471
process.chdir(workingDir);
446
- publicRequire("npm-js-interface")(command);
447
- process.chdir(oldCwd);
472
+ publicRequire(scriptPath);
448
473
)" ,
449
474
engineDir,
450
475
workingDir,
451
- cmd
476
+ scriptPath
452
477
);
453
478
454
479
try {
455
- node::SetProcessExitHandler (env, [&](node::Environment* env_, int exit_code) { node::Stop (env); });
480
+ node::SetProcessExitHandler (env, [&](node::Environment*, int exit_code_) {
481
+ exit_code = exit_code_;
482
+ node::Stop (env);
483
+ });
456
484
MaybeLocal<v8::Value> loadenv_ret = node::LoadEnvironment (env, executeJs);
457
485
if (loadenv_ret.IsEmpty ()) // There has been a JS exception.
458
- throw " error " ;
459
- exit_code = node::SpinEventLoop (env).FromMaybe (0 );
486
+ throw std::runtime_error ( " Failed at LoadEnvironment " ) ;
487
+ exit_code = node::SpinEventLoop (env).FromMaybe (exit_code );
460
488
} catch (...) {
461
489
lse::LegacyScriptEngine::getInstance ().getSelf ().getLogger ().error (
462
490
" Fail to execute NPM command. Error occurs"
0 commit comments