nemoflix-amd-video / server.js
Ciri
Fix Space API proxy reuse
9789592
import Fastify from "fastify";
import fastifyStatic from "@fastify/static";
import { createProxyMiddleware } from "http-proxy-middleware";
import { fileURLToPath } from "node:url";
import path from "node:path";
import fs from "node:fs";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const port = Number(process.env.PORT || 7860);
function normalizeApiUrl(value) {
let url = String(value || "").trim().replace(/\/+$/, "");
if (!url) return "";
if (!/^https?:\/\//i.test(url)) url = `http://${url}`;
const parsed = new URL(url);
if (!parsed.port) parsed.port = "8190";
return parsed.toString().replace(/\/+$/, "");
}
const apiTarget = normalizeApiUrl(process.env.NEMOFLIX_API_URL || process.env.NEMOFLIX_AMD_API_URL || "");
const app = Fastify({ logger: true });
const distDir = path.join(__dirname, "studio", "dist");
const backendProxy = apiTarget
? createProxyMiddleware({
target: apiTarget,
changeOrigin: true,
ws: true,
logLevel: "warn",
timeout: 30_000,
proxyTimeout: 30_000,
on: {
error: (err, _req, res) => {
app.log.error({ err, apiTarget }, "backend proxy error");
if (!res.headersSent) {
res.writeHead(502, { "Content-Type": "application/json" });
}
res.end(JSON.stringify({ detail: `Backend unavailable: ${err.message}` }));
},
},
})
: null;
app.addHook("onRequest", async (request, reply) => {
if (request.url.startsWith("/api/") || request.url === "/api" || request.url.startsWith("/media/") || request.url === "/media") {
if (!backendProxy) {
return reply.code(503).send({ detail: "NEMOFLIX_API_URL is not configured" });
}
await new Promise((resolve, reject) => backendProxy(request.raw, reply.raw, (err) => err ? reject(err) : resolve()));
reply.hijack();
}
});
app.get("/space-health", async () => ({ ok: true, apiConfigured: Boolean(apiTarget), apiTarget: apiTarget || null }));
await app.register(fastifyStatic, { root: distDir, prefix: "/" });
app.setNotFoundHandler((request, reply) => {
const index = path.join(distDir, "index.html");
if (fs.existsSync(index)) return reply.type("text/html").send(fs.createReadStream(index));
return reply.code(404).send("Studio build not found");
});
app.listen({ host: "0.0.0.0", port });