const state = require('../../../infrastructure/state'); const { logError } = require('../../../infrastructure/logger'); const { trackRequest, trackRequestWithTiming } = require('../../../maintenance/metrics'); const { createErrorResponse } = require('../../../infrastructure/error_handler'); const { saveBlockedPeers } = require('../cache'); async function handlePeersRoutes(req, res) { const urlPath = req.urlPath || new URL(req.url, `https://${req.headers.host}`).pathname; const method = req.method; // GET /api/peers - List all peers with details if (method === 'GET' && urlPath === '/api/peers') { try { const startTime = Date.now(); const peers = Array.from(state.connectedPeers).map(peerId => { const connectTime = state.peerStartTimes.get(peerId); const uptime = connectTime ? Date.now() - connectTime : 0; const metrics = state.peerMetrics.get(peerId) || { connections: 0, totalDuration: 0, avgDuration: 0, lastSeen: null }; const isBlocked = state.blockedPeers && state.blockedPeers.has(peerId); return { id: peerId, connected: true, connectTime: connectTime || null, uptime, metrics, isBlocked }; }); const responseTime = Date.now() - startTime; trackRequestWithTiming('/api/peers', true, responseTime); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(peers)); } catch (err) { logError('Admin', `Failed to fetch peers: ${err.message}`); trackRequest('/api/peers', false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } // GET /api/peers/:id - Get peer details if (method === 'GET' && urlPath.startsWith('/api/peers/') && !urlPath.endsWith('/history') && !urlPath.endsWith('/blocked')) { try { const peerId = urlPath.split('/api/peers/')[1]; if (!peerId) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Peer ID is required' })); trackRequest(urlPath, false); return true; } const startTime = Date.now(); const connectTime = state.peerStartTimes.get(peerId); const uptime = connectTime ? Date.now() - connectTime : 0; const history = state.peerHistory.get(peerId) || []; const metrics = state.peerMetrics.get(peerId) || { connections: 0, totalDuration: 0, avgDuration: 0, lastSeen: null }; const isBlocked = state.blockedPeers && state.blockedPeers.has(peerId); const isConnected = state.connectedPeers.has(peerId); const responseTime = Date.now() - startTime; trackRequestWithTiming(urlPath, true, responseTime); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ id: peerId, connected: isConnected, connectTime: connectTime || null, uptime, history: history.slice(-50), // Last 50 events metrics, isBlocked })); } catch (err) { logError('Admin', `Failed to fetch peer details: ${err.message}`); trackRequest(urlPath, false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } // GET /api/peers/:id/history - Get peer connection history if (method === 'GET' && urlPath.endsWith('/history')) { try { const peerId = urlPath.split('/api/peers/')[1].replace('/history', ''); if (!peerId) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Peer ID is required' })); trackRequest(urlPath, false); return true; } const startTime = Date.now(); const history = (state.peerHistory.get(peerId) || []).slice(-50); const responseTime = Date.now() - startTime; trackRequestWithTiming(urlPath, true, responseTime); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(history)); } catch (err) { logError('Admin', `Failed to fetch peer history: ${err.message}`); trackRequest(urlPath, false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } // POST /api/peers/:id/block - Block peer if (method === 'POST' && urlPath.endsWith('/block')) { try { const peerId = urlPath.split('/api/peers/')[1].replace('/block', ''); if (!peerId) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Peer ID is required' })); trackRequest(urlPath, false); return true; } if (!state.blockedPeers) { state.blockedPeers = new Set(); } state.blockedPeers.add(peerId); // Save blocked peers to disk await saveBlockedPeers(); // Disconnect if currently connected if (state.connectedPeers.has(peerId)) { // Find and close the connection // Note: This is a simplified approach - in practice you'd need to track connections logError('Admin', `Peer ${peerId} is currently connected. Blocking will take effect on next connection attempt.`); } trackRequest(urlPath, true); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: `Peer ${peerId} blocked` })); } catch (err) { logError('Admin', `Failed to block peer: ${err.message}`); trackRequest(urlPath, false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } // POST /api/peers/:id/unblock - Unblock peer if (method === 'POST' && urlPath.endsWith('/unblock')) { try { const peerId = urlPath.split('/api/peers/')[1].replace('/unblock', ''); if (!peerId) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ error: 'Peer ID is required' })); trackRequest(urlPath, false); return true; } if (state.blockedPeers) { state.blockedPeers.delete(peerId); } // Save blocked peers to disk await saveBlockedPeers(); trackRequest(urlPath, true); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: `Peer ${peerId} unblocked` })); } catch (err) { logError('Admin', `Failed to unblock peer: ${err.message}`); trackRequest(urlPath, false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } // GET /api/peers/blocked - List blocked peers if (method === 'GET' && urlPath === '/api/peers/blocked') { try { const blocked = state.blockedPeers ? Array.from(state.blockedPeers) : []; trackRequest(urlPath, true); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(blocked)); } catch (err) { logError('Admin', `Failed to fetch blocked peers: ${err.message}`); trackRequest(urlPath, false); const errorResponse = createErrorResponse(err, 500); res.writeHead(errorResponse.statusCode, errorResponse.headers); res.end(errorResponse.body); } return true; } return false; } module.exports = { handlePeersRoutes };