108 lines
3.1 KiB
JavaScript
108 lines
3.1 KiB
JavaScript
import { spawn } from 'node:child_process';
|
|
import { existsSync, mkdirSync, readFileSync } from 'node:fs';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const rootDir = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
const runtimeDir = join(rootDir, 'runtime', 'nianxx-play');
|
|
const serverPath = join(runtimeDir, 'server.js');
|
|
|
|
function parseEnvValue(raw) {
|
|
const value = raw.trim();
|
|
if (
|
|
(value.startsWith('"') && value.endsWith('"')) ||
|
|
(value.startsWith("'") && value.endsWith("'"))
|
|
) {
|
|
try {
|
|
return JSON.parse(value);
|
|
} catch {
|
|
return value.slice(1, -1);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function parseEnvFile(filePath) {
|
|
if (!existsSync(filePath)) return {};
|
|
const env = {};
|
|
const raw = readFileSync(filePath, 'utf8');
|
|
for (const line of raw.split(/\r?\n/)) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
const match = trimmed.match(/^(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)=(.*)$/);
|
|
if (!match) continue;
|
|
env[match[1]] = parseEnvValue(match[2]);
|
|
}
|
|
return env;
|
|
}
|
|
|
|
function loadEnv() {
|
|
const envFiles = [
|
|
join(rootDir, '.env'),
|
|
join(rootDir, '.env.local'),
|
|
];
|
|
if (process.env.NIANXXPLAY_LOAD_BUNDLED_ENV === '1') {
|
|
envFiles.push(join(runtimeDir, '.env.runtime'));
|
|
}
|
|
|
|
const fileEnv = {};
|
|
for (const file of envFiles) {
|
|
Object.assign(fileEnv, parseEnvFile(file));
|
|
}
|
|
return { ...fileEnv, ...process.env };
|
|
}
|
|
|
|
if (!existsSync(serverPath)) {
|
|
console.error(`Zhinian Creation Assistant runtime entry not found: ${serverPath}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const baseEnv = loadEnv();
|
|
const port = baseEnv.PORT || baseEnv.NIANXX_PLAY_PORT || '3000';
|
|
const hostname = baseEnv.HOSTNAME || '127.0.0.1';
|
|
const runtimeRoot = baseEnv.NIANXXPLAY_RUNTIME_DIR || join(rootDir, '.runtime');
|
|
const dataDir = baseEnv.NIANXXPLAY_DATA_DIR || join(runtimeRoot, 'data');
|
|
const uploadDir = baseEnv.NIANXXPLAY_UPLOAD_DIR || join(runtimeRoot, 'uploads');
|
|
const resultDir = baseEnv.NIANXXPLAY_RESULT_DIR || join(runtimeRoot, 'generated-results');
|
|
|
|
mkdirSync(dataDir, { recursive: true });
|
|
mkdirSync(uploadDir, { recursive: true });
|
|
mkdirSync(resultDir, { recursive: true });
|
|
|
|
const env = {
|
|
...baseEnv,
|
|
PORT: String(port),
|
|
HOSTNAME: hostname,
|
|
NODE_ENV: 'production',
|
|
NEXT_TELEMETRY_DISABLED: '1',
|
|
NIANXXPLAY_RUNTIME_DIR: runtimeRoot,
|
|
NIANXXPLAY_DATA_DIR: dataDir,
|
|
NIANXXPLAY_UPLOAD_DIR: uploadDir,
|
|
NIANXXPLAY_RESULT_DIR: resultDir,
|
|
NIANXXPLAY_PUBLIC_BASE_URL: baseEnv.NIANXXPLAY_PUBLIC_BASE_URL || `http://${hostname}:${port}`,
|
|
NIANXXPLAY_DESKTOP_MANAGED: '1',
|
|
};
|
|
|
|
console.log(`[Zhinian Creation Assistant] Starting on http://${hostname}:${port}`);
|
|
console.log(`[Zhinian Creation Assistant] Runtime data: ${runtimeRoot}`);
|
|
|
|
const child = spawn(process.execPath, [serverPath], {
|
|
cwd: runtimeDir,
|
|
env,
|
|
stdio: 'inherit',
|
|
});
|
|
|
|
function stop(signal) {
|
|
if (!child.killed) child.kill(signal);
|
|
}
|
|
|
|
process.on('SIGINT', () => stop('SIGINT'));
|
|
process.on('SIGTERM', () => stop('SIGTERM'));
|
|
|
|
child.on('exit', (code, signal) => {
|
|
if (signal) {
|
|
process.exit(0);
|
|
}
|
|
process.exit(code ?? 0);
|
|
});
|