Files
suaveplan/packages/networking/drive/drive-webrtc/src/peer-manager/topology/super-peer.ts
2026-05-27 23:47:53 +01:00

90 lines
3.1 KiB
TypeScript

/**
* Super-peer topology — well-resourced "super peers" form a full
* mesh among themselves and accept connections from any peer; ordinary
* peers connect to a bounded number of super peers (default 3).
*/
import type { PeerInfo } from "../../types/peer.types.js";
import {
type AdmitDecision,
pickLowestScore,
type TopologySelectOptions,
type TopologyStrategy,
} from "./topology-strategy.js";
export interface SuperPeerStrategyOptions {
/** Whether this node is itself a super peer. */
readonly selfIsSuperPeer: boolean;
/** Set of peer ids known to be super peers. */
readonly superPeerIds: ReadonlySet<string>;
/** Cap on outbound super-peer connections for non-super peers. */
readonly targetSuperPeers?: number;
}
const DEFAULT_TARGET_SUPER_PEERS = 3;
export class SuperPeerStrategy implements TopologyStrategy {
public readonly name = "super-peer" as const;
private readonly selfIsSuperPeer: boolean;
private readonly superPeerIds: ReadonlySet<string>;
private readonly targetSuperPeers: number;
public constructor(opts: SuperPeerStrategyOptions) {
this.selfIsSuperPeer = opts.selfIsSuperPeer;
this.superPeerIds = opts.superPeerIds;
this.targetSuperPeers =
opts.targetSuperPeers ?? DEFAULT_TARGET_SUPER_PEERS;
}
public selectConnections(
currentPeers: readonly PeerInfo[],
newPeer: PeerInfo,
options: TopologySelectOptions
): readonly PeerInfo[] {
if (newPeer.id === options.selfPeerId) return [];
if (this.selfIsSuperPeer) {
if (currentPeers.length >= options.maxPeers) return [];
return [newPeer];
}
if (!this.superPeerIds.has(newPeer.id)) return [];
const connectedSuperPeers = currentPeers.filter((p) =>
this.superPeerIds.has(p.id)
).length;
if (connectedSuperPeers >= this.targetSuperPeers) 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 (this.selfIsSuperPeer) {
if (currentPeers.length < options.maxPeers) {
return { admit: true };
}
const evict = pickLowestScore(
currentPeers.filter((p) => !this.superPeerIds.has(p.id)),
options.metricsFor
);
if (evict === undefined) return { admit: false };
return { admit: true, evict };
}
if (!this.superPeerIds.has(newPeer.id)) return { admit: false };
const connectedSuperPeers = currentPeers.filter((p) =>
this.superPeerIds.has(p.id)
);
if (
connectedSuperPeers.length < this.targetSuperPeers &&
currentPeers.length < options.maxPeers
) {
return { admit: true };
}
return { admit: false };
}
}