@gguf/claw
Version:
WhatsApp gateway CLI (Baileys web) with Pi RPC agent
96 lines (94 loc) • 3.14 kB
JavaScript
import { _ as sleep } from "./utils-DX85MiPR.js";
import { p as resolveLsofCommandSync } from "./errors-CZ9opC6L.js";
import { execFileSync } from "node:child_process";
//#region src/cli/ports.ts
function parseLsofOutput(output) {
const lines = output.split(/\r?\n/).filter(Boolean);
const results = [];
let current = {};
for (const line of lines) if (line.startsWith("p")) {
if (current.pid) results.push(current);
current = { pid: Number.parseInt(line.slice(1), 10) };
} else if (line.startsWith("c")) current.command = line.slice(1);
if (current.pid) results.push(current);
return results;
}
function listPortListeners(port) {
try {
return parseLsofOutput(execFileSync(resolveLsofCommandSync(), [
"-nP",
`-iTCP:${port}`,
"-sTCP:LISTEN",
"-FpFc"
], { encoding: "utf-8" }));
} catch (err) {
const status = err.status;
if (err.code === "ENOENT") throw new Error("lsof not found; required for --force", { cause: err });
if (status === 1) return [];
throw err instanceof Error ? err : new Error(String(err));
}
}
function forceFreePort(port) {
const listeners = listPortListeners(port);
for (const proc of listeners) try {
process.kill(proc.pid, "SIGTERM");
} catch (err) {
throw new Error(`failed to kill pid ${proc.pid}${proc.command ? ` (${proc.command})` : ""}: ${String(err)}`, { cause: err });
}
return listeners;
}
function killPids(listeners, signal) {
for (const proc of listeners) try {
process.kill(proc.pid, signal);
} catch (err) {
throw new Error(`failed to kill pid ${proc.pid}${proc.command ? ` (${proc.command})` : ""}: ${String(err)}`, { cause: err });
}
}
async function forceFreePortAndWait(port, opts = {}) {
const timeoutMs = Math.max(opts.timeoutMs ?? 1500, 0);
const intervalMs = Math.max(opts.intervalMs ?? 100, 1);
const sigtermTimeoutMs = Math.min(Math.max(opts.sigtermTimeoutMs ?? 600, 0), timeoutMs);
const killed = forceFreePort(port);
if (killed.length === 0) return {
killed,
waitedMs: 0,
escalatedToSigkill: false
};
let waitedMs = 0;
const triesSigterm = intervalMs > 0 ? Math.ceil(sigtermTimeoutMs / intervalMs) : 0;
for (let i = 0; i < triesSigterm; i++) {
if (listPortListeners(port).length === 0) return {
killed,
waitedMs,
escalatedToSigkill: false
};
await sleep(intervalMs);
waitedMs += intervalMs;
}
if (listPortListeners(port).length === 0) return {
killed,
waitedMs,
escalatedToSigkill: false
};
killPids(listPortListeners(port), "SIGKILL");
const remainingBudget = Math.max(timeoutMs - waitedMs, 0);
const triesSigkill = intervalMs > 0 ? Math.ceil(remainingBudget / intervalMs) : 0;
for (let i = 0; i < triesSigkill; i++) {
if (listPortListeners(port).length === 0) return {
killed,
waitedMs,
escalatedToSigkill: true
};
await sleep(intervalMs);
waitedMs += intervalMs;
}
const still = listPortListeners(port);
if (still.length === 0) return {
killed,
waitedMs,
escalatedToSigkill: true
};
throw new Error(`port ${port} still has listeners after --force: ${still.map((p) => p.pid).join(", ")}`);
}
//#endregion
export { forceFreePortAndWait as n, forceFreePort as t };