137 lines
4.0 KiB
JavaScript
137 lines
4.0 KiB
JavaScript
import { execFileSync, spawn } from 'node:child_process';
|
|
import { existsSync, readFileSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
|
|
const repoRoot = process.cwd();
|
|
const apiServerExePath = resolve(
|
|
repoRoot,
|
|
'server-rs/target/debug/api-server.exe',
|
|
);
|
|
const shellEnvKeys = new Set(Object.keys(process.env));
|
|
|
|
function loadEnvFile(path, target) {
|
|
if (!existsSync(path)) {
|
|
return;
|
|
}
|
|
|
|
const rawText = readFileSync(path, 'utf8');
|
|
for (const rawLine of rawText.split(/\r?\n/u)) {
|
|
const line = rawLine.trim();
|
|
if (!line || line.startsWith('#')) {
|
|
continue;
|
|
}
|
|
|
|
const match = line.match(/^([A-Za-z_][A-Za-z0-9_]*)=(.*)$/u);
|
|
if (!match) {
|
|
continue;
|
|
}
|
|
|
|
const [, key, rawValue] = match;
|
|
// 只保留启动命令行和外层 shell 已显式传入的环境变量优先级;
|
|
// `.env.local` 需要能覆盖 `.env`,否则本地短信登录会被默认 false 压住。
|
|
if (shellEnvKeys.has(key)) {
|
|
continue;
|
|
}
|
|
|
|
target[key] = rawValue.replace(/^['"]|['"]$/gu, '');
|
|
}
|
|
}
|
|
|
|
const mergedEnv = { ...process.env };
|
|
// 保持与 dev-web-rust.mjs / dev-rust-stack.sh 一致:shell > .env > .env.local > .env.secrets.local。
|
|
loadEnvFile(resolve(repoRoot, '.env'), mergedEnv);
|
|
loadEnvFile(resolve(repoRoot, '.env.local'), mergedEnv);
|
|
loadEnvFile(resolve(repoRoot, '.env.secrets.local'), mergedEnv);
|
|
|
|
mergedEnv.GENARRATIVE_API_HOST = mergedEnv.GENARRATIVE_API_HOST || '127.0.0.1';
|
|
mergedEnv.GENARRATIVE_API_PORT = mergedEnv.GENARRATIVE_API_PORT || '3100';
|
|
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL =
|
|
mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL || 'http://127.0.0.1:3101';
|
|
mergedEnv.GENARRATIVE_SPACETIME_DATABASE = mergedEnv.GENARRATIVE_SPACETIME_DATABASE || '';
|
|
mergedEnv.GENARRATIVE_SPACETIME_TOKEN = mergedEnv.GENARRATIVE_SPACETIME_TOKEN || '';
|
|
|
|
if (!mergedEnv.GENARRATIVE_SPACETIME_DATABASE) {
|
|
console.error(
|
|
'[api-server] 缺少 GENARRATIVE_SPACETIME_DATABASE。',
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
function stopExistingWindowsApiServer() {
|
|
if (process.platform !== 'win32') {
|
|
return;
|
|
}
|
|
|
|
// Windows 下 cargo 重新编译时无法覆盖仍在运行的 exe,只清理本仓库 target 内的旧进程。
|
|
const command = [
|
|
'$ErrorActionPreference = "Continue"',
|
|
'$target = [System.IO.Path]::GetFullPath($env:GENARRATIVE_API_SERVER_EXE_TARGET)',
|
|
'$processes = Get-Process -Name api-server -ErrorAction SilentlyContinue | Where-Object {',
|
|
' $_.Path -and ([System.IO.Path]::GetFullPath($_.Path) -ieq $target)',
|
|
'}',
|
|
'foreach ($process in $processes) {',
|
|
' try {',
|
|
' Stop-Process -Id $process.Id -Force -ErrorAction Stop',
|
|
' Wait-Process -Id $process.Id -Timeout 5 -ErrorAction SilentlyContinue',
|
|
' Write-Output $process.Id',
|
|
' } catch {',
|
|
' Write-Error "[api-server] 忽略旧进程清理瞬时失败 pid=$($process.Id): $($_.Exception.Message)"',
|
|
' }',
|
|
'}',
|
|
'exit 0',
|
|
].join('\n');
|
|
|
|
const output = execFileSync(
|
|
'powershell.exe',
|
|
['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', command],
|
|
{
|
|
encoding: 'utf8',
|
|
env: {
|
|
...process.env,
|
|
GENARRATIVE_API_SERVER_EXE_TARGET: apiServerExePath,
|
|
},
|
|
},
|
|
).trim();
|
|
|
|
if (output) {
|
|
console.log(`[api-server] 已停止旧 api-server 进程: ${output}`);
|
|
}
|
|
}
|
|
|
|
try {
|
|
stopExistingWindowsApiServer();
|
|
} catch (error) {
|
|
console.error(
|
|
`[api-server] 清理旧 api-server 进程失败: ${error.message}`,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(
|
|
`[api-server] SpacetimeDB ${mergedEnv.GENARRATIVE_SPACETIME_DATABASE} @ ${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL}`,
|
|
);
|
|
|
|
const child = spawn(
|
|
'cargo',
|
|
['run', '-p', 'api-server', '--manifest-path', 'server-rs/Cargo.toml'],
|
|
{
|
|
cwd: repoRoot,
|
|
env: mergedEnv,
|
|
stdio: 'inherit',
|
|
},
|
|
);
|
|
|
|
child.on('error', (error) => {
|
|
console.error(`[api-server] 启动 cargo 失败: ${error.message}`);
|
|
process.exit(1);
|
|
});
|
|
|
|
child.on('exit', (code, signal) => {
|
|
if (signal) {
|
|
console.error(`[api-server] api-server 被信号终止: ${signal}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
process.exit(code ?? 0);
|
|
});
|