63 lines
1.8 KiB
JavaScript
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 };
|