Reference implementation for the Phoenix Architecture. Work in progress. aicoding.leaflet.pub/
ai coding crazy
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 121 lines 4.3 kB view raw
1/** 2 * Server — HTTP Server 3 * 4 * AUTO-GENERATED by Phoenix VCS 5 * Provides health check, metrics, and module endpoints. 6 */ 7 8import { createServer, IncomingMessage, ServerResponse } from 'node:http'; 9 10import * as connectionHandling from './connection-handling.js'; 11import * as rooms from './rooms.js'; 12 13// ─── Metrics ───────────────────────────────────────────────────────────────── 14 15const _svcMetrics = { 16 requests_total: 0, 17 requests_by_path: {} as Record<string, number>, 18 errors_total: 0, 19 uptime_start: Date.now(), 20}; 21 22// ─── Module Registry ───────────────────────────────────────────────────────── 23 24const _svcModules = { 25 'connection-handling': connectionHandling, 26 'rooms': rooms, 27}; 28 29// ─── Router ────────────────────────────────────────────────────────────────── 30 31type Handler = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>; 32 33const routes: Record<string, Handler> = { 34 '/health': (_req, res) => { 35 res.writeHead(200, { 'Content-Type': 'application/json' }); 36 res.end(JSON.stringify({ 37 status: 'ok', 38 service: 'Server', 39 uptime: Math.floor((Date.now() - _svcMetrics.uptime_start) / 1000), 40 modules: Object.keys(_svcModules), 41 })); 42 }, 43 44 '/metrics': (_req, res) => { 45 res.writeHead(200, { 'Content-Type': 'application/json' }); 46 res.end(JSON.stringify({ 47 ..._svcMetrics, 48 uptime_seconds: Math.floor((Date.now() - _svcMetrics.uptime_start) / 1000), 49 }, null, 2)); 50 }, 51 52 '/modules': (_req, res) => { 53 const info = Object.entries(_svcModules).map(([name, mod]) => { 54 const phoenix = (mod as Record<string, unknown>)._phoenix as Record<string, unknown> | undefined; 55 return { 56 name, 57 risk_tier: phoenix?.risk_tier ?? 'unknown', 58 exports: Object.keys(mod).filter(k => k !== '_phoenix'), 59 }; 60 }); 61 res.writeHead(200, { 'Content-Type': 'application/json' }); 62 res.end(JSON.stringify(info, null, 2)); 63 }, 64}; 65 66// ─── Server ────────────────────────────────────────────────────────────────── 67 68function handleRequest(req: IncomingMessage, res: ServerResponse): void { 69 const url = req.url ?? '/'; 70 const path = url.split('?')[0]; 71 72 _svcMetrics.requests_total++; 73 _svcMetrics.requests_by_path[path] = (_svcMetrics.requests_by_path[path] ?? 0) + 1; 74 75 const handler = routes[path]; 76 if (handler) { 77 try { 78 handler(req, res); 79 } catch (err) { 80 _svcMetrics.errors_total++; 81 res.writeHead(500, { 'Content-Type': 'application/json' }); 82 res.end(JSON.stringify({ error: String(err) })); 83 } 84 } else { 85 res.writeHead(404, { 'Content-Type': 'application/json' }); 86 res.end(JSON.stringify({ 87 error: 'Not Found', 88 path, 89 available: Object.keys(routes), 90 })); 91 } 92} 93 94export function startServer(port?: number): { server: ReturnType<typeof createServer>; port: number; ready: Promise<void> } { 95 const requestedPort = port ?? parseInt(process.env.SERVER_PORT ?? process.env.PORT ?? '3001', 10); 96 const server = createServer(handleRequest); 97 let actualPort = requestedPort; 98 99 const ready = new Promise<void>(resolve => { 100 server.listen(requestedPort, () => { 101 const addr = server.address(); 102 if (addr && typeof addr === 'object') actualPort = addr.port; 103 result.port = actualPort; 104 console.log(`Server listening on http://localhost:${actualPort}`); 105 console.log(` /health — health check`); 106 console.log(` /metrics — request metrics`); 107 console.log(` /modules — registered modules`); 108 resolve(); 109 }); 110 }); 111 112 const result = { server, port: actualPort, ready }; 113 return result; 114} 115 116// Start when run directly 117const isMain = process.argv[1]?.endsWith('/server/server.js') || 118 process.argv[1]?.endsWith('/server/server.ts'); 119if (isMain) { 120 startServer(); 121}