core/adapters/server.adapter.ts

core/adapters/server.adapter.ts is a file in Bane's Lab Build Scripts. 140 lines of code and 36 definitions.

import {
    commandFailed,
    portHeldLine,
    portReleasedLine,
    probeFailed,
    signalFailed,
} from "#configuration/strings/server.strings";
import { execFileSync } from "node:child_process";
import { isRecord } from "#core/selectors/base.selector";
import process from "node:process";
import { wait } from "#core/timers/base.timer";

const WINDOWS = "win32";
const LISTENING = "LISTENING";
const SYSTEM_PIDS: ReadonlySet<string> = new Set(["0", "4"]);
const RELEASE_ATTEMPTS = 20;
const RELEASE_INTERVAL_MS = 50;

const LOCAL_ADDRESS_COLUMN = 1;
const STATE_COLUMN = 3;
const PID_COLUMN = 4;

const NO_MATCH_STATUS = 1;
const TASK_GONE_STATUS = 128;
const PROCESS_GONE = "ESRCH";

const tokensOf = function tokensOf(line: string): string[] {
    return line
        .split(" ")
        .map((token) => token.trim())
        .filter((token) => token.length > 0);
};

const exitStatusOf = function exitStatusOf(error: unknown): unknown {
    return isRecord(error) ? error["status"] : null;
};

const commandOutput = function commandOutput(
    file: string,
    args: readonly string[],
    quiet: ReadonlySet<number>,
): string {
    try {
        return execFileSync(file, [...args], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
    } catch (error: unknown) {
        const status = exitStatusOf(error);
        if (typeof status === "number" && quiet.has(status)) {
            return "";
        }
        throw new Error(commandFailed(file), { cause: error });
    }
};

const signaled = function signaled(pid: number): boolean {
    try {
        process.kill(pid, "SIGKILL");
        return true;
    } catch (error: unknown) {
        if (isRecord(error) && error["code"] === PROCESS_GONE) {
            return false;
        }
        throw new Error(signalFailed(pid), { cause: error });
    }
};

const windowsHolders = function windowsHolders(port: number): string[] {
    const suffix = `:${String(port)}`;
    const pids = new Set<string>();
    for (const line of commandOutput("netstat", ["-ano", "-p", "TCP"], new Set()).split("\n")) {
        const tokens = tokensOf(line);
        const local = tokens[LOCAL_ADDRESS_COLUMN] ?? "";
        const state = tokens[STATE_COLUMN] ?? "";
        const pid = tokens[PID_COLUMN] ?? "";
        if (local.endsWith(suffix) && state === LISTENING && pid.length > 0 && !SYSTEM_PIDS.has(pid)) {
            pids.add(pid);
        }
    }
    return [...pids];
};

const posixHolders = function posixHolders(port: number): string[] {
    const listed = commandOutput("lsof", ["-ti", `tcp:${String(port)}`, "-sTCP:LISTEN"], new Set([NO_MATCH_STATUS]));
    return [
        ...new Set(
            listed
                .split("\n")
                .map((line) => line.trim())
                .filter((pid) => pid.length > 0 && !SYSTEM_PIDS.has(pid)),
        ),
    ];
};

export const holdersOf = function holdersOf(port: number): string[] {
    return process.platform === WINDOWS ? windowsHolders(port) : posixHolders(port);
};

const alive = function alive(pid: number): boolean {
    try {
        process.kill(pid, 0);
        return true;
    } catch (error: unknown) {
        if (isRecord(error) && error["code"] === PROCESS_GONE) {
            return false;
        }
        throw new Error(probeFailed(pid), { cause: error });
    }
};

const killTaskTree = function killTaskTree(pid: number): boolean {
    try {
        const output = commandOutput("taskkill", ["/PID", String(pid), "/F", "/T"], new Set([TASK_GONE_STATUS]));
        return output.length > 0;
    } catch (error: unknown) {
        if (alive(pid)) {
            throw error;
        }
        return true;
    }
};

export const terminateTree = function terminateTree(pid: number): boolean {
    return process.platform === WINDOWS ? killTaskTree(pid) : signaled(-pid);
};

const terminate = function terminate(pid: string): boolean {
    return process.platform === WINDOWS ? killTaskTree(Number(pid)) : signaled(Number(pid));
};

export const awaitRelease = async function awaitRelease(port: number, attempt = 0): Promise<boolean> {
    if (holdersOf(port).length === 0) {
        return true;
    }
    if (attempt >= RELEASE_ATTEMPTS) {
        return false;
    }
    await wait(RELEASE_INTERVAL_MS);
    return awaitRelease(port, attempt + 1);
};

export const freePort = async function freePort(port: number): Promise<string[]> {
    const held = holdersOf(port);
    if (held.length === 0) {
        return [];
    }
    held.forEach((pid) => {
        terminate(pid);
    });
    const released = await awaitRelease(port);
    const label = held.join(", ");
    if (!released) {
        process.stderr.write(portHeldLine(port, label));
        return held;
    }
    process.stdout.write(portReleasedLine(port, label));
    return held;
};