63 lines
2.3 KiB
JavaScript
63 lines
2.3 KiB
JavaScript
import { createReadStream, existsSync, statSync } from "node:fs";
|
|
import { createServer } from "node:http";
|
|
import { extname, resolve, sep } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { createGameApiHandler } from "./game-api.mjs";
|
|
|
|
const distPath = fileURLToPath(new URL("../dist", import.meta.url));
|
|
const indexPath = resolve(distPath, "index.html");
|
|
const host = process.env.HOST ?? "127.0.0.1";
|
|
const port = Number(process.env.PORT ?? 4173);
|
|
const contentTypes = {
|
|
".css": "text/css; charset=utf-8",
|
|
".glb": "model/gltf-binary",
|
|
".html": "text/html; charset=utf-8",
|
|
".ico": "image/x-icon",
|
|
".jpeg": "image/jpeg",
|
|
".jpg": "image/jpeg",
|
|
".js": "text/javascript; charset=utf-8",
|
|
".json": "application/json; charset=utf-8",
|
|
".png": "image/png",
|
|
".svg": "image/svg+xml",
|
|
".webp": "image/webp",
|
|
};
|
|
|
|
function sendFile(response, filePath) {
|
|
response.statusCode = 200;
|
|
response.setHeader("Content-Type", contentTypes[extname(filePath).toLowerCase()] ?? "application/octet-stream");
|
|
response.setHeader("X-Content-Type-Options", "nosniff");
|
|
response.setHeader("Referrer-Policy", "same-origin");
|
|
response.setHeader("X-Frame-Options", "DENY");
|
|
createReadStream(filePath).pipe(response);
|
|
}
|
|
|
|
function serveStatic(request, response) {
|
|
let requestPath;
|
|
try { requestPath = decodeURIComponent(new URL(request.url, "http://localhost").pathname); }
|
|
catch { response.statusCode = 400; return response.end("Bad request"); }
|
|
const candidate = resolve(distPath, `.${requestPath}`);
|
|
const insideDist = candidate === distPath || candidate.startsWith(`${distPath}${sep}`);
|
|
if (insideDist && existsSync(candidate) && statSync(candidate).isFile()) return sendFile(response, candidate);
|
|
if (!existsSync(indexPath)) {
|
|
response.statusCode = 503;
|
|
return response.end("Build missing. Run pnpm build.");
|
|
}
|
|
return sendFile(response, indexPath);
|
|
}
|
|
|
|
const api = createGameApiHandler();
|
|
const server = createServer((request, response) => {
|
|
void api.handle(request, response, () => serveStatic(request, response));
|
|
});
|
|
|
|
server.listen(port, host, () => console.log(`I Want To Heal listening on http://${host}:${port}`));
|
|
|
|
function shutdown() {
|
|
server.close(() => {
|
|
api.close();
|
|
process.exit(0);
|
|
});
|
|
}
|
|
process.on("SIGINT", shutdown);
|
|
process.on("SIGTERM", shutdown);
|