52 lines
2.7 KiB
JavaScript
52 lines
2.7 KiB
JavaScript
import { createServer } from 'node:http';
|
|
import { createReadStream } from 'node:fs';
|
|
import { readFile, stat } from 'node:fs/promises';
|
|
import { pipeline } from 'node:stream/promises';
|
|
import { pathToFileURL } from 'node:url';
|
|
import path from 'node:path';
|
|
import { output } from './suite.mjs';
|
|
|
|
// A local-only source server; only the two indexes and package files are exposed.
|
|
export async function serve(port = 0) {
|
|
let base;
|
|
const server = createServer(async (request, response) => {
|
|
try {
|
|
if (request.method !== 'GET' && request.method !== 'HEAD') { response.writeHead(405).end(); return; }
|
|
const pathname = new URL(request.url, 'http://localhost').pathname;
|
|
if (['/index.json', '/faults-index.json'].includes(pathname)) {
|
|
const index = JSON.parse(await readFile(path.join(output, pathname.slice(1)), 'utf8'));
|
|
for (const curio of index.curios) for (const version of curio.versions) for (const artifact of version.artifacts) {
|
|
artifact.url = `${base}/packages/${encodeURIComponent(path.basename(new URL(artifact.url).pathname))}`;
|
|
}
|
|
const body = JSON.stringify(index);
|
|
response.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8', 'Content-Length': Buffer.byteLength(body), 'Cache-Control': 'no-store' });
|
|
response.end(request.method === 'HEAD' ? undefined : body);
|
|
} else if (/^\/packages\/[a-z0-9][a-z0-9.+-]*\.curio$/.test(pathname)) {
|
|
const file = path.join(output, pathname.slice(1));
|
|
const metadata = await stat(file);
|
|
response.writeHead(200, { 'Content-Type': 'application/octet-stream', 'Content-Length': metadata.size });
|
|
if (request.method === 'HEAD') response.end();
|
|
else await pipeline(createReadStream(file), response);
|
|
} else { response.writeHead(404).end(); }
|
|
} catch (error) {
|
|
if (!response.headersSent) response.writeHead(error.code === 'ENOENT' ? 404 : 500);
|
|
response.end();
|
|
}
|
|
});
|
|
await new Promise((resolve, reject) => {
|
|
server.once('error', reject);
|
|
server.listen(port, '127.0.0.1', resolve);
|
|
});
|
|
base = `http://127.0.0.1:${server.address().port}`;
|
|
return { base, close: () => new Promise(resolve => server.close(resolve)) };
|
|
}
|
|
|
|
if (process.argv[1] && import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href) {
|
|
const port = Number(process.env.QA_HTTP_PORT || 8765);
|
|
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new Error('QA_HTTP_PORT must be 1..65535');
|
|
const server = await serve(port);
|
|
console.log(`常规 HTTP 源:${server.base}/index.json\n故障 HTTP 源:${server.base}/faults-index.json\nCtrl-C 停止服务。`);
|
|
process.once('SIGINT', () => { void server.close(); });
|
|
process.once('SIGTERM', () => { void server.close(); });
|
|
}
|