97 lines
3.1 KiB
JavaScript
97 lines
3.1 KiB
JavaScript
import { createServer } from "node:http";
|
|
import { createReadStream, statSync } from "node:fs";
|
|
import { extname, join, normalize } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const rootDir = fileURLToPath(new URL(".", import.meta.url));
|
|
const port = Number(process.env.INVITE_TEST_PORT || 65248);
|
|
const apiTarget = String(process.env.INVITE_API_TARGET || "http://127.0.0.1:2900").replace(/\/$/, "");
|
|
|
|
const mimeTypes = {
|
|
".html": "text/html; charset=utf-8",
|
|
".js": "text/javascript; charset=utf-8",
|
|
".css": "text/css; charset=utf-8",
|
|
".json": "application/json; charset=utf-8",
|
|
".png": "image/png",
|
|
".jpg": "image/jpeg",
|
|
".jpeg": "image/jpeg",
|
|
".svg": "image/svg+xml",
|
|
};
|
|
|
|
function sendText(response, status, text) {
|
|
response.writeHead(status, { "content-type": "text/plain; charset=utf-8" });
|
|
response.end(text);
|
|
}
|
|
|
|
function serveStatic(request, response) {
|
|
const requestPath = new URL(request.url, "http://localhost").pathname;
|
|
const pathname = requestPath === "/" ? "/dev-test.html" : requestPath;
|
|
const filePath = normalize(join(rootDir, pathname));
|
|
if (!filePath.startsWith(rootDir)) {
|
|
sendText(response, 403, "Forbidden");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const stat = statSync(filePath);
|
|
if (!stat.isFile()) {
|
|
sendText(response, 404, "Not found");
|
|
return;
|
|
}
|
|
response.writeHead(200, {
|
|
"content-type": mimeTypes[extname(filePath)] || "application/octet-stream",
|
|
"content-length": stat.size,
|
|
});
|
|
createReadStream(filePath).pipe(response);
|
|
} catch {
|
|
sendText(response, 404, "Not found");
|
|
}
|
|
}
|
|
|
|
async function proxyAPI(request, response) {
|
|
const incomingURL = new URL(request.url, "http://localhost");
|
|
const targetURL = new URL(incomingURL.pathname.replace(/^\/api/, "") + incomingURL.search, apiTarget);
|
|
const headers = new Headers();
|
|
for (const [key, value] of Object.entries(request.headers)) {
|
|
if (value !== undefined && key.toLowerCase() !== "host") {
|
|
headers.set(key, Array.isArray(value) ? value.join(",") : value);
|
|
}
|
|
}
|
|
|
|
try {
|
|
const upstream = await fetch(targetURL, {
|
|
method: request.method,
|
|
headers,
|
|
body: request.method === "GET" || request.method === "HEAD" ? undefined : request,
|
|
duplex: "half",
|
|
});
|
|
response.writeHead(upstream.status, {
|
|
"content-type": upstream.headers.get("content-type") || "application/octet-stream",
|
|
});
|
|
if (upstream.body) {
|
|
for await (const chunk of upstream.body) {
|
|
response.write(chunk);
|
|
}
|
|
}
|
|
response.end();
|
|
} catch (error) {
|
|
response.writeHead(502, { "content-type": "application/json; charset=utf-8" });
|
|
response.end(JSON.stringify({
|
|
status: false,
|
|
code: "proxy_error",
|
|
message: error instanceof Error ? error.message : "proxy error",
|
|
}));
|
|
}
|
|
}
|
|
|
|
createServer((request, response) => {
|
|
if (request.url?.startsWith("/api/") || request.url === "/api") {
|
|
proxyAPI(request, response);
|
|
return;
|
|
}
|
|
serveStatic(request, response);
|
|
}).listen(port, "127.0.0.1", () => {
|
|
console.log(`Invite dev test page: http://127.0.0.1:${port}/dev-test.html`);
|
|
console.log(`Proxy target: ${apiTarget}`);
|
|
});
|