Files
paperclip/docker/openclaw-smoke/server.mjs

104 lines
2.8 KiB
JavaScript

import http from "node:http";
const port = Number.parseInt(process.env.PORT ?? "8787", 10);
const webhookPath = process.env.OPENCLAW_SMOKE_PATH?.trim() || "/webhook";
const expectedAuthHeader = process.env.OPENCLAW_SMOKE_AUTH?.trim() || "";
const maxBodyBytes = 1_000_000;
const maxEvents = 200;
const events = [];
let nextId = 1;
function writeJson(res, status, payload) {
res.statusCode = status;
res.setHeader("content-type", "application/json; charset=utf-8");
res.end(JSON.stringify(payload));
}
function readBody(req) {
return new Promise((resolve, reject) => {
const chunks = [];
let total = 0;
req.on("data", (chunk) => {
total += chunk.length;
if (total > maxBodyBytes) {
reject(new Error("payload_too_large"));
req.destroy();
return;
}
chunks.push(chunk);
});
req.on("end", () => {
resolve(Buffer.concat(chunks).toString("utf8"));
});
req.on("error", reject);
});
}
function trimEvents() {
if (events.length <= maxEvents) return;
events.splice(0, events.length - maxEvents);
}
const server = http.createServer(async (req, res) => {
const method = req.method ?? "GET";
const url = req.url ?? "/";
if (method === "GET" && url === "/health") {
writeJson(res, 200, { ok: true, webhookPath, events: events.length });
return;
}
if (method === "GET" && url === "/events") {
writeJson(res, 200, { count: events.length, events });
return;
}
if (method === "POST" && url === "/reset") {
events.length = 0;
writeJson(res, 200, { ok: true });
return;
}
if (method === "POST" && url === webhookPath) {
const authorization = req.headers.authorization ?? "";
if (expectedAuthHeader && authorization !== expectedAuthHeader) {
writeJson(res, 401, { error: "unauthorized" });
return;
}
try {
const raw = await readBody(req);
let body = null;
try {
body = raw.length > 0 ? JSON.parse(raw) : null;
} catch {
body = { raw };
}
const event = {
id: `evt-${nextId++}`,
receivedAt: new Date().toISOString(),
method,
path: url,
authorizationPresent: Boolean(authorization),
body,
};
events.push(event);
trimEvents();
writeJson(res, 200, { ok: true, received: true, eventId: event.id, count: events.length });
} catch (err) {
const code = err instanceof Error && err.message === "payload_too_large" ? 413 : 500;
writeJson(res, code, { error: err instanceof Error ? err.message : "unknown_error" });
}
return;
}
writeJson(res, 404, { error: "not_found" });
});
server.listen(port, "0.0.0.0", () => {
// eslint-disable-next-line no-console
console.log(`[openclaw-smoke] listening on :${port} path=${webhookPath}`);
});