import { app } from "electron"; import fs from "node:fs"; import http, { type Server } from "node:http"; import path from "node:path"; let server: Server | null = null; let currentUrl = ""; function fixtureRoot(): string { const candidates = [ process.resourcesPath ? path.join(process.resourcesPath, "fixture") : "", path.join(app.getAppPath(), "resources", "fixture"), path.join(__dirname, "../../resources/fixture") ].filter(Boolean); const found = candidates.find((candidate) => fs.existsSync(path.join(candidate, "index.html"))); if (!found) throw new Error(`fixture index.html not found; tried ${candidates.join(", ")}`); return found; } export async function startFixtureServer(preferredPort = 17863): Promise { if (server && currentUrl) return currentUrl; const root = fixtureRoot(); server = http.createServer((request, response) => { const url = new URL(request.url || "/", "http://127.0.0.1"); if (url.pathname === "/download.csv") { response.writeHead(200, { "Content-Type": "text/csv; charset=utf-8", "Content-Disposition": "attachment; filename=orders.csv" }); response.end("name,amount,status\r\nRPA,128,created\r\n"); return; } if (url.pathname !== "/" && url.pathname !== "/index.html") { response.writeHead(404).end("Not found"); return; } response.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store" }); fs.createReadStream(path.join(root, "index.html")).pipe(response); }); const attempts = preferredPort === 0 ? [0] : Array.from({ length: 10 }, (_, index) => preferredPort + index); for (const port of attempts) { try { await new Promise((resolve, reject) => { const onError = (error: Error) => { server?.removeListener("listening", onListening); reject(error); }; const onListening = () => { server?.removeListener("error", onError); resolve(); }; server!.once("error", onError); server!.once("listening", onListening); server!.listen(port, "127.0.0.1"); }); const address = server.address(); const activePort = typeof address === "object" && address ? address.port : port; currentUrl = `http://127.0.0.1:${activePort}/`; return currentUrl; } catch (error) { if ((error as NodeJS.ErrnoException).code !== "EADDRINUSE") throw error; } } throw new Error("无法启动本地演示站:17863-17872 端口均被占用"); } export async function stopFixtureServer(): Promise { const active = server; server = null; currentUrl = ""; if (!active) return; await new Promise((resolve) => active.close(() => resolve())); } export function fixtureUrl(): string { return currentUrl; }