Skip to content

Commit 2f598eb

Browse files
authoredNov 25, 2021
feat: update dht (#1009)
Changes dht creation to use factory function and updates docs BREAKING CHANGE: libp2p-kad-dht has a new event-based API which is exposed as `_dht`
1 parent 443a102 commit 2f598eb

File tree

13 files changed

+182
-67
lines changed

13 files changed

+182
-67
lines changed
 

‎.github/workflows/main.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ jobs:
1717
node-version: 14
1818
- run: npm install
1919
- run: npx aegir lint
20-
- uses: gozala/typescript-error-reporter-action@v1.0.8
2120
- run: npx aegir build
2221
- run: npx aegir dep-check
2322
- uses: ipfs/aegir/actions/bundle-size@v32.1.0
@@ -67,4 +66,4 @@ jobs:
6766
steps:
6867
- uses: actions/checkout@v2
6968
- run: npm install
70-
- run: cd node_modules/interop-libp2p && yarn && LIBP2P_JS=${GITHUB_WORKSPACE}/src/index.js npx aegir test -t node --bail -- --exit
69+
- run: npm run test:interop -- --bail -- --exit

‎doc/CONFIGURATION.md

+36-40
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
1-
#
2-
3-
- [Configuration](#configuration)
4-
- [Overview](#overview)
5-
- [Modules](#modules)
6-
- [Transport](#transport)
7-
- [Stream Multiplexing](#stream-multiplexing)
8-
- [Connection Encryption](#connection-encryption)
9-
- [Peer Discovery](#peer-discovery)
10-
- [Content Routing](#content-routing)
11-
- [Peer Routing](#peer-routing)
12-
- [DHT](#dht)
13-
- [Pubsub](#pubsub)
14-
- [Customizing libp2p](#customizing-libp2p)
15-
- [Examples](#examples)
16-
- [Basic setup](#basic-setup)
17-
- [Customizing Peer Discovery](#customizing-peer-discovery)
18-
- [Setup webrtc transport and discovery](#setup-webrtc-transport-and-discovery)
19-
- [Customizing Pubsub](#customizing-pubsub)
20-
- [Customizing DHT](#customizing-dht)
21-
- [Setup with Content and Peer Routing](#setup-with-content-and-peer-routing)
22-
- [Setup with Relay](#setup-with-relay)
23-
- [Setup with Auto Relay](#setup-with-auto-relay)
24-
- [Setup with Keychain](#setup-with-keychain)
25-
- [Configuring Dialing](#configuring-dialing)
26-
- [Configuring Connection Manager](#configuring-connection-manager)
27-
- [Configuring Transport Manager](#configuring-transport-manager)
28-
- [Configuring Metrics](#configuring-metrics)
29-
- [Configuring PeerStore](#configuring-peerstore)
30-
- [Customizing Transports](#customizing-transports)
31-
- [Configuring the NAT Manager](#configuring-the-nat-manager)
32-
- [Browser support](#browser-support)
33-
- [UPnP and NAT-PMP](#upnp-and-nat-pmp)
34-
- [Configuration examples](#configuration-examples)
1+
#
2+
3+
- [Overview](#overview)
4+
- [Modules](#modules)
5+
- [Transport](#transport)
6+
- [Stream Multiplexing](#stream-multiplexing)
7+
- [Connection Encryption](#connection-encryption)
8+
- [Peer Discovery](#peer-discovery)
9+
- [Content Routing](#content-routing)
10+
- [Peer Routing](#peer-routing)
11+
- [DHT](#dht)
12+
- [Pubsub](#pubsub)
13+
- [Customizing libp2p](#customizing-libp2p)
14+
- [Examples](#examples)
15+
- [Basic setup](#basic-setup)
16+
- [Customizing Peer Discovery](#customizing-peer-discovery)
17+
- [Setup webrtc transport and discovery](#setup-webrtc-transport-and-discovery)
18+
- [Customizing Pubsub](#customizing-pubsub)
19+
- [Customizing DHT](#customizing-dht)
20+
- [Setup with Content and Peer Routing](#setup-with-content-and-peer-routing)
21+
- [Setup with Relay](#setup-with-relay)
22+
- [Setup with Auto Relay](#setup-with-auto-relay)
23+
- [Setup with Keychain](#setup-with-keychain)
24+
- [Configuring Dialing](#configuring-dialing)
25+
- [Configuring Connection Manager](#configuring-connection-manager)
26+
- [Configuring Transport Manager](#configuring-transport-manager)
27+
- [Configuring Metrics](#configuring-metrics)
28+
- [Configuring PeerStore](#configuring-peerstore)
29+
- [Customizing Transports](#customizing-transports)
30+
- [Configuring the NAT Manager](#configuring-the-nat-manager)
31+
- [Browser support](#browser-support)
32+
- [UPnP and NAT-PMP](#upnp-and-nat-pmp)
33+
- [Configuring protocol name](#configuring-protocol-name)
34+
- [Configuration examples](#configuration-examples)
3535

3636
## Overview
3737

@@ -374,11 +374,7 @@ const node = await Libp2p.create({
374374
dht: { // The DHT options (and defaults) can be found in its documentation
375375
kBucketSize: 20,
376376
enabled: true, // This flag is required for DHT to run (disabled by default)
377-
randomWalk: {
378-
enabled: true, // Allows to disable discovery (enabled by default)
379-
interval: 300e3,
380-
timeout: 10e3
381-
}
377+
clientMode: false // Whether to run the WAN DHT in client or server mode (default: client mode)
382378
}
383379
}
384380
})
@@ -788,7 +784,7 @@ By default under nodejs libp2p will attempt to use [UPnP](https://en.wikipedia.o
788784
789785
#### Configuring protocol name
790786
791-
Changing the protocol name prefix can isolate default public network (IPFS) for custom purposes.
787+
Changing the protocol name prefix can isolate default public network (IPFS) for custom purposes.
792788
793789
```js
794790
const node = await Libp2p.create({

‎examples/delegated-routing/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"libp2p": "github:libp2p/js-libp2p#master",
88
"libp2p-delegated-content-routing": "~0.2.2",
99
"libp2p-delegated-peer-routing": "~0.2.2",
10-
"libp2p-kad-dht": "~0.14.12",
10+
"libp2p-kad-dht": "^0.26.5",
1111
"libp2p-mplex": "~0.8.5",
1212
"libp2p-secio": "~0.11.1",
1313
"libp2p-webrtc-star": "~0.15.8",

‎examples/transports/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const concat = require('it-concat')
9191
const MPLEX = require('libp2p-mplex')
9292
```
9393

94-
We are going to reuse the `createNode` function from step 1, but this time add a stream multiplexer from `libp2p-mplex`.
94+
We are going to reuse the `createNode` function from step 1, but this time add a stream multiplexer from `libp2p-mplex`.
9595
```js
9696
const createNode = async () => {
9797
const node = await Libp2p.create({

‎package.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"test:node": "aegir test -t node -f \"./test/**/*.{node,spec}.js\"",
4242
"test:browser": "aegir test -t browser",
4343
"test:examples": "cd examples && npm run test:all",
44+
"test:interop": "LIBP2P_JS=$PWD npx aegir test -t node -f ./node_modules/libp2p-interop/test/*",
4445
"prepare": "aegir build --no-bundle",
4546
"release": "aegir release -t node -t browser",
4647
"release-minor": "aegir release --type minor -t node -t browser",
@@ -142,7 +143,6 @@
142143
"buffer": "^6.0.3",
143144
"datastore-core": "^6.0.7",
144145
"delay": "^5.0.0",
145-
"interop-libp2p": "^0.4.0",
146146
"into-stream": "^7.0.0",
147147
"ipfs-http-client": "^52.0.2",
148148
"it-concat": "^2.0.0",
@@ -155,7 +155,8 @@
155155
"libp2p-floodsub": "^0.27.0",
156156
"libp2p-gossipsub": "^0.11.0",
157157
"libp2p-interfaces-compliance-tests": "^1.0.0",
158-
"libp2p-kad-dht": "^0.24.2",
158+
"libp2p-interop": "^0.5.0",
159+
"libp2p-kad-dht": "^0.26.5",
159160
"libp2p-mdns": "^0.17.0",
160161
"libp2p-mplex": "^0.10.1",
161162
"libp2p-tcp": "^0.17.0",

‎src/content-routing/index.js

+35-9
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ const {
88
requirePeers,
99
maybeLimitSource
1010
} = require('./utils')
11-
11+
const drain = require('it-drain')
1212
const merge = require('it-merge')
1313
const { pipe } = require('it-pipe')
14+
const { DHTContentRouting } = require('../dht/dht-content-routing')
1415

1516
/**
1617
* @typedef {import('peer-id')} PeerId
@@ -38,7 +39,7 @@ class ContentRouting {
3839

3940
// If we have the dht, add it to the available content routers
4041
if (this.dht && libp2p._config.dht.enabled) {
41-
this.routers.push(this.dht)
42+
this.routers.push(new DHTContentRouting(this.dht))
4243
}
4344
}
4445

@@ -91,12 +92,12 @@ class ContentRouting {
9192
* @param {number} [options.minPeers] - minimum number of peers required to successfully put
9293
* @returns {Promise<void>}
9394
*/
94-
put (key, value, options) {
95+
async put (key, value, options) {
9596
if (!this.libp2p.isStarted() || !this.dht.isStarted) {
9697
throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED)
9798
}
9899

99-
return this.dht.put(key, value, options)
100+
await drain(this.dht.put(key, value, options))
100101
}
101102

102103
/**
@@ -108,12 +109,18 @@ class ContentRouting {
108109
* @param {number} [options.timeout] - optional timeout (default: 60000)
109110
* @returns {Promise<GetData>}
110111
*/
111-
get (key, options) {
112+
async get (key, options) {
112113
if (!this.libp2p.isStarted() || !this.dht.isStarted) {
113114
throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED)
114115
}
115116

116-
return this.dht.get(key, options)
117+
for await (const event of this.dht.get(key, options)) {
118+
if (event.name === 'VALUE') {
119+
return { from: event.peerId, val: event.value }
120+
}
121+
}
122+
123+
throw errCode(new Error(messages.NOT_FOUND), codes.ERR_NOT_FOUND)
117124
}
118125

119126
/**
@@ -123,14 +130,33 @@ class ContentRouting {
123130
* @param {number} nVals
124131
* @param {Object} [options] - get options
125132
* @param {number} [options.timeout] - optional timeout (default: 60000)
126-
* @returns {Promise<GetData[]>}
127133
*/
128-
async getMany (key, nVals, options) { // eslint-disable-line require-await
134+
async * getMany (key, nVals, options) { // eslint-disable-line require-await
129135
if (!this.libp2p.isStarted() || !this.dht.isStarted) {
130136
throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED)
131137
}
132138

133-
return this.dht.getMany(key, nVals, options)
139+
if (!nVals) {
140+
return
141+
}
142+
143+
let gotValues = 0
144+
145+
for await (const event of this.dht.get(key, options)) {
146+
if (event.name === 'VALUE') {
147+
yield { from: event.peerId, val: event.value }
148+
149+
gotValues++
150+
151+
if (gotValues === nVals) {
152+
break
153+
}
154+
}
155+
}
156+
157+
if (gotValues === 0) {
158+
throw errCode(new Error(messages.NOT_FOUND), codes.ERR_NOT_FOUND)
159+
}
134160
}
135161
}
136162

‎src/dht/dht-content-routing.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
'use strict'
2+
3+
const drain = require('it-drain')
4+
5+
/**
6+
* @typedef {import('peer-id')} PeerId
7+
* @typedef {import('libp2p-interfaces/src/content-routing/types').ContentRouting} ContentRoutingModule
8+
* @typedef {import('multiformats/cid').CID} CID
9+
*/
10+
11+
/**
12+
* Wrapper class to convert events into returned values
13+
*
14+
* @implements {ContentRoutingModule}
15+
*/
16+
class DHTContentRouting {
17+
/**
18+
* @param {import('libp2p-kad-dht').DHT} dht
19+
*/
20+
constructor (dht) {
21+
this._dht = dht
22+
}
23+
24+
/**
25+
* @param {CID} cid
26+
*/
27+
async provide (cid) {
28+
await drain(this._dht.provide(cid))
29+
}
30+
31+
/**
32+
* @param {CID} cid
33+
* @param {*} options
34+
*/
35+
async * findProviders (cid, options) {
36+
for await (const event of this._dht.findProviders(cid, options)) {
37+
if (event.name === 'PROVIDER') {
38+
yield * event.providers
39+
}
40+
}
41+
}
42+
}
43+
44+
module.exports = { DHTContentRouting }

‎src/dht/dht-peer-routing.js

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict'
2+
3+
const errCode = require('err-code')
4+
const { messages, codes } = require('../errors')
5+
6+
/**
7+
* @typedef {import('peer-id')} PeerId
8+
* @typedef {import('libp2p-interfaces/src/peer-routing/types').PeerRouting} PeerRoutingModule
9+
*/
10+
11+
/**
12+
* Wrapper class to convert events into returned values
13+
*
14+
* @implements {PeerRoutingModule}
15+
*/
16+
class DHTPeerRouting {
17+
/**
18+
* @param {import('libp2p-kad-dht').DHT} dht
19+
*/
20+
constructor (dht) {
21+
this._dht = dht
22+
}
23+
24+
/**
25+
* @param {PeerId} peerId
26+
* @param {any} options
27+
*/
28+
async findPeer (peerId, options = {}) {
29+
for await (const event of this._dht.findPeer(peerId, options)) {
30+
if (event.name === 'FINAL_PEER') {
31+
return event.peer
32+
}
33+
}
34+
35+
throw errCode(new Error(messages.NOT_FOUND), codes.ERR_NOT_FOUND)
36+
}
37+
38+
/**
39+
* @param {Uint8Array} key
40+
* @param {any} options
41+
*/
42+
async * getClosestPeers (key, options = {}) {
43+
for await (const event of this._dht.getClosestPeers(key, options)) {
44+
if (event.name === 'PEER_RESPONSE') {
45+
yield * event.closer
46+
}
47+
}
48+
}
49+
}
50+
51+
module.exports = { DHTPeerRouting }

‎src/errors.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
exports.messages = {
44
NOT_STARTED_YET: 'The libp2p node is not started yet',
55
DHT_DISABLED: 'DHT is not available',
6-
CONN_ENCRYPTION_REQUIRED: 'At least one connection encryption module is required'
6+
CONN_ENCRYPTION_REQUIRED: 'At least one connection encryption module is required',
7+
NOT_FOUND: 'Not found'
78
}
89

910
exports.codes = {
@@ -29,6 +30,7 @@ exports.codes = {
2930
ERR_INVALID_PARAMETERS: 'ERR_INVALID_PARAMETERS',
3031
ERR_INVALID_PEER: 'ERR_INVALID_PEER',
3132
ERR_MUXER_UNAVAILABLE: 'ERR_MUXER_UNAVAILABLE',
33+
ERR_NOT_FOUND: 'ERR_NOT_FOUND',
3234
ERR_TIMEOUT: 'ERR_TIMEOUT',
3335
ERR_TRANSPORT_UNAVAILABLE: 'ERR_TRANSPORT_UNAVAILABLE',
3436
ERR_TRANSPORT_DIAL_FAILED: 'ERR_TRANSPORT_DIAL_FAILED',

‎src/index.js

+3-8
Original file line numberDiff line numberDiff line change
@@ -301,14 +301,9 @@ class Libp2p extends EventEmitter {
301301
// dht provided components (peerRouting, contentRouting, dht)
302302
if (this._modules.dht) {
303303
const DHT = this._modules.dht
304-
// @ts-ignore Object is not constructable
305-
this._dht = new DHT({
304+
// @ts-ignore TODO: types need fixing - DHT is an `object` which has no `create` method
305+
this._dht = DHT.create({
306306
libp2p: this,
307-
dialer: this.dialer,
308-
peerId: this.peerId,
309-
peerStore: this.peerStore,
310-
registrar: this.registrar,
311-
datastore: this.datastore,
312307
...this._config.dht
313308
})
314309
}
@@ -624,7 +619,7 @@ class Libp2p extends EventEmitter {
624619

625620
// DHT subsystem
626621
if (this._config.dht.enabled) {
627-
this._dht && this._dht.start()
622+
this._dht && await this._dht.start()
628623

629624
// TODO: this should be modified once random-walk is used as
630625
// the other discovery modules

‎src/nat-manager.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class NatManager {
114114
const client = this._getClient()
115115
const publicIp = this._externalIp || await client.externalIp()
116116

117-
// @ts-ignore isPrivate has no call signatures
117+
// @ts-expect-error types are wrong
118118
if (isPrivateIp(publicIp)) {
119119
throw new Error(`${publicIp} is private - please set config.nat.externalIp to an externally routable IP or ensure you are not behind a double NAT`)
120120
}

‎src/peer-routing.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const {
2121
clearDelayedInterval
2222
// @ts-ignore module with no types
2323
} = require('set-delayed-interval')
24+
const { DHTPeerRouting } = require('./dht/dht-peer-routing')
2425

2526
/**
2627
* @typedef {import('peer-id')} PeerId
@@ -51,7 +52,7 @@ class PeerRouting {
5152

5253
// If we have the dht, add it to the available peer routers
5354
if (libp2p._dht && libp2p._config.dht.enabled) {
54-
this._routers.push(libp2p._dht)
55+
this._routers.push(new DHTPeerRouting(libp2p._dht))
5556
}
5657

5758
this._refreshManagerOptions = libp2p._options.peerRouting.refreshManager

‎test/ts-use/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"libp2p-delegated-peer-routing": "^0.10.0",
1111
"libp2p-gossipsub": "^0.9.0",
1212
"libp2p-interfaces": "^1.0.1",
13-
"libp2p-kad-dht": "^0.23.1",
13+
"libp2p-kad-dht": "^0.26.5",
1414
"libp2p-mplex": "^0.10.4",
1515
"@chainsafe/libp2p-noise": "^4.1.0",
1616
"libp2p-record": "^0.10.4",

0 commit comments

Comments
 (0)
Please sign in to comment.