70 lines
2.7 KiB
TypeScript
70 lines
2.7 KiB
TypeScript
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<string> {
|
||
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<void>((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<void> {
|
||
const active = server;
|
||
server = null;
|
||
currentUrl = "";
|
||
if (!active) return;
|
||
await new Promise<void>((resolve) => active.close(() => resolve()));
|
||
}
|
||
|
||
export function fixtureUrl(): string {
|
||
return currentUrl;
|
||
}
|