2022-09-11 10:02:58 +10:00
|
|
|
import type { PeerId } from "@libp2p/interface-peer-id";
|
2022-09-11 09:49:17 +10:00
|
|
|
import type { Peer, PeerStore } from "@libp2p/interface-peer-store";
|
2022-09-11 10:02:58 +10:00
|
|
|
import debug from "debug";
|
|
|
|
|
|
|
|
|
|
const log = debug("waku:select-peer");
|
2021-06-16 23:37:13 +10:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns a pseudo-random peer that supports the given protocol.
|
|
|
|
|
* Useful for protocols such as store and light push
|
|
|
|
|
*/
|
2022-09-11 09:54:10 +10:00
|
|
|
export function selectRandomPeer(peers: Peer[]): Peer | undefined {
|
2021-06-16 23:37:13 +10:00
|
|
|
if (peers.length === 0) return;
|
2021-07-12 13:11:43 +10:00
|
|
|
|
|
|
|
|
const index = Math.round(Math.random() * (peers.length - 1));
|
|
|
|
|
return peers[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the list of peers that supports the given protocol.
|
|
|
|
|
*/
|
2022-06-20 16:48:30 +10:00
|
|
|
export async function getPeersForProtocol(
|
2022-09-11 09:49:17 +10:00
|
|
|
peerStore: PeerStore,
|
2022-02-24 16:25:58 +11:00
|
|
|
protocols: string[]
|
2022-06-20 16:48:30 +10:00
|
|
|
): Promise<Peer[]> {
|
|
|
|
|
const peers: Peer[] = [];
|
2022-09-11 09:49:17 +10:00
|
|
|
await peerStore.forEach((peer) => {
|
2022-02-24 16:25:58 +11:00
|
|
|
for (let i = 0; i < protocols.length; i++) {
|
|
|
|
|
if (peer.protocols.includes(protocols[i])) {
|
2022-06-20 16:48:30 +10:00
|
|
|
peers.push(peer);
|
2022-02-24 16:25:58 +11:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-20 16:48:30 +10:00
|
|
|
});
|
|
|
|
|
return peers;
|
2021-06-16 23:37:13 +10:00
|
|
|
}
|
2022-09-11 10:02:58 +10:00
|
|
|
|
|
|
|
|
export async function selectPeerForProtocol(
|
|
|
|
|
peerStore: PeerStore,
|
|
|
|
|
protocols: string[],
|
|
|
|
|
peerId?: PeerId
|
|
|
|
|
): Promise<{ peer: Peer; protocol: string } | undefined> {
|
|
|
|
|
let peer;
|
|
|
|
|
if (peerId) {
|
|
|
|
|
peer = await peerStore.get(peerId);
|
|
|
|
|
if (!peer) {
|
|
|
|
|
log(
|
|
|
|
|
`Failed to retrieve connection details for provided peer in peer store: ${peerId.toString()}`
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
const peers = await getPeersForProtocol(peerStore, protocols);
|
|
|
|
|
peer = selectRandomPeer(peers);
|
|
|
|
|
if (!peer) {
|
|
|
|
|
log("Failed to find known peer that registers protocols", protocols);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let protocol;
|
|
|
|
|
for (const codec of protocols) {
|
|
|
|
|
if (peer.protocols.includes(codec)) {
|
|
|
|
|
protocol = codec;
|
|
|
|
|
// Do not break as we want to keep the last value
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
log(`Using codec ${protocol}`);
|
|
|
|
|
if (!protocol) {
|
|
|
|
|
log(
|
|
|
|
|
`Peer does not register required protocols: ${peer.id.toString()}`,
|
|
|
|
|
protocols
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { peer, protocol };
|
|
|
|
|
}
|