67 lines
2.3 KiB
JavaScript
67 lines
2.3 KiB
JavaScript
/* Local dev server: serves ./site and proxies /ws to the relay, so the pages
|
|
run same-origin exactly like they do behind nginx in production.
|
|
|
|
Usage:
|
|
OBSERVER_TOKEN=test cargo run # in relay/, terminal 1
|
|
node devserver.mjs # terminal 2 -> http://localhost:8080
|
|
Env: PORT (default 8080), RELAY (default 127.0.0.1:8770). */
|
|
|
|
import { createServer } from "node:http";
|
|
import { connect } from "node:net";
|
|
import { readFile } from "node:fs/promises";
|
|
import { extname, join, normalize } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const PORT = Number(process.env.PORT || 8080);
|
|
const [RELAY_HOST, RELAY_PORT] = (process.env.RELAY || "127.0.0.1:8770").split(":");
|
|
const SITE = join(fileURLToPath(new URL(".", import.meta.url)), "site");
|
|
|
|
const MIME = {
|
|
".html": "text/html; charset=utf-8",
|
|
".css": "text/css; charset=utf-8",
|
|
".js": "text/javascript; charset=utf-8",
|
|
".mp3": "audio/mpeg",
|
|
".wav": "audio/wav",
|
|
};
|
|
|
|
const server = createServer(async (req, res) => {
|
|
let path = decodeURIComponent(req.url.split("?")[0]);
|
|
if (path === "/") path = "/clock.html";
|
|
if (path === "/control") path = "/control.html";
|
|
|
|
// keep it inside SITE
|
|
const file = join(SITE, normalize(path));
|
|
if (!file.startsWith(SITE)) {
|
|
res.writeHead(403).end("forbidden");
|
|
return;
|
|
}
|
|
try {
|
|
const body = await readFile(file);
|
|
res.writeHead(200, { "content-type": MIME[extname(file)] || "application/octet-stream" });
|
|
res.end(body);
|
|
} catch {
|
|
res.writeHead(404).end("not found");
|
|
}
|
|
});
|
|
|
|
// Proxy the WebSocket upgrade straight through to the relay.
|
|
server.on("upgrade", (req, socket, head) => {
|
|
const upstream = connect(Number(RELAY_PORT), RELAY_HOST, () => {
|
|
const lines = [`${req.method} ${req.url} HTTP/1.1`];
|
|
for (let i = 0; i < req.rawHeaders.length; i += 2) {
|
|
lines.push(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}`);
|
|
}
|
|
upstream.write(lines.join("\r\n") + "\r\n\r\n");
|
|
if (head && head.length) upstream.write(head);
|
|
socket.pipe(upstream);
|
|
upstream.pipe(socket);
|
|
});
|
|
const bail = () => socket.destroy();
|
|
upstream.on("error", bail);
|
|
socket.on("error", () => upstream.destroy());
|
|
});
|
|
|
|
server.listen(PORT, () => {
|
|
console.log(`observer-effect dev server: http://localhost:${PORT}/ (control: /control)`);
|
|
console.log(`proxying /ws -> ${RELAY_HOST}:${RELAY_PORT}`);
|
|
});
|