mirror of https://github.com/waku-org/js-waku.git
Merge pull request #262 from status-im/bootstrap
This commit is contained in:
commit
5be718ffdb
|
@ -47,6 +47,7 @@
|
|||
"livechat",
|
||||
"mkdir",
|
||||
"multiaddr",
|
||||
"multiaddresses",
|
||||
"multiaddrs",
|
||||
"multicodecs",
|
||||
"mplex",
|
||||
|
|
|
@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- New `bootstrap` option for `Waku.create` to easily connect to Waku nodes upon start up.
|
||||
|
||||
### Changed
|
||||
- Renamed `discover.getStatusFleetNodes` to `discovery.getBootstrapNodes`;
|
||||
Changed the API to allow retrieval of bootstrap nodes from other sources.
|
||||
|
||||
### Removed
|
||||
- Examples (cli-chat): The focus of this library is Web environment;
|
||||
Several examples now cover usage of Waku Relay and Waku Store making cli-chat example obsolete;
|
||||
|
|
27
README.md
27
README.md
|
@ -32,32 +32,7 @@ npm install js-waku
|
|||
```ts
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
const waku = await Waku.create();
|
||||
```
|
||||
|
||||
### Connect to a new peer
|
||||
|
||||
```ts
|
||||
// Directly dial a new peer
|
||||
await waku.dial('/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ');
|
||||
|
||||
// Or, add peer to address book so it auto dials in the background
|
||||
waku.addPeerToAddressBook(
|
||||
'16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ',
|
||||
['/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss']
|
||||
);
|
||||
```
|
||||
|
||||
You can also use `getStatusFleetNodes` to connect to nodes run by Status:
|
||||
|
||||
```ts
|
||||
import { getStatusFleetNodes } from 'js-waku';
|
||||
|
||||
getStatusFleetNodes().then((nodes) => {
|
||||
nodes.forEach((addr) => {
|
||||
waku.dial(addr);
|
||||
});
|
||||
});
|
||||
const waku = await Waku.create({ bootstrap: true });
|
||||
```
|
||||
|
||||
### Listen for messages
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { Waku, WakuMessage } from 'js-waku';
|
||||
import { DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||
import { validatePublicKeyMessage } from './crypto';
|
||||
import { Message } from './messaging/Messages';
|
||||
|
@ -9,14 +9,7 @@ export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto';
|
|||
export const DirectMessageContentTopic = '/eth-dm/1/direct-message/proto';
|
||||
|
||||
export async function initWaku(): Promise<Waku> {
|
||||
const waku = await Waku.create({});
|
||||
|
||||
// Dial all nodes it can find
|
||||
getStatusFleetNodes().then((nodes) => {
|
||||
nodes.forEach((addr) => {
|
||||
waku.dial(addr);
|
||||
});
|
||||
});
|
||||
const waku = await Waku.create({ bootstrap: true });
|
||||
|
||||
// Wait to be connected to at least one peer
|
||||
await new Promise((resolve, reject) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { Waku, WakuMessage } from 'js-waku';
|
||||
import { DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||
import { validatePublicKeyMessage } from './crypto';
|
||||
import { Message } from './messaging/Messages';
|
||||
|
@ -11,14 +11,7 @@ export const DirectMessageContentTopic =
|
|||
'/eth-pm-wallet/1/direct-message/proto';
|
||||
|
||||
export async function initWaku(): Promise<Waku> {
|
||||
const waku = await Waku.create({});
|
||||
|
||||
// Dial all nodes it can find
|
||||
getStatusFleetNodes().then((nodes) => {
|
||||
nodes.forEach((addr) => {
|
||||
waku.dial(addr);
|
||||
});
|
||||
});
|
||||
const waku = await Waku.create({ bootstrap: true });
|
||||
|
||||
// Wait to be connected to at least one peer
|
||||
await new Promise((resolve, reject) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import './App.css';
|
||||
import { getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import protons from 'protons';
|
||||
|
||||
|
@ -96,8 +96,12 @@ function App() {
|
|||
export default App;
|
||||
|
||||
async function bootstrapWaku(waku) {
|
||||
const nodes = await getStatusFleetNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
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) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import './App.css';
|
||||
import { getStatusFleetNodes, StoreCodec, Waku } from 'js-waku';
|
||||
import { StoreCodec, Waku } from 'js-waku';
|
||||
import * as React from 'react';
|
||||
import protons from 'protons';
|
||||
|
||||
|
@ -17,9 +17,6 @@ function App() {
|
|||
const [waku, setWaku] = React.useState(undefined);
|
||||
const [wakuStatus, setWakuStatus] = React.useState('None');
|
||||
const [messages, setMessages] = React.useState([]);
|
||||
// Set to true when Waku connects to a store node
|
||||
// it does not reflect whether we then disconnected from said node.
|
||||
const [connectedToStore, setConnectedToStore] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!!waku) return;
|
||||
|
@ -27,20 +24,15 @@ function App() {
|
|||
|
||||
setWakuStatus('Starting');
|
||||
|
||||
Waku.create().then((waku) => {
|
||||
Waku.create({ bootstrap: true }).then((waku) => {
|
||||
setWaku(waku);
|
||||
setWakuStatus('Connecting');
|
||||
bootstrapWaku(waku).then(() => {
|
||||
setWakuStatus('Ready');
|
||||
});
|
||||
});
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
// This is superfluous as the try/catch block would catch the failure if
|
||||
// we are indeed not connected to any store node.
|
||||
if (!connectedToStore) return;
|
||||
if (wakuStatus !== 'Connected to Store') return;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
waku.store
|
||||
|
@ -57,33 +49,27 @@ function App() {
|
|||
}, 10000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [waku, connectedToStore]);
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!waku) return;
|
||||
|
||||
// We do not handle disconnection/re-connection in this example
|
||||
if (connectedToStore) return;
|
||||
if (wakuStatus === 'Connected to Store') return;
|
||||
|
||||
const isStoreNode = ({ protocols }) => {
|
||||
if (protocols.includes(StoreCodec)) {
|
||||
// We are now connected to a store node
|
||||
setConnectedToStore(true);
|
||||
setWakuStatus('Connected to Store');
|
||||
}
|
||||
};
|
||||
|
||||
// This demonstrates how to wait for a connection to a store node.
|
||||
//
|
||||
// This is only for demonstration purposes. It is not really needed in this
|
||||
// example app as we query the store node every 10s and catch if it fails.
|
||||
// Meaning if we are not connected to a store node, then it just fails and
|
||||
// we try again 10s later.
|
||||
waku.libp2p.peerStore.on('change:protocols', isStoreNode);
|
||||
|
||||
return () => {
|
||||
waku.libp2p.peerStore.removeListener('change:protocols', isStoreNode);
|
||||
};
|
||||
}, [waku, connectedToStore]);
|
||||
}, [waku, wakuStatus]);
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
|
@ -100,11 +86,6 @@ function App() {
|
|||
|
||||
export default App;
|
||||
|
||||
async function bootstrapWaku(waku) {
|
||||
const nodes = await getStatusFleetNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
}
|
||||
|
||||
function decodeMessage(wakuMessage) {
|
||||
if (!wakuMessage.payload) return;
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@ import { useEffect, useReducer, useState } from 'react';
|
|||
import './App.css';
|
||||
import {
|
||||
Direction,
|
||||
Environment,
|
||||
getStatusFleetNodes,
|
||||
getBootstrapNodes,
|
||||
StoreCodec,
|
||||
Waku,
|
||||
WakuMessage,
|
||||
|
@ -182,16 +181,10 @@ async function initWaku(setter: (waku: Waku) => void) {
|
|||
},
|
||||
},
|
||||
},
|
||||
bootstrap: getBootstrapNodes.bind({}, selectFleetEnv()),
|
||||
});
|
||||
|
||||
setter(waku);
|
||||
|
||||
const nodes = await getStatusFleetNodes(selectFleetEnv());
|
||||
await Promise.all(
|
||||
nodes.map((addr) => {
|
||||
return waku.dial(addr);
|
||||
})
|
||||
);
|
||||
} catch (e) {
|
||||
console.log('Issue starting waku ', e);
|
||||
}
|
||||
|
@ -200,9 +193,9 @@ async function initWaku(setter: (waku: Waku) => void) {
|
|||
function selectFleetEnv() {
|
||||
// Works with react-scripts
|
||||
if (process?.env?.NODE_ENV === 'development') {
|
||||
return Environment.Test;
|
||||
return ['fleets', 'wakuv2.test', 'waku-websocket'];
|
||||
} else {
|
||||
return Environment.Prod;
|
||||
return ['fleets', 'wakuv2.prod', 'waku-websocket'];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,16 +82,18 @@ function App() {
|
|||
# Connect to Other Peers
|
||||
|
||||
The Waku instance needs to connect to other peers to communicate with the network.
|
||||
First, create `bootstrapWaku` to connect to the Status fleet:
|
||||
First, create `bootstrapWaku` to connect to Waku bootstrap nodes:
|
||||
|
||||
```js
|
||||
import { getStatusFleetNodes } from 'js-waku';
|
||||
import { getBootstrapNodes } from 'js-waku';
|
||||
|
||||
async function bootstrapWaku(waku) {
|
||||
// Retrieve node addresses from https://fleets.status.im/
|
||||
const nodes = await getStatusFleetNodes();
|
||||
// Connect to the nodes
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
try {
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
} catch (e) {
|
||||
console.error('Failed to bootstrap to Waku network');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -34,9 +34,10 @@ You are free to choose any method to bootstrap and DappConnect will ship with ne
|
|||
For now, the easiest way is to connect to Status' Waku fleet:
|
||||
|
||||
```js
|
||||
import { getStatusFleetNodes } from 'js-waku';
|
||||
const nodes = await getStatusFleetNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
import { getBootstrapNodes } from 'js-waku';
|
||||
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
```
|
||||
|
||||
# Receive messages
|
||||
|
@ -177,7 +178,7 @@ Feel free to check out other [guides](menu.md) or [examples](/examples/examples.
|
|||
Here is the final code:
|
||||
|
||||
```js
|
||||
import { getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import { getBootstrapNodes, Waku, WakuMessage } from 'js-waku';
|
||||
import protons from 'protons';
|
||||
|
||||
const proto = protons(`
|
||||
|
@ -189,7 +190,7 @@ message SimpleChatMessage {
|
|||
|
||||
const wakuNode = await Waku.create();
|
||||
|
||||
const nodes = await getStatusFleetNodes();
|
||||
const nodes = await getBootstrapNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
|
||||
const processIncomingMessage = (wakuMessage) => {
|
||||
|
|
|
@ -38,20 +38,21 @@ 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 other methods to bootstrap and DappConnect will ship with new bootstrap mechanisms 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 { getStatusFleetNodes } from 'js-waku';
|
||||
const nodes = await getStatusFleetNodes();
|
||||
await Promise.all(nodes.map((addr) => waku.dial(addr)));
|
||||
import { Waku } from 'js-waku';
|
||||
|
||||
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'
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
# Use Protobuf
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
"it-length-prefixed": "^5.0.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"libp2p": "^0.32.0",
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
|
@ -15055,6 +15056,39 @@
|
|||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libp2p-bootstrap": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-bootstrap/-/libp2p-bootstrap-0.13.0.tgz",
|
||||
"integrity": "sha512-8sXEZrikY+chKvMorkvOi9E/v9GvwsYr9DAEfzQZrOKQZByqhan1aXQKWrSpc4AxEv5/UopRzu1P47bkOi8wdw==",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.1",
|
||||
"mafmt": "^10.0.0",
|
||||
"multiaddr": "^10.0.0",
|
||||
"peer-id": "^0.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libp2p-bootstrap/node_modules/peer-id": {
|
||||
"version": "0.15.2",
|
||||
"resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.15.2.tgz",
|
||||
"integrity": "sha512-3OMbup76F28gKsQK4rGheEJHwosnJGe2+Obsf1xFaS9DpUaG9/JK0rtguWVLbrkxPclsCceci8g3/ulg8jsORA==",
|
||||
"dependencies": {
|
||||
"class-is": "^1.1.0",
|
||||
"libp2p-crypto": "^0.19.0",
|
||||
"minimist": "^1.2.5",
|
||||
"multiformats": "^9.3.0",
|
||||
"protobufjs": "^6.10.2",
|
||||
"uint8arrays": "^2.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"peer-id": "src/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/libp2p-crypto": {
|
||||
"version": "0.19.6",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.19.6.tgz",
|
||||
|
@ -36622,6 +36656,32 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"libp2p-bootstrap": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-bootstrap/-/libp2p-bootstrap-0.13.0.tgz",
|
||||
"integrity": "sha512-8sXEZrikY+chKvMorkvOi9E/v9GvwsYr9DAEfzQZrOKQZByqhan1aXQKWrSpc4AxEv5/UopRzu1P47bkOi8wdw==",
|
||||
"requires": {
|
||||
"debug": "^4.3.1",
|
||||
"mafmt": "^10.0.0",
|
||||
"multiaddr": "^10.0.0",
|
||||
"peer-id": "^0.15.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"peer-id": {
|
||||
"version": "0.15.2",
|
||||
"resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.15.2.tgz",
|
||||
"integrity": "sha512-3OMbup76F28gKsQK4rGheEJHwosnJGe2+Obsf1xFaS9DpUaG9/JK0rtguWVLbrkxPclsCceci8g3/ulg8jsORA==",
|
||||
"requires": {
|
||||
"class-is": "^1.1.0",
|
||||
"libp2p-crypto": "^0.19.0",
|
||||
"minimist": "^1.2.5",
|
||||
"multiformats": "^9.3.0",
|
||||
"protobufjs": "^6.10.2",
|
||||
"uint8arrays": "^2.0.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"libp2p-crypto": {
|
||||
"version": "0.19.6",
|
||||
"resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.19.6.tgz",
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
"it-length-prefixed": "^5.0.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"libp2p": "^0.32.0",
|
||||
"libp2p-bootstrap": "^0.13.0",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-mplex": "^0.10.4",
|
||||
"libp2p-noise": "^4.0.0",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export { getStatusFleetNodes, Environment, Protocol } from './lib/discover';
|
||||
export { getBootstrapNodes } from './lib/discovery';
|
||||
|
||||
export * as utils from './lib/utils';
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
/**
|
||||
* Returns multiaddrs (inc. ip) of nim-waku nodes ran by Status.
|
||||
* Used as a temporary discovery helper until more parties run their own nodes.
|
||||
*/
|
||||
import axios from 'axios';
|
||||
|
||||
export enum Protocol {
|
||||
websocket = 'websocket',
|
||||
tcp = 'tcp',
|
||||
}
|
||||
|
||||
export enum Environment {
|
||||
Test = 'test',
|
||||
Prod = 'prod',
|
||||
}
|
||||
|
||||
export async function getStatusFleetNodes(
|
||||
env: Environment = Environment.Prod,
|
||||
protocol: Protocol = Protocol.websocket
|
||||
): Promise<string[]> {
|
||||
const res = await axios.get('https://fleets.status.im/', {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
const wakuFleet = res.data.fleets[`wakuv2.${env}`];
|
||||
|
||||
switch (protocol) {
|
||||
case Protocol.tcp:
|
||||
return Object.values(wakuFleet['waku']);
|
||||
default:
|
||||
return Object.values(wakuFleet['waku-websocket']);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
import axios from 'axios';
|
||||
import debug from 'debug';
|
||||
|
||||
const dbg = debug('waku:discovery');
|
||||
|
||||
/**
|
||||
* GET list of nodes from remote HTTP host.
|
||||
*
|
||||
* Default behaviour is to return nodes hosted by Status.
|
||||
*
|
||||
* @param path The property path to access the node list. The result should be
|
||||
* a string, a string array or an object. If the result is an object then the
|
||||
* values of the objects are used as multiaddresses. For example, if the GET
|
||||
* request returns `{ foo: { bar: [address1, address2] } }` then `path` should be
|
||||
* `[ "foo", "bar" ]`.
|
||||
* @param url Remote host containing bootstrap peers in JSON format.
|
||||
*
|
||||
* @returns An array of multiaddresses.
|
||||
* @throws If the remote host is unreachable or the response cannot be parsed
|
||||
* according to the passed _path_.
|
||||
*/
|
||||
export async function getBootstrapNodes(
|
||||
path: string[] = ['fleets', 'wakuv2.prod', 'waku-websocket'],
|
||||
url = 'https://fleets.status.im/'
|
||||
): Promise<string[]> {
|
||||
const res = await axios.get(url, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
let nodes = res.data;
|
||||
|
||||
for (const prop of path) {
|
||||
if (nodes[prop] === undefined) {
|
||||
dbg(
|
||||
`Failed to retrieve bootstrap nodes: ${prop} does not exist on `,
|
||||
nodes
|
||||
);
|
||||
throw `Failed to retrieve bootstrap nodes: ${prop} does not exist on ${JSON.stringify(
|
||||
nodes
|
||||
)}`;
|
||||
}
|
||||
nodes = nodes[prop];
|
||||
}
|
||||
|
||||
if (Array.isArray(nodes)) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
if (typeof nodes === 'string') {
|
||||
return [nodes];
|
||||
}
|
||||
|
||||
if (typeof nodes === 'object') {
|
||||
return Object.values(nodes);
|
||||
}
|
||||
|
||||
throw `Failed to retrieve bootstrap nodes: response format is not supported: ${JSON.stringify(
|
||||
nodes
|
||||
)}`;
|
||||
}
|
|
@ -2,20 +2,98 @@ import { expect } from 'chai';
|
|||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import TCP from 'libp2p-tcp';
|
||||
import PeerId from 'peer-id';
|
||||
|
||||
import { makeLogFileName, NimWaku, NOISE_KEY_1 } from '../test_utils/';
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
NOISE_KEY_2,
|
||||
} from '../test_utils/';
|
||||
|
||||
import { Waku } from './waku';
|
||||
|
||||
describe('Waku Dial', function () {
|
||||
let waku: Waku;
|
||||
let waku2: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku ? nimWaku.stop() : null;
|
||||
waku ? await waku.stop() : null;
|
||||
|
||||
await Promise.all([waku ? waku.stop() : null, waku2 ? waku2.stop() : null]);
|
||||
});
|
||||
|
||||
describe('Bootstrap', function () {
|
||||
it('Passing an array', async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
waku = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
addresses: { listen: ['/ip4/0.0.0.0/tcp/0'] },
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
});
|
||||
|
||||
const multiAddrWithId = waku.getLocalMultiaddrWithID();
|
||||
|
||||
waku2 = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: {
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
bootstrap: [multiAddrWithId],
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
|
||||
expect(connectedPeerID.toB58String()).to.eq(
|
||||
waku2.libp2p.peerId.toB58String()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Bootstrap', function () {
|
||||
it('Passing a function', async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
waku = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
addresses: { listen: ['/ip4/0.0.0.0/tcp/0'] },
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
});
|
||||
|
||||
const multiAddrWithId = waku.getLocalMultiaddrWithID();
|
||||
|
||||
waku2 = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: {
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
bootstrap: () => {
|
||||
return [multiAddrWithId];
|
||||
},
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
|
||||
expect(connectedPeerID.toB58String()).to.eq(
|
||||
waku2.libp2p.peerId.toB58String()
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Interop: Nim', function () {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import debug from 'debug';
|
||||
import Libp2p, { Connection, Libp2pModules, Libp2pOptions } from 'libp2p';
|
||||
import Bootstrap from 'libp2p-bootstrap';
|
||||
import { MuxedStream } from 'libp2p-interfaces/dist/src/stream-muxer/types';
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
|
@ -15,6 +17,7 @@ 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 { WakuMessage } from './waku_message';
|
||||
import { RelayCodecs, WakuRelay } from './waku_relay';
|
||||
|
@ -23,8 +26,10 @@ import { StoreCodec, WakuStore } from './waku_store';
|
|||
|
||||
const websocketsTransportKey = Websockets.prototype[Symbol.toStringTag];
|
||||
|
||||
const DefaultPingKeepAliveValueSecs = 0;
|
||||
const DefaultRelayKeepAliveValueSecs = 5 * 60;
|
||||
export const DefaultPingKeepAliveValueSecs = 0;
|
||||
export const DefaultRelayKeepAliveValueSecs = 5 * 60;
|
||||
|
||||
const dbg = debug('waku:waku');
|
||||
|
||||
export interface CreateOptions {
|
||||
/**
|
||||
|
@ -71,6 +76,18 @@ export interface CreateOptions {
|
|||
* This is only used for test purposes to not run out of entropy during CI runs.
|
||||
*/
|
||||
staticNoiseKey?: bytes;
|
||||
/**
|
||||
* Use libp2p-bootstrap to discover and connect to new nodes.
|
||||
*
|
||||
* You can pass:
|
||||
* - `true` to use {@link getBootstrapNodes},
|
||||
* - an array of multiaddresses,
|
||||
* - a function that returns an array of multiaddresses (or Promise of).
|
||||
*
|
||||
* Note: It overrides any other peerDiscovery modules that may have been set via
|
||||
* {@link CreateOptions.libp2p}.
|
||||
*/
|
||||
bootstrap?: boolean | string[] | (() => string[] | Promise<string[]>);
|
||||
}
|
||||
|
||||
export class Waku {
|
||||
|
@ -161,6 +178,40 @@ export class Waku {
|
|||
pubsub: WakuRelay,
|
||||
});
|
||||
|
||||
if (options?.bootstrap) {
|
||||
let bootstrap: undefined | (() => string[] | Promise<string[]>);
|
||||
|
||||
if (options.bootstrap === true) {
|
||||
bootstrap = getBootstrapNodes;
|
||||
} else if (Array.isArray(options.bootstrap)) {
|
||||
bootstrap = (): string[] => {
|
||||
return options.bootstrap as string[];
|
||||
};
|
||||
} else if (typeof options.bootstrap === 'function') {
|
||||
bootstrap = options.bootstrap;
|
||||
}
|
||||
|
||||
if (bootstrap !== undefined) {
|
||||
// Note: this overrides any other peer discover
|
||||
libp2pOpts.modules = Object.assign(libp2pOpts.modules, {
|
||||
peerDiscovery: [Bootstrap],
|
||||
});
|
||||
|
||||
try {
|
||||
const list = await bootstrap();
|
||||
|
||||
libp2pOpts.config.peerDiscovery = {
|
||||
[Bootstrap.tag]: {
|
||||
list,
|
||||
enabled: true,
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
dbg('Failed to retrieve bootstrap nodes', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: modules property is correctly set thanks to voodoo
|
||||
const libp2p = await Libp2p.create(libp2pOpts);
|
||||
|
|
Loading…
Reference in New Issue