Files
p2ns/includes/admin/admin-backend/routes/peers.js
T
2025-12-17 20:05:50 -05:00

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 };