const url = require('url'); const state = require('../../infrastructure/state'); const { trackRequest } = require('../../maintenance/metrics'); const { createErrorResponse } = require('../../infrastructure/error_handler'); const { metrics } = require('../../maintenance/metrics'); async function handleStatusRoutes(req, res) { const urlPath = req.urlPath || new URL(req.url, `https://${req.headers.host}`).pathname; const method = req.method; if (method === 'GET' && urlPath === '/api/status') { try { const status = { isMaster: state.isMaster, isConnected: !!state.dnsPass, peersCount: state.connectedPeers.size, isShuttingDown: state.isShuttingDown || false }; trackRequest('/api/status', true); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(status)); } catch (err) { trackRequest('/api/status', false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } if (method === 'POST' && urlPath === '/api/shutdown') { try { const { logInfo } = require('../../infrastructure/logger'); // Send success response before shutting down res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Graceful shutdown initiated. Process will exit after cleanup completes.' })); // Trigger graceful shutdown after sending response setTimeout(() => { logInfo('Admin', 'Initiating graceful shutdown (without cleaning storage)...'); process.emit('SIGTERM'); }, 500); // Small delay to ensure response is sent } catch (err) { const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } if (method === 'GET' && urlPath === '/api/health') { try { const query = url.parse(req.url, true).query; const probeType = query.probe || 'liveness'; const dnsHealthy = !!state.dnsPass && state.dnsPass.opened !== false; const proxyHealthy = process.env.DISABLE_PROXY_SERVER !== 'true'; const swarmHealthy = state.connectedPeers !== undefined; const corestoreHealthy = state.dnsPass && state.dnsPass.base && state.dnsPass.base.writable !== undefined; const hyperswarmHealthy = swarmHealthy; const dnsServerHealthy = process.env.DISABLE_DNS_SERVER !== 'true'; const httpsServerHealthy = process.env.DISABLE_PROXY_SERVER !== 'true'; const allServicesHealthy = dnsHealthy && proxyHealthy && swarmHealthy && corestoreHealthy && hyperswarmHealthy; const status = allServicesHealthy ? 'healthy' : 'degraded'; const health = { status: status, timestamp: new Date().toISOString(), uptime: Date.now() - (metrics?.startTime || Date.now()), probe: probeType, services: { dns: { enabled: dnsServerHealthy, healthy: dnsHealthy, initialized: !!state.dnsPass, details: { passReady: state.dnsPass?.opened !== false, domainsCount: state.domainToIPMap?.size || 0 } }, proxy: { enabled: httpsServerHealthy, healthy: proxyHealthy, details: { httpsEnabled: process.env.DISABLE_PROXY_SERVER !== 'true', httpEnabled: process.env.DISABLE_PROXY_SERVER !== 'true' } }, swarm: { healthy: swarmHealthy, details: { connectedPeers: state.connectedPeers?.size || 0, isMaster: state.isMaster || false } } }, dependencies: { corestore: { healthy: corestoreHealthy, details: { initialized: !!state.dnsPass, writable: state.dnsPass?.base?.writable || false } }, hyperswarm: { healthy: hyperswarmHealthy, details: { connectedPeers: state.connectedPeers?.size || 0 } } } }; if (probeType === 'readiness') { const ready = allServicesHealthy && state.dnsPass && state.dnsPass.ready; if (!ready) { trackRequest('/api/health', false); res.writeHead(503, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ ...health, status: 'not_ready' })); return true; } } const statusCode = allServicesHealthy ? 200 : 503; trackRequest('/api/health', allServicesHealthy); res.writeHead(statusCode, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(health)); } catch (err) { trackRequest('/api/health', false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } return false; } module.exports = { handleStatusRoutes };