Files
Genarrative/scripts/api-server-dev.mjs
2026-05-08 22:12:10 +08:00

136 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 };
loadEnvFile(resolve(repoRoot, '.env.secrets.local'), mergedEnv);
loadEnvFile(resolve(repoRoot, '.env.local'), mergedEnv);
loadEnvFile(resolve(repoRoot, '.env'), 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);
});