network/src/ipfs/loadBalancerService.ts
2025-04-01 10:44:20 +03:00

144 lines
3.8 KiB
TypeScript

// Load balancer service - Implements load balancing strategies for distributing connections
import * as ipfsService from './ipfsService';
import { config } from '../config';
// Track last peer chosen for round-robin strategy
let lastPeerIndex = -1;
interface PeerInfo {
peerId: string;
load: number;
publicAddress: string;
}
interface PeerStatus extends PeerInfo {
lastSeen: number;
}
interface NodeStatus {
fingerprint: string;
peerCount: number;
isHealthy: boolean;
}
interface LoadBalancerServiceModule {
getOptimalPeer: () => PeerInfo | null;
getAllPeers: () => PeerStatus[];
getNodeStatus: () => NodeStatus;
}
/**
* Get the optimal peer based on the configured load balancing strategy
* @returns Object containing the selected peer information or null if no peers available
*/
export const getOptimalPeer = (): { peerId: string; load: number; publicAddress: string } | null => {
// Get all available peers
const connectedPeers = ipfsService.getConnectedPeers();
// If no peers are available, return null
if (connectedPeers.size === 0) {
console.log('[LOAD-BALANCER] No peers available for load balancing');
return null;
}
// Convert Map to Array for easier manipulation
const peersArray = Array.from(connectedPeers.entries()).map(([peerId, data]) => {
return {
peerId,
load: data.load,
lastSeen: data.lastSeen,
publicAddress: data.publicAddress,
};
});
// Apply the load balancing strategy
const strategy = config.loadBalancer.strategy;
let selectedPeer;
switch (strategy) {
case 'least-loaded':
// Find the peer with the lowest load
selectedPeer = peersArray.reduce((min, current) => (current.load < min.load ? current : min), peersArray[0]);
console.log(
`[LOAD-BALANCER] Selected least loaded peer: ${selectedPeer.peerId.substring(0, 15)}... with load ${
selectedPeer.load
}%`
);
break;
case 'round-robin':
// Simple round-robin strategy
lastPeerIndex = (lastPeerIndex + 1) % peersArray.length;
selectedPeer = peersArray[lastPeerIndex];
console.log(
`[LOAD-BALANCER] Selected round-robin peer: ${selectedPeer.peerId.substring(0, 15)}... with load ${
selectedPeer.load
}%`
);
break;
case 'random':
// Random selection
const randomIndex = Math.floor(Math.random() * peersArray.length);
selectedPeer = peersArray[randomIndex];
console.log(
`[LOAD-BALANCER] Selected random peer: ${selectedPeer.peerId.substring(0, 15)}... with load ${
selectedPeer.load
}%`
);
break;
default:
// Default to least-loaded if unknown strategy
selectedPeer = peersArray.reduce((min, current) => (current.load < min.load ? current : min), peersArray[0]);
console.log(
`[LOAD-BALANCER] Selected least loaded peer: ${selectedPeer.peerId.substring(0, 15)}... with load ${
selectedPeer.load
}%`
);
}
return {
peerId: selectedPeer.peerId,
load: selectedPeer.load,
publicAddress: selectedPeer.publicAddress,
};
};
/**
* Get all available peers with their load information
* @returns Array of peer information objects
*/
export const getAllPeers = () => {
const connectedPeers = ipfsService.getConnectedPeers();
const result: any = [];
connectedPeers.forEach((data, peerId) => {
result.push({
peerId,
load: data.load,
lastSeen: data.lastSeen,
});
});
return result;
};
/**
* Get information about the current node's load
*/
export const getNodeStatus = () => {
const connectedPeers = ipfsService.getConnectedPeers();
return {
fingerprint: config.env.fingerprint,
peerCount: connectedPeers.size,
isHealthy: true,
};
};
export default {
getOptimalPeer,
getAllPeers,
getNodeStatus,
} as LoadBalancerServiceModule;