144 lines
3.8 KiB
TypeScript
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;
|