mirror of https://github.com/waku-org/js-waku.git
Added `Waku.waitForConnectedPeer` helper
To ensure that we are connected to Waku peers when using the bootstrap option.
This commit is contained in:
parent
524fbc9361
commit
a21d641280
|
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Allow passing decryption keys in hex string format.
|
||||
- Allow passing decryption keys to `WakuStore` instance to avoid having to pass them at every `queryHistory` call.
|
||||
- Allow passing decryption keys to `Waku` instance to avoid having to pass them to both `WakuRelay` and `WakuStore`.
|
||||
- `Waku.waitForConnectedPeer` helper to ensure that we are connected to Waku peers when using the bootstrap option.
|
||||
|
||||
### Changed
|
||||
- **Breaking**: Moved `startTime` and `endTime` for history queries to a `timeFilter` property as both or neither must be passed; passing only one parameter is not supported.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import './App.css';
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { Waku, WakuMessage } from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import protons from 'protons';
|
||||
|
||||
|
@ -24,10 +24,10 @@ function App() {
|
|||
|
||||
setWakuStatus('Starting');
|
||||
|
||||
Waku.create().then((waku) => {
|
||||
Waku.create({ bootstrap: true }).then((waku) => {
|
||||
setWaku(waku);
|
||||
setWakuStatus('Connecting');
|
||||
bootstrapWaku(waku).then(() => {
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus('Ready');
|
||||
});
|
||||
});
|
||||
|
@ -95,15 +95,6 @@ function App() {
|
|||
|
||||
export default App;
|
||||
|
||||
async function bootstrapWaku(waku) {
|
||||
try {
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
} catch (e) {
|
||||
console.error('Failed to bootstrap to Waku network');
|
||||
}
|
||||
}
|
||||
|
||||
async function sendMessage(message, timestamp, waku) {
|
||||
const time = timestamp.getTime();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import './App.css';
|
||||
import { StoreCodec, Waku } from 'js-waku';
|
||||
import { Waku } from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import protons from 'protons';
|
||||
|
||||
|
@ -57,18 +57,10 @@ function App() {
|
|||
// We do not handle disconnection/re-connection in this example
|
||||
if (wakuStatus === 'Connected to Store') return;
|
||||
|
||||
const isStoreNode = ({ protocols }) => {
|
||||
if (protocols.includes(StoreCodec)) {
|
||||
// We are now connected to a store node
|
||||
setWakuStatus('Connected to Store');
|
||||
}
|
||||
};
|
||||
|
||||
waku.libp2p.peerStore.on('change:protocols', isStoreNode);
|
||||
|
||||
return () => {
|
||||
waku.libp2p.peerStore.removeListener('change:protocols', isStoreNode);
|
||||
};
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
// We are now connected to a store node
|
||||
setWakuStatus('Connected to Store');
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
import { useEffect, useReducer, useState } from 'react';
|
||||
import './App.css';
|
||||
import {
|
||||
Direction,
|
||||
getBootstrapNodes,
|
||||
StoreCodec,
|
||||
Waku,
|
||||
WakuMessage,
|
||||
} from 'js-waku';
|
||||
import { Direction, getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import handleCommand from './command';
|
||||
import Room from './Room';
|
||||
import { WakuContext } from './WakuContext';
|
||||
|
@ -79,8 +73,8 @@ async function retrieveStoreMessages(
|
|||
});
|
||||
|
||||
return res.length;
|
||||
} catch {
|
||||
console.log('Failed to retrieve messages');
|
||||
} catch (e) {
|
||||
console.log('Failed to retrieve messages', e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -131,29 +125,21 @@ export default function App() {
|
|||
if (!waku) return;
|
||||
if (historicalMessagesRetrieved) return;
|
||||
|
||||
const checkAndRetrieve = ({ protocols }: { protocols: string[] }) => {
|
||||
if (protocols.includes(StoreCodec)) {
|
||||
console.log(`Retrieving archived messages}`);
|
||||
setHistoricalMessagesRetrieved(true);
|
||||
const retrieveMessages = async () => {
|
||||
await waku.waitForConnectedPeer();
|
||||
console.log(`Retrieving archived messages}`);
|
||||
|
||||
try {
|
||||
retrieveStoreMessages(waku, dispatchMessages).then((length) =>
|
||||
console.log(`Messages retrieved:`, length)
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(`Error encountered when retrieving archived messages`, e);
|
||||
}
|
||||
try {
|
||||
retrieveStoreMessages(waku, dispatchMessages).then((length) => {
|
||||
console.log(`Messages retrieved:`, length);
|
||||
setHistoricalMessagesRetrieved(true);
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(`Error encountered when retrieving archived messages`, e);
|
||||
}
|
||||
};
|
||||
|
||||
waku.libp2p.peerStore.on('change:protocols', checkAndRetrieve);
|
||||
|
||||
return () => {
|
||||
waku.libp2p.peerStore.removeListener(
|
||||
'change:protocols',
|
||||
checkAndRetrieve
|
||||
);
|
||||
};
|
||||
retrieveMessages();
|
||||
}, [waku, historicalMessagesRetrieved]);
|
||||
|
||||
return (
|
||||
|
|
|
@ -60,7 +60,7 @@ function App() {
|
|||
setWakuStatus('Starting');
|
||||
|
||||
// Create Waku
|
||||
Waku.create().then((waku) => {
|
||||
Waku.create({ bootstrap: true }).then((waku) => {
|
||||
// Once done, put it in the state
|
||||
setWaku(waku);
|
||||
// And update the status
|
||||
|
@ -69,8 +69,8 @@ function App() {
|
|||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<div className='App'>
|
||||
<header className='App-header'>
|
||||
// Display the status on the web page
|
||||
<p>{wakuStatus}</p>
|
||||
</header>
|
||||
|
@ -79,25 +79,11 @@ function App() {
|
|||
}
|
||||
```
|
||||
|
||||
# Connect to Other Peers
|
||||
# Wait to be connected
|
||||
|
||||
The Waku instance needs to connect to other peers to communicate with the network.
|
||||
First, create `bootstrapWaku` to connect to Waku bootstrap nodes:
|
||||
|
||||
```js
|
||||
import { getBootstrapNodes } from 'js-waku';
|
||||
|
||||
async function bootstrapWaku(waku) {
|
||||
try {
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
} catch (e) {
|
||||
console.error('Failed to bootstrap to Waku network');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, bootstrap after Waku is created in the previous `useEffect` block:
|
||||
When using the `bootstrap` option, it may take some times to connect to other peers.
|
||||
To ensure that you have relay peers available to send and receive messages,
|
||||
use the `Waku.waitForConnectedPeer()` async function:
|
||||
|
||||
```js
|
||||
React.useEffect(() => {
|
||||
|
@ -106,17 +92,16 @@ React.useEffect(() => {
|
|||
|
||||
setWakuStatus('Starting');
|
||||
|
||||
Waku.create().then((waku) => {
|
||||
Waku.create({ bootstrap: true }).then((waku) => {
|
||||
setWaku(waku);
|
||||
setWakuStatus('Connecting');
|
||||
bootstrapWaku(waku).then(() => {
|
||||
waku.waitForConnectedPeer().then(() => {
|
||||
setWakuStatus('Ready');
|
||||
});
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
```
|
||||
|
||||
DappConnect will provide more discovery and bootstrap methods over time, or you can make your own.
|
||||
```
|
||||
|
||||
# Define Message Format
|
||||
|
||||
|
|
|
@ -23,23 +23,35 @@ In order to interact with the Waku network, you first need a Waku instance:
|
|||
```js
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
const wakuNode = await Waku.create();
|
||||
const wakuNode = await Waku.create({ bootstrap: true });
|
||||
```
|
||||
|
||||
# Connect to Other Peers
|
||||
|
||||
The Waku instance needs to connect to other peers to communicate with the network.
|
||||
You are free to choose any method to bootstrap and DappConnect will ship with new methods in the future.
|
||||
|
||||
For now, the easiest way is to connect to Status' Waku fleet:
|
||||
Passing the `bootstrap` option will connect your node to predefined Waku nodes.
|
||||
If you want to bootstrap to your own nodes, you can pass an array of multiaddresses instead:
|
||||
|
||||
```js
|
||||
import { getBootstrapNodes } from 'js-waku';
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
const wakuNode = await Waku.create({
|
||||
bootstrap: [
|
||||
'/dns4/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAkvWiyFsgRhuJEb9JfjYxEkoHLgnUQmr1N5mKWnYjxYRVm',
|
||||
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ'
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
# Wait to be connected
|
||||
|
||||
When using the `bootstrap` option, it may take some times to connect to other peers.
|
||||
To ensure that you have relay peers available to send and receive messages,
|
||||
use the following function:
|
||||
|
||||
```js
|
||||
await waku.waitForConnectedPeer();
|
||||
```
|
||||
|
||||
The returned Promise will resolve once you are connected to a Waku Relay peer.
|
||||
|
||||
# Receive messages
|
||||
|
||||
To watch messages for your app, you need to register an observer on relay for your app's content topic:
|
||||
|
|
|
@ -55,6 +55,18 @@ const wakuNode = await Waku.create({
|
|||
});
|
||||
```
|
||||
|
||||
# Wait to be connected
|
||||
|
||||
When using the `bootstrap` option, it may take some times to connect to other peers.
|
||||
To ensure that you have store peers available to retrieve historical messages from,
|
||||
use the following function:
|
||||
|
||||
```js
|
||||
await waku.waitForConnectedPeer();
|
||||
```
|
||||
|
||||
The returned Promise will resolve once you are connected to a Waku Store peer.
|
||||
|
||||
# Use Protobuf
|
||||
|
||||
Waku v2 protocols use [protobuf](https://developers.google.com/protocol-buffers/) [by default](https://rfc.vac.dev/spec/10/).
|
||||
|
@ -153,19 +165,3 @@ Note that `WakuStore.queryHistory` select an available store node for you.
|
|||
However, it can only select a connected node, which is why the bootstrapping is necessary.
|
||||
It will throw an error if no store node is available.
|
||||
|
||||
## Wait to be connected
|
||||
|
||||
Depending on your dApp design, you may want to wait for a store node to be available first.
|
||||
In this case, you can listen for the [PeerStore's change protocol event](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#known-protocols-for-a-peer-change)
|
||||
to know whether any of your connected peers is a store peer:
|
||||
|
||||
```js
|
||||
import { StoreCodec } from 'js-waku';
|
||||
|
||||
// Or using a callback
|
||||
waku.libp2p.peerStore.on('change:protocols', ({ peerId, protocols }) => {
|
||||
if (protocols.includes(StoreCodec)) {
|
||||
// A Store node is available!
|
||||
}
|
||||
});
|
||||
```
|
||||
|
|
|
@ -13,12 +13,14 @@ import Websockets from 'libp2p-websockets';
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import filters from 'libp2p-websockets/src/filters';
|
||||
import { Peer } from 'libp2p/dist/src/peer-store';
|
||||
import Ping from 'libp2p/src/ping';
|
||||
import { Multiaddr, multiaddr } from 'multiaddr';
|
||||
import PeerId from 'peer-id';
|
||||
|
||||
import { getBootstrapNodes } from './discovery';
|
||||
import { WakuLightPush } from './waku_light_push';
|
||||
import { getPeersForProtocol } from './select_peer';
|
||||
import { LightPushCodec, WakuLightPush } from './waku_light_push';
|
||||
import { WakuMessage } from './waku_message';
|
||||
import { RelayCodecs, WakuRelay } from './waku_relay';
|
||||
import { RelayPingContentTopic } from './waku_relay/constants';
|
||||
|
@ -310,6 +312,46 @@ export class Waku {
|
|||
return localMultiaddr + '/p2p/' + this.libp2p.peerId.toB58String();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait to be connected to a peer. Useful when using the [[CreateOptions.bootstrap]]
|
||||
* with [[Waku.create]]. The Promise resolves only once we are connected to a
|
||||
* Store peer, Relay peer and Light Push peer.
|
||||
*/
|
||||
async waitForConnectedPeer(): Promise<void> {
|
||||
const desiredProtocols = [[StoreCodec], [LightPushCodec], RelayCodecs];
|
||||
|
||||
await Promise.all(
|
||||
desiredProtocols.map((desiredProtocolVersions) => {
|
||||
const peers = new Array<Peer>();
|
||||
desiredProtocolVersions.forEach((proto) => {
|
||||
getPeersForProtocol(this.libp2p, proto).forEach((peer) =>
|
||||
peers.push(peer)
|
||||
);
|
||||
});
|
||||
dbg('peers for ', desiredProtocolVersions, peers);
|
||||
|
||||
if (peers.length > 0) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
// No peer available for this protocol, waiting to connect to one.
|
||||
return new Promise<void>((resolve) => {
|
||||
this.libp2p.peerStore.on(
|
||||
'change:protocols',
|
||||
({ protocols: connectedPeerProtocols }) => {
|
||||
desiredProtocolVersions.forEach((desiredProto) => {
|
||||
if (connectedPeerProtocols.includes(desiredProto)) {
|
||||
dbg('Resolving for', desiredProto, connectedPeerProtocols);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private startKeepAlive(
|
||||
peerId: PeerId,
|
||||
pingPeriodSecs: number,
|
||||
|
|
Loading…
Reference in New Issue