This commit is contained in:
949036910@qq.com
2026-05-28 08:47:06 +08:00
parent b0c3d97bfa
commit 1a32a59635

View File

@@ -41,6 +41,17 @@ static RE_REQUIRE: Lazy<Regex> =
const INLINE_ENTRY: &str = "__inline_entry__.js"; const INLINE_ENTRY: &str = "__inline_entry__.js";
/// Windows子进程不创建可见控制台窗口避免运行 node.exe 时闪黑框)。
#[cfg(windows)]
fn hide_console_window(cmd: &mut Command) {
use std::os::windows::process::CommandExt;
const CREATE_NO_WINDOW: u32 = 0x0800_0000;
cmd.as_std_mut().creation_flags(CREATE_NO_WINDOW);
}
#[cfg(not(windows))]
fn hide_console_window(_cmd: &mut Command) {}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum NodeError { pub enum NodeError {
#[error("node.exe 未找到(请检查 resources/nodejs/ 是否存在)")] #[error("node.exe 未找到(请检查 resources/nodejs/ 是否存在)")]
@@ -125,6 +136,13 @@ fn build_file_runner(entry_script: &str) -> String {
}}; }};
}})(); }})();
/** Windows 管道子进程write 后立刻 process.exit 会触发 libuv UV_HANDLE_CLOSING 断言 */
function writeAsync(stream, chunk) {{
return new Promise((resolve, reject) => {{
stream.write(chunk, (err) => (err ? reject(err) : resolve()));
}});
}}
(async () => {{ (async () => {{
let raw = ""; let raw = "";
process.stdin.setEncoding("utf8"); process.stdin.setEncoding("utf8");
@@ -134,29 +152,45 @@ fn build_file_runner(entry_script: &str) -> String {
require("./{entry_script}"); require("./{entry_script}");
if (typeof globalThis.__nodejsMain !== "function") {{ if (typeof globalThis.__nodejsMain !== "function") {{
process.stderr.write( await writeAsync(
"__EVT__" + JSON.stringify({{ process.stderr,
"__EVT__" +
JSON.stringify({{
type: "log", type: "log",
level: "error", level: "error",
msg: "脚本未注册 globalThis.__nodejsMain", msg: "脚本未注册 globalThis.__nodejsMain",
}}) + "\n" }}) +
"\n"
); );
process.exit(1); process.exitCode = 1;
return;
}} }}
try {{ try {{
const result = await globalThis.__nodejsMain(params); const result = await globalThis.__nodejsMain(params);
process.stdout.write( await writeAsync(
"__RESULT__" + JSON.stringify(result === undefined ? null : result) + "\n" process.stdout,
"__RESULT__" +
JSON.stringify(result === undefined ? null : result) +
"\n"
); );
process.exit(0);
}} catch (e) {{ }} catch (e) {{
const msg = (e && (e.stack || e.message)) || String(e); const msg = (e && (e.stack || e.message)) || String(e);
process.stderr.write( await writeAsync(
process.stderr,
"__EVT__" + JSON.stringify({{ type: "log", level: "error", msg }}) + "\n" "__EVT__" + JSON.stringify({{ type: "log", level: "error", msg }}) + "\n"
); );
process.exit(2); process.exitCode = 2;
}} }}
}})(); }})().catch(async (e) => {{
const msg = (e && (e.stack || e.message)) || String(e);
try {{
await writeAsync(
process.stderr,
"__EVT__" + JSON.stringify({{ type: "log", level: "error", msg }}) + "\n"
);
}} catch (_) {{}}
process.exitCode = 1;
}});
"# "#
) )
} }
@@ -369,6 +403,7 @@ async fn run_script_bundle(
if let Some(dir) = crate::cover_python::locate_cover_scripts_dir() { if let Some(dir) = crate::cover_python::locate_cover_scripts_dir() {
cmd.env("AICLIENT_COVER_SCRIPTS_DIR", dir); cmd.env("AICLIENT_COVER_SCRIPTS_DIR", dir);
} }
hide_console_window(&mut cmd);
let mut child = cmd.spawn()?; let mut child = cmd.spawn()?;
// 把 params JSON 灌进 stdin // 把 params JSON 灌进 stdin
@@ -456,9 +491,15 @@ async fn run_script_bundle(
result result
}); });
let status = child.wait().await?; // 与 stdout/stderr 读取并行等待避免子进程在管道未排空时退出Windows libuv
let stderr_tail = stderr_task.await.unwrap_or_default(); let (status, stderr_tail, result_line) = tokio::join!(
let result_line = stdout_task.await.unwrap_or(None); child.wait(),
stderr_task,
stdout_task,
);
let status = status?;
let stderr_tail = stderr_tail.unwrap_or_default();
let result_line = result_line.unwrap_or(None);
let _ = tokio::fs::remove_dir_all(&bundle_dir).await; let _ = tokio::fs::remove_dir_all(&bundle_dir).await;