fix: add dev artifact entrypoints
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
import { createServer, request as httpRequest } from "node:http";
|
||||
|
||||
import { DEV_ENDPOINT, ENVIRONMENT_DEV } from "../protocol/index.mjs";
|
||||
|
||||
export function parsePort(value, fallback) {
|
||||
const parsed = Number.parseInt(value ?? "", 10);
|
||||
if (Number.isInteger(parsed) && parsed > 0 && parsed < 65536) {
|
||||
return parsed;
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
export function resolveHostPort({ listenEnv, hostEnv, portEnv, fallbackPort }) {
|
||||
const listen = process.env[listenEnv] ?? "";
|
||||
const [listenHost, listenPort] = listen.includes(":") ? listen.split(":") : ["", listen];
|
||||
const host = process.env[hostEnv] || listenHost || "0.0.0.0";
|
||||
const port = parsePort(process.env[portEnv] || listenPort, fallbackPort);
|
||||
return { host, port };
|
||||
}
|
||||
|
||||
export function healthPayload({ serviceId, role, details = {} }) {
|
||||
const commitId = process.env.HWLAB_COMMIT_ID || process.env.HWLAB_GIT_SHA || "unknown";
|
||||
const imageReference = process.env.HWLAB_IMAGE || `ghcr.io/pikastech/${serviceId}:${commitId.slice(0, 7) || "unknown"}`;
|
||||
const imageTag = process.env.HWLAB_IMAGE_TAG || commitId.slice(0, 7) || "unknown";
|
||||
|
||||
return {
|
||||
serviceId,
|
||||
environment: ENVIRONMENT_DEV,
|
||||
status: "ok",
|
||||
service: {
|
||||
id: serviceId,
|
||||
role,
|
||||
healthPath: "/health",
|
||||
livePath: "/health/live"
|
||||
},
|
||||
commit: {
|
||||
id: commitId,
|
||||
source: process.env.HWLAB_BUILD_SOURCE || "runtime-env"
|
||||
},
|
||||
image: {
|
||||
reference: imageReference,
|
||||
tag: imageTag,
|
||||
digest: process.env.HWLAB_IMAGE_DIGEST || "unknown"
|
||||
},
|
||||
endpoint: process.env.HWLAB_PUBLIC_ENDPOINT || DEV_ENDPOINT,
|
||||
observedAt: new Date().toISOString(),
|
||||
details
|
||||
};
|
||||
}
|
||||
|
||||
export function sendJson(response, statusCode, body) {
|
||||
const payload = JSON.stringify(body, null, 2);
|
||||
response.writeHead(statusCode, {
|
||||
"content-type": "application/json; charset=utf-8",
|
||||
"content-length": Buffer.byteLength(payload)
|
||||
});
|
||||
response.end(payload);
|
||||
}
|
||||
|
||||
export function createServiceServer({ serviceId, role, routes = new Map(), details = () => ({}) }) {
|
||||
return createServer(async (request, response) => {
|
||||
try {
|
||||
const url = new URL(request.url || "/", `http://${serviceId}.local`);
|
||||
if (request.method === "GET" && (url.pathname === "/health" || url.pathname === "/health/live")) {
|
||||
sendJson(response, 200, healthPayload({ serviceId, role, details: details() }));
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method === "GET" && url.pathname === "/help") {
|
||||
sendJson(response, 200, {
|
||||
serviceId,
|
||||
commands: ["GET /health", "GET /health/live", ...routes.keys()]
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const handler = routes.get(`${request.method ?? "GET"} ${url.pathname}`);
|
||||
if (!handler) {
|
||||
sendJson(response, 404, { error: "not_found", serviceId, path: url.pathname });
|
||||
return;
|
||||
}
|
||||
|
||||
sendJson(response, 200, await handler({ request, url }));
|
||||
} catch (error) {
|
||||
sendJson(response, 500, {
|
||||
error: "internal_error",
|
||||
serviceId,
|
||||
message: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function listen(server, { serviceId, host, port }) {
|
||||
server.listen(port, host, () => {
|
||||
process.stdout.write(`${JSON.stringify({ serviceId, status: "listening", host, port })}\n`);
|
||||
});
|
||||
|
||||
for (const signal of ["SIGINT", "SIGTERM"]) {
|
||||
process.on(signal, () => {
|
||||
server.close(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function proxyHttpRequest({ request, response, upstream }) {
|
||||
const target = new URL(request.url || "/", upstream);
|
||||
const proxy = httpRequest(
|
||||
target,
|
||||
{
|
||||
method: request.method,
|
||||
headers: {
|
||||
...request.headers,
|
||||
host: target.host
|
||||
}
|
||||
},
|
||||
(upstreamResponse) => {
|
||||
response.writeHead(upstreamResponse.statusCode ?? 502, upstreamResponse.headers);
|
||||
upstreamResponse.pipe(response);
|
||||
}
|
||||
);
|
||||
|
||||
proxy.on("error", (error) => {
|
||||
sendJson(response, 502, {
|
||||
error: "upstream_unavailable",
|
||||
upstream,
|
||||
message: error.message
|
||||
});
|
||||
});
|
||||
|
||||
request.pipe(proxy);
|
||||
}
|
||||
Reference in New Issue
Block a user