216 lines
7.8 KiB
JavaScript
216 lines
7.8 KiB
JavaScript
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 };
|
|
|