mirror of https://github.com/waku-org/js-waku.git
fix: Wait for remote peer for Waku Relay
The promise resolves only if a remote peer is added to the gossipsub mesh.
This commit is contained in:
parent
2265a0099f
commit
d7b08f7e24
|
@ -32,6 +32,7 @@
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"libp2p": "next",
|
"libp2p": "next",
|
||||||
"multiformats": "^9.6.5",
|
"multiformats": "^9.6.5",
|
||||||
|
"p-event": "^5.0.1",
|
||||||
"protons-runtime": "^1.0.4",
|
"protons-runtime": "^1.0.4",
|
||||||
"uint8arrays": "^3.0.0",
|
"uint8arrays": "^3.0.0",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
|
@ -9798,6 +9799,31 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/p-event": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"p-timeout": "^5.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/p-event/node_modules/p-timeout": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/p-fifo": {
|
"node_modules/p-fifo": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz",
|
||||||
|
@ -20602,6 +20628,21 @@
|
||||||
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.0.tgz",
|
||||||
"integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ=="
|
"integrity": "sha512-Vb3QRvQ0Y5XnF40ZUWW7JfLogicVh/EnA5gBIvKDJoYpeI82+1E3AlB9yOcKFS0AhHrWVnAQO39fbR0G99IVEQ=="
|
||||||
},
|
},
|
||||||
|
"p-event": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-event/-/p-event-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==",
|
||||||
|
"requires": {
|
||||||
|
"p-timeout": "^5.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"p-timeout": {
|
||||||
|
"version": "5.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-5.1.0.tgz",
|
||||||
|
"integrity": "sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"p-fifo": {
|
"p-fifo": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz",
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"libp2p": "next",
|
"libp2p": "next",
|
||||||
"multiformats": "^9.6.5",
|
"multiformats": "^9.6.5",
|
||||||
|
"p-event": "^5.0.1",
|
||||||
"protons-runtime": "^1.0.4",
|
"protons-runtime": "^1.0.4",
|
||||||
"uint8arrays": "^3.0.0",
|
"uint8arrays": "^3.0.0",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^8.3.2"
|
||||||
|
|
|
@ -36,7 +36,7 @@ describe("Wait for remote peer", function () {
|
||||||
await waku.dial(multiAddrWithId);
|
await waku.dial(multiAddrWithId);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
await waitForRemotePeer(waku, [Protocols.Relay]);
|
await waitForRemotePeer(waku, [Protocols.Relay]);
|
||||||
const peers = waku.relay.getPeers();
|
const peers = waku.relay.getMeshPeers();
|
||||||
const nimPeerId = multiAddrWithId.getPeerId();
|
const nimPeerId = multiAddrWithId.getPeerId();
|
||||||
|
|
||||||
expect(nimPeerId).to.not.be.undefined;
|
expect(nimPeerId).to.not.be.undefined;
|
||||||
|
@ -64,8 +64,7 @@ describe("Wait for remote peer", function () {
|
||||||
await waku.dial(multiAddrWithId);
|
await waku.dial(multiAddrWithId);
|
||||||
await waitPromise;
|
await waitPromise;
|
||||||
|
|
||||||
// TODO: Should getMeshPeers be used instead?
|
const peers = waku.relay.getMeshPeers();
|
||||||
const peers = waku.relay.getPeers();
|
|
||||||
const nimPeerId = multiAddrWithId.getPeerId();
|
const nimPeerId = multiAddrWithId.getPeerId();
|
||||||
|
|
||||||
expect(nimPeerId).to.not.be.undefined;
|
expect(nimPeerId).to.not.be.undefined;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import type { GossipSub } from "@chainsafe/libp2p-gossipsub";
|
||||||
import { Peer, PeerProtocolsChangeData } from "@libp2p/interface-peer-store";
|
import { Peer, PeerProtocolsChangeData } from "@libp2p/interface-peer-store";
|
||||||
import debug from "debug";
|
import debug from "debug";
|
||||||
import type { Libp2p } from "libp2p";
|
import type { Libp2p } from "libp2p";
|
||||||
|
import { pEvent } from "p-event";
|
||||||
|
|
||||||
import { StoreCodecs } from "./constants";
|
import { StoreCodecs } from "./constants";
|
||||||
import { Protocols, Waku } from "./waku";
|
import { Protocols, Waku } from "./waku";
|
||||||
|
@ -14,10 +16,18 @@ interface WakuProtocol {
|
||||||
peers: () => Promise<Peer[]>;
|
peers: () => Promise<Peer[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface WakuGossipSubProtocol extends GossipSub {
|
||||||
|
getMeshPeers: () => string[];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wait for a remote peer to be ready given the passed protocols.
|
* Wait for a remote peer to be ready given the passed protocols.
|
||||||
* Useful when using the [[CreateOptions.bootstrap]] with [[Waku.create]].
|
* Useful when using the [[CreateOptions.bootstrap]] with [[Waku.create]].
|
||||||
*
|
*
|
||||||
|
* If the passed protocols is a GossipSub protocol, then it resolves only once
|
||||||
|
* a peer is in a mesh, to help ensure that other peers will send and receive
|
||||||
|
* message to us.
|
||||||
|
*
|
||||||
* @param waku The Waku Node
|
* @param waku The Waku Node
|
||||||
* @param protocols The protocols that need to be enabled by remote peers.
|
* @param protocols The protocols that need to be enabled by remote peers.
|
||||||
* @param timeoutMs A timeout value in milliseconds..
|
* @param timeoutMs A timeout value in milliseconds..
|
||||||
|
@ -34,23 +44,10 @@ export async function waitForRemotePeer(
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
protocols = protocols ?? [Protocols.Relay];
|
protocols = protocols ?? [Protocols.Relay];
|
||||||
|
|
||||||
const promises: Promise<void>[] = [];
|
const promises = [];
|
||||||
|
|
||||||
if (protocols.includes(Protocols.Relay)) {
|
if (protocols.includes(Protocols.Relay)) {
|
||||||
const peers = waku.relay.getMeshPeers(waku.relay.pubSubTopic);
|
promises.push(waitForGossipSubPeerInMesh(waku.relay));
|
||||||
|
|
||||||
if (peers.length == 0) {
|
|
||||||
// No peer yet available, wait for a subscription
|
|
||||||
const promise = new Promise<void>((resolve) => {
|
|
||||||
// TODO: Remove listeners once done
|
|
||||||
waku.relay.addEventListener("subscription-change", () => {
|
|
||||||
// Remote peer subscribed to topic, now wait for a heartbeat
|
|
||||||
// so that the mesh is updated and the remote peer added to it
|
|
||||||
waku.relay.addEventListener("gossipsub:heartbeat", () => resolve());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
promises.push(promise);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocols.includes(Protocols.Store)) {
|
if (protocols.includes(Protocols.Store)) {
|
||||||
|
@ -105,6 +102,21 @@ async function waitForConnectedPeer(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for a peer with the given protocol to be connected and in the gossipsub
|
||||||
|
* mesh.
|
||||||
|
*/
|
||||||
|
async function waitForGossipSubPeerInMesh(
|
||||||
|
waku: WakuGossipSubProtocol
|
||||||
|
): Promise<void> {
|
||||||
|
let peers = waku.getMeshPeers();
|
||||||
|
|
||||||
|
while (peers.length == 0) {
|
||||||
|
await pEvent(waku, "gossipsub:heartbeat");
|
||||||
|
peers = waku.getMeshPeers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const awaitTimeout = (ms: number, rejectReason: string): Promise<void> =>
|
const awaitTimeout = (ms: number, rejectReason: string): Promise<void> =>
|
||||||
new Promise((_resolve, reject) => setTimeout(() => reject(rejectReason), ms));
|
new Promise((_resolve, reject) => setTimeout(() => reject(rejectReason), ms));
|
||||||
|
|
||||||
|
|
|
@ -210,9 +210,6 @@ export class WakuRelay extends GossipSub {
|
||||||
}
|
}
|
||||||
|
|
||||||
getMeshPeers(topic?: TopicStr): PeerIdStr[] {
|
getMeshPeers(topic?: TopicStr): PeerIdStr[] {
|
||||||
return super.getMeshPeers(topic ?? DefaultPubSubTopic);
|
return super.getMeshPeers(topic ?? this.pubSubTopic);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement method that uses Relay codec
|
|
||||||
// public async heartbeat(): Promise<void> {
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue