76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import { statSync } from "node:fs";
|
|
import { resolve } from "node:path";
|
|
|
|
const root = process.cwd();
|
|
const watchedFiles = [
|
|
resolve(root, "scripts/caserun-native-server.ts"),
|
|
resolve(root, "scripts/caserun-native-fixtures.ts")
|
|
];
|
|
|
|
let child: ReturnType<typeof spawnNativeServer> | null = null;
|
|
let signature = sourceSignature();
|
|
let stopping = false;
|
|
let restarting = false;
|
|
|
|
function sourceSignature(): string | null {
|
|
try {
|
|
return watchedFiles.map((path) => {
|
|
const source = statSync(path);
|
|
return `${path}:${source.mtimeMs}:${source.size}`;
|
|
}).join("|");
|
|
} catch (error) {
|
|
if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
function startChild(reason: string): void {
|
|
const spawned = spawnNativeServer();
|
|
child = spawned;
|
|
console.log(JSON.stringify({ event: "caserun-native-reload", mode: "native-test", reason, pid: spawned.pid }));
|
|
void spawned.exited.then((exitCode) => {
|
|
if (!stopping && child === spawned) console.log(JSON.stringify({ event: "caserun-native-exit", exitCode }));
|
|
});
|
|
}
|
|
|
|
function spawnNativeServer() {
|
|
return Bun.spawn([process.execPath, "scripts/caserun-native-server.ts"], { cwd: root, stdin: "ignore", stdout: "inherit", stderr: "inherit" });
|
|
}
|
|
|
|
async function stopChild(): Promise<void> {
|
|
const runningChild = child;
|
|
if (!runningChild) return;
|
|
if (runningChild.exitCode === null) runningChild.kill("SIGTERM");
|
|
await runningChild.exited;
|
|
if (child === runningChild) child = null;
|
|
}
|
|
|
|
startChild("initial");
|
|
|
|
async function reloadIfChanged(): Promise<void> {
|
|
if (stopping || restarting) return;
|
|
const nextSignature = sourceSignature();
|
|
if (nextSignature === null || nextSignature === signature) return;
|
|
signature = nextSignature;
|
|
restarting = true;
|
|
try {
|
|
await stopChild();
|
|
if (!stopping) startChild("source-change");
|
|
} finally {
|
|
restarting = false;
|
|
}
|
|
}
|
|
|
|
const timer = setInterval(() => void reloadIfChanged(), 100);
|
|
|
|
async function shutdown(): Promise<void> {
|
|
if (stopping) return;
|
|
stopping = true;
|
|
clearInterval(timer);
|
|
await stopChild();
|
|
process.exit(0);
|
|
}
|
|
|
|
process.on("SIGINT", () => void shutdown());
|
|
process.on("SIGTERM", () => void shutdown());
|