full sync
This commit is contained in:
153
scripts/serverctl.js
Normal file
153
scripts/serverctl.js
Normal file
@@ -0,0 +1,153 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { spawn } = require("child_process");
|
||||
|
||||
const ROOT = path.join(__dirname, "..");
|
||||
const DATA_DIR = path.join(ROOT, "data");
|
||||
const LOG_DIR = path.join(ROOT, "logs");
|
||||
const PID_FILE = path.join(DATA_DIR, "server.pid");
|
||||
const OUT_LOG = path.join(LOG_DIR, "server.out.log");
|
||||
const ERR_LOG = path.join(LOG_DIR, "server.err.log");
|
||||
|
||||
fs.mkdirSync(DATA_DIR, { recursive: true });
|
||||
fs.mkdirSync(LOG_DIR, { recursive: true });
|
||||
|
||||
const command = process.argv[2] || "status";
|
||||
|
||||
if (command === "start") {
|
||||
start();
|
||||
} else if (command === "stop") {
|
||||
stop();
|
||||
} else if (command === "restart") {
|
||||
restart();
|
||||
} else if (command === "status") {
|
||||
status();
|
||||
} else {
|
||||
console.error(`Unknown command: ${command}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function start() {
|
||||
const pid = readPid();
|
||||
if (pid && isRunning(pid)) {
|
||||
console.log(`Live Event server already running with PID ${pid}`);
|
||||
console.log(`Logs: ${OUT_LOG}`);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanupStalePid();
|
||||
|
||||
const stdoutFd = fs.openSync(OUT_LOG, "a");
|
||||
const stderrFd = fs.openSync(ERR_LOG, "a");
|
||||
const child = spawn(process.execPath, ["server.js"], {
|
||||
cwd: ROOT,
|
||||
detached: true,
|
||||
windowsHide: true,
|
||||
stdio: ["ignore", stdoutFd, stderrFd],
|
||||
env: {
|
||||
...process.env,
|
||||
RC_TIMING_PID_FILE: PID_FILE,
|
||||
},
|
||||
});
|
||||
|
||||
child.unref();
|
||||
fs.writeFileSync(PID_FILE, `${child.pid}\n`);
|
||||
|
||||
console.log(`Live Event server started in background`);
|
||||
console.log(`PID: ${child.pid}`);
|
||||
console.log(`Logs: ${OUT_LOG}`);
|
||||
}
|
||||
|
||||
async function stop() {
|
||||
const pid = readPid();
|
||||
if (!pid) {
|
||||
console.log("Live Event server is not running");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isRunning(pid)) {
|
||||
cleanupStalePid();
|
||||
console.log("Removed stale pid file");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
process.kill(pid, "SIGTERM");
|
||||
} catch (error) {
|
||||
console.error(`Could not stop PID ${pid}: ${error instanceof Error ? error.message : String(error)}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const stopped = await waitForExit(pid, 5000);
|
||||
if (!stopped && process.platform !== "win32") {
|
||||
try {
|
||||
process.kill(pid, "SIGKILL");
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
await waitForExit(pid, 1000);
|
||||
}
|
||||
|
||||
cleanupStalePid();
|
||||
console.log(`Live Event server stopped`);
|
||||
}
|
||||
|
||||
async function restart() {
|
||||
await stop();
|
||||
start();
|
||||
}
|
||||
|
||||
function status() {
|
||||
const pid = readPid();
|
||||
if (pid && isRunning(pid)) {
|
||||
console.log(`Live Event server is running`);
|
||||
console.log(`PID: ${pid}`);
|
||||
console.log(`Logs: ${OUT_LOG}`);
|
||||
return;
|
||||
}
|
||||
|
||||
cleanupStalePid();
|
||||
console.log("Live Event server is not running");
|
||||
}
|
||||
|
||||
function readPid() {
|
||||
if (!fs.existsSync(PID_FILE)) {
|
||||
return null;
|
||||
}
|
||||
const raw = fs.readFileSync(PID_FILE, "utf8").trim();
|
||||
const pid = Number(raw);
|
||||
return Number.isFinite(pid) && pid > 0 ? pid : null;
|
||||
}
|
||||
|
||||
function isRunning(pid) {
|
||||
try {
|
||||
process.kill(pid, 0);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function cleanupStalePid() {
|
||||
const pid = readPid();
|
||||
if (!pid || !isRunning(pid)) {
|
||||
fs.rmSync(PID_FILE, { force: true });
|
||||
}
|
||||
}
|
||||
|
||||
function waitForExit(pid, timeoutMs) {
|
||||
return new Promise((resolve) => {
|
||||
const started = Date.now();
|
||||
const timer = setInterval(() => {
|
||||
if (!isRunning(pid)) {
|
||||
clearInterval(timer);
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
if (Date.now() - started >= timeoutMs) {
|
||||
clearInterval(timer);
|
||||
resolve(false);
|
||||
}
|
||||
}, 150);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user