52 lines
2.1 KiB
JavaScript
Executable File
52 lines
2.1 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
import fs from "node:fs";
|
|
import { spawn } from "node:child_process";
|
|
|
|
const appPort = 4322;
|
|
const portHex = appPort.toString(16).toUpperCase().padStart(4, "0");
|
|
|
|
function listeningSocketInodes() {
|
|
const inodes = new Set();
|
|
for (const file of ["/proc/net/tcp", "/proc/net/tcp6"]) {
|
|
if (!fs.existsSync(file)) continue;
|
|
for (const line of fs.readFileSync(file, "utf8").trim().split("\n").slice(1)) {
|
|
const columns = line.trim().split(/\s+/);
|
|
const localPort = columns[1]?.split(":").at(-1);
|
|
const state = columns[3];
|
|
const inode = columns[9];
|
|
if (localPort === portHex && state === "0A" && inode) inodes.add(inode);
|
|
}
|
|
}
|
|
return inodes;
|
|
}
|
|
|
|
function listenerPids(inodes) {
|
|
const pids = [];
|
|
for (const entry of fs.readdirSync("/proc").filter((value) => /^\d+$/.test(value))) {
|
|
const directory = `/proc/${entry}/fd`;
|
|
let descriptors;
|
|
try { descriptors = fs.readdirSync(directory); } catch { continue; }
|
|
const ownsSocket = descriptors.some((descriptor) => {
|
|
try {
|
|
const target = fs.readlinkSync(`${directory}/${descriptor}`);
|
|
return [...inodes].some((inode) => target === `socket:[${inode}]`);
|
|
} catch { return false; }
|
|
});
|
|
if (ownsSocket && Number(entry) !== process.pid) pids.push(Number(entry));
|
|
}
|
|
return pids;
|
|
}
|
|
|
|
const delay = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
const alive = (pid) => { try { process.kill(pid, 0); return true; } catch { return false; } };
|
|
|
|
const pids = listenerPids(listeningSocketInodes());
|
|
for (const pid of pids) process.kill(pid, "SIGTERM");
|
|
for (let attempt = 0; attempt < 20 && pids.some(alive); attempt += 1) await delay(100);
|
|
for (const pid of pids.filter(alive)) process.kill(pid, "SIGKILL");
|
|
|
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
const child = spawn(npmCommand, ["run", "dev:app"], { stdio: "inherit" });
|
|
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => child.kill(signal));
|
|
child.on("exit", (code, signal) => process.exit(signal ? 1 : (code ?? 1)));
|