import { createServer, type Server as HttpServer } from "node:http"; import { type WebSocket, WebSocketServer } from "ws"; import { handleHealth } from "../../src/health/health.js"; import type { Handshake, WsServerFactory, WsServerLike, WsServerStartOptions, WsServerStartResult, WsSocketLike, } from "../../src/types/types.js"; /** * Production-grade `WsServerLike` implementation backed by the real * `ws` package and a Node `http.Server`. The HTTP server also routes * `/health` / `/ready` / `/live` probes through the daemon's snapshot * so the integration test can hit those endpoints from the same port. */ export class RealWsServer implements WsServerLike { #http: HttpServer | undefined; #wss: WebSocketServer | undefined; readonly #sockets = new Map< string, { socket: WebSocket; like: WsSocketLike } >(); readonly #snapshot: () => { running: boolean; disposed: boolean; clientCount: number; roomCount: number; startedAt: number | undefined; }; #nextId = 0; public constructor( snapshot: () => { running: boolean; disposed: boolean; clientCount: number; roomCount: number; startedAt: number | undefined; } ) { this.#snapshot = snapshot; } public async start( opts: WsServerStartOptions ): Promise { const http = createServer((req, res) => { const handled = handleHealth(req.url, this.#snapshot()); if (handled) { res.writeHead(handled.status, { "content-type": "application/json", }); res.end(handled.body); return; } res.writeHead(404, { "content-type": "text/plain" }); res.end("not found"); }); const wss = new WebSocketServer({ server: http }); wss.on("connection", (socket, request) => { const id = `wsc-${++this.#nextId}`; const url = request.url ?? "/"; const q = new URL(url, "http://x").searchParams; const handshake: Handshake = { headers: Object.fromEntries( Object.entries(request.headers).map(([k, v]) => [ k, Array.isArray(v) ? v.join(",") : v, ]) ), remoteAddress: request.socket.remoteAddress, url, query: Object.fromEntries(q.entries()), }; const like: WsSocketLike = { id, remoteAddress: request.socket.remoteAddress, send: (payload) => { if (socket.readyState === socket.OPEN) socket.send(payload); }, close: (code, reason) => socket.close(code, reason), }; this.#sockets.set(id, { socket, like }); opts.callbacks.onConnection(like, handshake); socket.on("message", (data) => opts.callbacks.onMessage(id, data.toString()) ); socket.on("close", (code, reason) => { this.#sockets.delete(id); opts.callbacks.onClose(id, code, reason.toString()); }); socket.on("error", (err) => opts.callbacks.onError(id, err)); }); await new Promise((resolve, reject) => { const onErr = (err: Error): void => reject(err); http.once("error", onErr); http.listen(opts.port, opts.host, () => { http.removeListener("error", onErr); resolve(); }); }); this.#http = http; this.#wss = wss; const addr = http.address() as { address: string; port: number }; return { address: addr.address, port: addr.port }; } public async stop(): Promise { await new Promise((resolve) => { this.#wss?.close(() => resolve()); }); await new Promise((resolve) => { const http = this.#http; if (!http) { resolve(); return; } http.close(() => resolve()); }); } public async closeAll(code = 1001, reason = "shutdown"): Promise { for (const { socket } of this.#sockets.values()) socket.close(code, reason); } } /** Build a real-ws factory bound to a snapshot accessor. */ export function makeRealWsServerFactory( snapshot: () => { running: boolean; disposed: boolean; clientCount: number; roomCount: number; startedAt: number | undefined; } ): WsServerFactory { return () => new RealWsServer(snapshot); }