Lumi/src/services/web-upgrades.js
2026-07-22 11:01:49 +02:00

63 lines
1.8 KiB
JavaScript

function createWebUpgradeRegistry() {
const handlers = [];
let attachedServer = null;
function add(pathname, handler) {
const path = normalizePath(pathname);
if (typeof handler !== "function") throw new Error("An upgrade handler is required.");
const entry = { path, handler };
handlers.push(entry);
return () => {
const index = handlers.indexOf(entry);
if (index >= 0) handlers.splice(index, 1);
};
}
function dispatch(request, socket, head) {
let pathname = "/";
try {
pathname = new URL(request.url || "/", "http://lumi.local").pathname;
} catch {}
const entry = handlers.find((candidate) => candidate.path === pathname);
if (!entry) {
socket.write("HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n");
socket.destroy();
return;
}
try {
entry.handler(request, socket, head);
} catch {
if (!socket.destroyed) {
socket.write("HTTP/1.1 500 Internal Server Error\r\nConnection: close\r\n\r\n");
socket.destroy();
}
}
}
function attach(server) {
if (!server || typeof server.on !== "function") throw new Error("An HTTP server is required.");
if (attachedServer === server) return;
if (attachedServer) attachedServer.off("upgrade", dispatch);
attachedServer = server;
server.on("upgrade", dispatch);
}
function close() {
if (attachedServer) attachedServer.off("upgrade", dispatch);
attachedServer = null;
handlers.length = 0;
}
return { add, attach, close, count: () => handlers.length };
}
function normalizePath(value) {
const path = String(value || "").trim();
if (!path.startsWith("/") || path.includes("?") || path.includes("#")) {
throw new Error("Upgrade paths must be absolute URL paths.");
}
return path;
}
module.exports = { createWebUpgradeRegistry };