/** * Unified entry point for Dirigent services. * * Routes: * /no-reply/* → no-reply API (strips /no-reply prefix) * /moderator/* → moderator bot service (strips /moderator prefix) * otherwise → 404 * * Env vars: * SERVICES_PORT (default 8787) * MODERATOR_TOKEN Discord bot token (required for moderator) * PLUGIN_API_URL (default http://127.0.0.1:18789) * PLUGIN_API_TOKEN auth token for plugin API calls * SCHEDULE_IDENTIFIER (default ➡️) * DEBUG_MODE (default false) */ import http from "node:http"; import { createNoReplyHandler } from "./no-reply-api/server.mjs"; import { createModeratorService } from "./moderator/index.mjs"; const PORT = Number(process.env.SERVICES_PORT || 8787); const MODERATOR_TOKEN = process.env.MODERATOR_TOKEN || ""; const PLUGIN_API_URL = process.env.PLUGIN_API_URL || "http://127.0.0.1:18789"; const PLUGIN_API_TOKEN = process.env.PLUGIN_API_TOKEN || ""; const SCHEDULE_IDENTIFIER = process.env.SCHEDULE_IDENTIFIER || "➡️"; const DEBUG_MODE = process.env.DEBUG_MODE === "true" || process.env.DEBUG_MODE === "1"; function sendJson(res, status, payload) { res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" }); res.end(JSON.stringify(payload)); } // ── Initialize services ──────────────────────────────────────────────────────── const noReplyHandler = createNoReplyHandler(); let moderatorService = null; if (MODERATOR_TOKEN) { console.log("[dirigent-services] moderator bot enabled"); moderatorService = createModeratorService({ token: MODERATOR_TOKEN, pluginApiUrl: PLUGIN_API_URL, pluginApiToken: PLUGIN_API_TOKEN, scheduleIdentifier: SCHEDULE_IDENTIFIER, debugMode: DEBUG_MODE, }); } else { console.log("[dirigent-services] MODERATOR_TOKEN not set — moderator disabled"); } // ── HTTP server ──────────────────────────────────────────────────────────────── const server = http.createServer((req, res) => { const url = req.url ?? "/"; if (url === "/health") { return sendJson(res, 200, { ok: true, services: { noReply: true, moderator: !!moderatorService, }, }); } if (url.startsWith("/no-reply")) { req.url = url.slice("/no-reply".length) || "/"; return noReplyHandler(req, res); } if (url.startsWith("/moderator")) { if (!moderatorService) { return sendJson(res, 503, { error: "moderator service not configured" }); } req.url = url.slice("/moderator".length) || "/"; return moderatorService.httpHandler(req, res); } return sendJson(res, 404, { error: "not_found" }); }); server.listen(PORT, "127.0.0.1", () => { console.log(`[dirigent-services] listening on 127.0.0.1:${PORT}`); console.log(`[dirigent-services] /no-reply → no-reply API`); if (moderatorService) { console.log(`[dirigent-services] /moderator → moderator bot`); console.log(`[dirigent-services] plugin API: ${PLUGIN_API_URL}`); } if (DEBUG_MODE) { console.log(`[dirigent-services] debug mode ON`); } }); // ── Graceful shutdown ────────────────────────────────────────────────────────── function shutdown(signal) { console.log(`[dirigent-services] received ${signal}, shutting down`); if (moderatorService) { moderatorService.stop(); } server.close(() => { console.log("[dirigent-services] server closed"); process.exit(0); }); // Force-exit after 5s setTimeout(() => process.exit(1), 5000).unref(); } process.on("SIGTERM", () => shutdown("SIGTERM")); process.on("SIGINT", () => shutdown("SIGINT"));