pi-remote-control/extensions/remote-control/server/upgrade.ts

53 lines
1.7 KiB
TypeScript

/**
* WebSocket upgrade routing.
*
* Routes incoming HTTP Upgrade requests to the appropriate WebSocket handler
* based on the request path and session/topic. Non-matching paths are
* destroyed immediately.
*
* Current routes (all LEGACY — browser HTML client):
* /ws → legacy browser client WebSocket endpoint
*
* Future routes (T-1.5):
* /sessions/:id/stream → binary ANSI stream per tmux session
*
* T-1.5 will extend createUpgradeHandler to accept a session registry and
* dispatch to per-session stream handlers.
*/
import type { IncomingMessage } from "node:http";
import type { Socket } from "node:net";
import type { WsClient, WsServer } from "./types.js";
/**
* Create the HTTP `upgrade` event handler.
*
* @param wss - WebSocket server instance.
* @param isAuthenticated - Predicate that checks token/session on the request.
* @returns A handler suitable for `httpServer.on("upgrade", handler)`.
*/
export function createUpgradeHandler(
wss: WsServer,
isAuthenticated: (req: IncomingMessage) => boolean,
): (request: IncomingMessage, socket: Socket, head: Buffer) => void {
return (request: IncomingMessage, socket: Socket, head: Buffer): void => {
const url = new URL(request.url ?? "/", "http://localhost");
if (url.pathname === "/ws") {
// LEGACY: browser HTML client WebSocket endpoint — auth guard
if (!isAuthenticated(request)) {
socket.write("HTTP/1.1 403 Forbidden\r\n\r\n");
socket.destroy();
return;
}
wss.handleUpgrade(request, socket, head, (ws: WsClient) => {
wss.emit("connection", ws, request);
});
return;
}
// Unknown upgrade path — reject
socket.destroy();
};
}