113 lines
2.9 KiB
TypeScript
113 lines
2.9 KiB
TypeScript
import * as ipfsService from './ipfsService';
|
|
import { config } from '../config';
|
|
import { createServiceLogger } from '../utils/logger';
|
|
|
|
const logger = createServiceLogger('LOAD_BALANCER');
|
|
|
|
// Track last peer chosen for round-robin strategy
|
|
let lastPeerIndex = -1;
|
|
|
|
// Type definitions
|
|
export interface PeerInfo {
|
|
peerId: string;
|
|
load: number;
|
|
publicAddress: string;
|
|
}
|
|
|
|
export interface PeerStatus extends PeerInfo {
|
|
lastSeen: number;
|
|
}
|
|
|
|
export interface NodeStatus {
|
|
fingerprint: string;
|
|
peerCount: number;
|
|
isHealthy: boolean;
|
|
}
|
|
|
|
type LoadBalancerStrategy = 'leastLoaded' | 'roundRobin' | 'random';
|
|
|
|
/**
|
|
* Strategies for peer selection
|
|
*/
|
|
const strategies = {
|
|
leastLoaded: (peers: PeerStatus[]): PeerStatus => {
|
|
return peers.reduce((min, current) => (current.load < min.load ? current : min), peers[0]);
|
|
},
|
|
|
|
roundRobin: (peers: PeerStatus[]): PeerStatus => {
|
|
lastPeerIndex = (lastPeerIndex + 1) % peers.length;
|
|
return peers[lastPeerIndex];
|
|
},
|
|
|
|
random: (peers: PeerStatus[]): PeerStatus => {
|
|
const randomIndex = Math.floor(Math.random() * peers.length);
|
|
return peers[randomIndex];
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Get the optimal peer based on the configured load balancing strategy
|
|
*/
|
|
export const getOptimalPeer = (): PeerInfo | null => {
|
|
const connectedPeers = ipfsService.getConnectedPeers();
|
|
|
|
if (connectedPeers.size === 0) {
|
|
logger.info('No peers available for load balancing');
|
|
return null;
|
|
}
|
|
|
|
// Convert Map to Array for easier manipulation
|
|
const peersArray = Array.from(connectedPeers.entries()).map(([peerId, data]) => ({
|
|
peerId,
|
|
load: data.load,
|
|
lastSeen: data.lastSeen,
|
|
publicAddress: data.publicAddress,
|
|
}));
|
|
|
|
// Apply the selected load balancing strategy
|
|
const strategy = config.loadBalancer.strategy as LoadBalancerStrategy;
|
|
let selectedPeer;
|
|
|
|
// Select strategy function or default to least loaded
|
|
const strategyFn = strategies[strategy] || strategies.leastLoaded;
|
|
selectedPeer = strategyFn(peersArray);
|
|
|
|
logger.info(
|
|
`Selected peer (${strategy}): ${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
|
|
*/
|
|
export const getAllPeers = (): PeerStatus[] => {
|
|
const connectedPeers = ipfsService.getConnectedPeers();
|
|
|
|
return Array.from(connectedPeers.entries()).map(([peerId, data]) => ({
|
|
peerId,
|
|
load: data.load,
|
|
lastSeen: data.lastSeen,
|
|
publicAddress: data.publicAddress,
|
|
}));
|
|
};
|
|
|
|
/**
|
|
* Get information about the current node's load
|
|
*/
|
|
export const getNodeStatus = (): NodeStatus => {
|
|
const connectedPeers = ipfsService.getConnectedPeers();
|
|
return {
|
|
fingerprint: config.env.fingerprint,
|
|
peerCount: connectedPeers.size,
|
|
isHealthy: true,
|
|
};
|
|
};
|
|
|
|
export default { getOptimalPeer, getAllPeers, getNodeStatus };
|