51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
/**
|
|
* Full-mesh topology — every peer connects to every other peer, up
|
|
* to `maxPeers`. When capacity is reached, the lowest-scoring
|
|
* existing peer is evicted to make room for the new arrival.
|
|
*/
|
|
|
|
import type { PeerInfo } from "../../types/peer.types.js";
|
|
import {
|
|
type AdmitDecision,
|
|
pickLowestScore,
|
|
type TopologySelectOptions,
|
|
type TopologyStrategy,
|
|
} from "./topology-strategy.js";
|
|
|
|
export class FullMeshStrategy implements TopologyStrategy {
|
|
public readonly name = "full-mesh" as const;
|
|
|
|
public selectConnections(
|
|
currentPeers: readonly PeerInfo[],
|
|
newPeer: PeerInfo,
|
|
options: TopologySelectOptions
|
|
): readonly PeerInfo[] {
|
|
if (newPeer.id === options.selfPeerId) return [];
|
|
if (currentPeers.length >= options.maxPeers) return [];
|
|
return [newPeer];
|
|
}
|
|
|
|
public admitOrEvict(
|
|
currentPeers: readonly PeerInfo[],
|
|
newPeer: PeerInfo,
|
|
options: TopologySelectOptions
|
|
): AdmitDecision {
|
|
if (currentPeers.some((p) => p.id === newPeer.id)) {
|
|
return { admit: false };
|
|
}
|
|
if (currentPeers.length < options.maxPeers) {
|
|
return { admit: true };
|
|
}
|
|
const newScore = options.metricsFor?.(newPeer.id)?.score ?? 1;
|
|
const evictCandidate = pickLowestScore(
|
|
currentPeers,
|
|
options.metricsFor
|
|
);
|
|
if (evictCandidate === undefined) return { admit: false };
|
|
const evictScore =
|
|
options.metricsFor?.(evictCandidate.id)?.score ?? 0.5;
|
|
if (newScore <= evictScore) return { admit: false };
|
|
return { admit: true, evict: evictCandidate };
|
|
}
|
|
}
|