2023-08-16 20:18:13 +05:30
|
|
|
import type { Connection } from "@libp2p/interface/connection";
|
|
|
|
|
import type { Peer, PeerStore } from "@libp2p/interface/peer-store";
|
2022-09-11 10:02:58 +10:00
|
|
|
|
2023-09-08 21:36:55 +05:30
|
|
|
import { bytesToUtf8 } from "../bytes/index.js";
|
|
|
|
|
|
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];
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-08 21:36:55 +05:30
|
|
|
/**
|
2024-01-11 17:25:47 +05:30
|
|
|
* Function to sort peers by latency from lowest to highest
|
2023-09-08 21:36:55 +05:30
|
|
|
* @param peerStore - The Libp2p PeerStore
|
|
|
|
|
* @param peers - The list of peers to choose from
|
2024-01-11 17:25:47 +05:30
|
|
|
* @returns Sorted array of peers by latency
|
2023-09-08 21:36:55 +05:30
|
|
|
*/
|
2024-01-11 17:25:47 +05:30
|
|
|
export async function sortPeersByLatency(
|
2023-09-08 21:36:55 +05:30
|
|
|
peerStore: PeerStore,
|
|
|
|
|
peers: Peer[]
|
2024-01-11 17:25:47 +05:30
|
|
|
): Promise<Peer[]> {
|
|
|
|
|
if (peers.length === 0) return [];
|
2023-09-08 21:36:55 +05:30
|
|
|
|
|
|
|
|
const results = await Promise.all(
|
|
|
|
|
peers.map(async (peer) => {
|
2024-01-11 17:25:47 +05:30
|
|
|
try {
|
|
|
|
|
const pingBytes = (await peerStore.get(peer.id)).metadata.get("ping");
|
|
|
|
|
if (!pingBytes) return { peer, ping: Infinity };
|
|
|
|
|
|
|
|
|
|
const ping = Number(bytesToUtf8(pingBytes));
|
|
|
|
|
return { peer, ping };
|
|
|
|
|
} catch (error) {
|
|
|
|
|
return { peer, ping: Infinity };
|
|
|
|
|
}
|
2023-09-08 21:36:55 +05:30
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
2024-01-11 17:25:47 +05:30
|
|
|
// filter out null values
|
|
|
|
|
const validResults = results.filter(
|
|
|
|
|
(result): result is { peer: Peer; ping: number } => result !== null
|
|
|
|
|
);
|
2023-09-08 21:36:55 +05:30
|
|
|
|
2024-01-11 17:25:47 +05:30
|
|
|
return validResults
|
|
|
|
|
.sort((a, b) => a.ping - b.ping)
|
|
|
|
|
.map((result) => result.peer);
|
2023-09-08 21:36:55 +05:30
|
|
|
}
|
|
|
|
|
|
2021-07-12 13:11:43 +10:00
|
|
|
/**
|
|
|
|
|
* 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,
|
2023-08-16 20:18:13 +05:30
|
|
|
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
|
|
|
|
2024-01-02 15:49:31 +05:30
|
|
|
export async function getConnectedPeersForProtocol(
|
|
|
|
|
connections: Connection[],
|
|
|
|
|
peerStore: PeerStore,
|
|
|
|
|
protocols: string[]
|
|
|
|
|
): Promise<Peer[]> {
|
|
|
|
|
const openConnections = connections.filter(
|
|
|
|
|
(connection) => connection.status === "open"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const peerPromises = openConnections.map(async (connection) => {
|
|
|
|
|
const peer = await peerStore.get(connection.remotePeer);
|
|
|
|
|
const supportsProtocol = peer.protocols.some((protocol) =>
|
|
|
|
|
protocols.includes(protocol)
|
|
|
|
|
);
|
|
|
|
|
return supportsProtocol ? peer : null;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const peersWithNulls = await Promise.all(peerPromises);
|
|
|
|
|
return peersWithNulls.filter((peer): peer is Peer => peer !== null);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 15:46:10 +05:30
|
|
|
export function selectConnection(
|
2023-08-16 20:18:13 +05:30
|
|
|
connections: Connection[]
|
2022-12-06 15:46:10 +05:30
|
|
|
): Connection | undefined {
|
|
|
|
|
if (!connections.length) return;
|
|
|
|
|
if (connections.length === 1) return connections[0];
|
|
|
|
|
|
|
|
|
|
let latestConnection: Connection | undefined;
|
|
|
|
|
|
|
|
|
|
connections.forEach((connection) => {
|
2023-08-16 20:18:13 +05:30
|
|
|
if (connection.status === "open") {
|
2022-12-06 15:46:10 +05:30
|
|
|
if (!latestConnection) {
|
|
|
|
|
latestConnection = connection;
|
2023-08-16 20:18:13 +05:30
|
|
|
} else if (connection.timeline.open > latestConnection.timeline.open) {
|
2022-12-06 15:46:10 +05:30
|
|
|
latestConnection = connection;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return latestConnection;
|
|
|
|
|
}
|