libp2p 0.44.0 → 0.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.min.js +30 -30
- package/dist/src/address-manager/index.d.ts +8 -4
- package/dist/src/address-manager/index.d.ts.map +1 -1
- package/dist/src/address-manager/index.js +37 -6
- package/dist/src/address-manager/index.js.map +1 -1
- package/dist/src/address-manager/utils.d.ts +2 -0
- package/dist/src/address-manager/utils.d.ts.map +1 -0
- package/dist/src/address-manager/utils.js +12 -0
- package/dist/src/address-manager/utils.js.map +1 -0
- package/dist/src/autonat/constants.d.ts +16 -2
- package/dist/src/autonat/constants.d.ts.map +1 -1
- package/dist/src/autonat/constants.js +16 -2
- package/dist/src/autonat/constants.js.map +1 -1
- package/dist/src/autonat/index.d.ts +12 -33
- package/dist/src/autonat/index.d.ts.map +1 -1
- package/dist/src/autonat/index.js +36 -30
- package/dist/src/autonat/index.js.map +1 -1
- package/dist/src/circuit-relay/server/advert-service.d.ts.map +1 -1
- package/dist/src/circuit-relay/server/advert-service.js +2 -2
- package/dist/src/circuit-relay/server/advert-service.js.map +1 -1
- package/dist/src/circuit-relay/server/index.d.ts.map +1 -1
- package/dist/src/circuit-relay/server/index.js +10 -3
- package/dist/src/circuit-relay/server/index.js.map +1 -1
- package/dist/src/circuit-relay/transport/discovery.d.ts.map +1 -1
- package/dist/src/circuit-relay/transport/discovery.js +4 -2
- package/dist/src/circuit-relay/transport/discovery.js.map +1 -1
- package/dist/src/circuit-relay/transport/index.d.ts +3 -0
- package/dist/src/circuit-relay/transport/index.d.ts.map +1 -1
- package/dist/src/circuit-relay/transport/index.js +6 -4
- package/dist/src/circuit-relay/transport/index.js.map +1 -1
- package/dist/src/circuit-relay/transport/listener.d.ts.map +1 -1
- package/dist/src/circuit-relay/transport/listener.js +30 -26
- package/dist/src/circuit-relay/transport/listener.js.map +1 -1
- package/dist/src/circuit-relay/transport/reservation-store.d.ts +5 -4
- package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
- package/dist/src/circuit-relay/transport/reservation-store.js +37 -30
- package/dist/src/circuit-relay/transport/reservation-store.js.map +1 -1
- package/dist/src/components.d.ts +6 -63
- package/dist/src/components.d.ts.map +1 -1
- package/dist/src/components.js +60 -164
- package/dist/src/components.js.map +1 -1
- package/dist/src/config/connection-gater.browser.d.ts +8 -0
- package/dist/src/config/connection-gater.browser.d.ts.map +1 -0
- package/dist/src/config/connection-gater.browser.js +27 -0
- package/dist/src/config/connection-gater.browser.js.map +1 -0
- package/dist/src/config/connection-gater.d.ts +6 -0
- package/dist/src/config/connection-gater.d.ts.map +1 -0
- package/dist/src/config/connection-gater.js +18 -0
- package/dist/src/config/connection-gater.js.map +1 -0
- package/dist/src/config.d.ts +2 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +0 -62
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/auto-dial.d.ts +3 -0
- package/dist/src/connection-manager/auto-dial.d.ts.map +1 -1
- package/dist/src/connection-manager/auto-dial.js +36 -13
- package/dist/src/connection-manager/auto-dial.js.map +1 -1
- package/dist/src/connection-manager/connection-pruner.d.ts +4 -0
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
- package/dist/src/connection-manager/connection-pruner.js +23 -8
- package/dist/src/connection-manager/connection-pruner.js.map +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts +2 -1
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
- package/dist/src/connection-manager/dial-queue.js +36 -14
- package/dist/src/connection-manager/dial-queue.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +8 -7
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +23 -34
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/content-routing/index.d.ts +0 -10
- package/dist/src/content-routing/index.d.ts.map +1 -1
- package/dist/src/content-routing/index.js +7 -42
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/content-routing/utils.d.ts.map +1 -1
- package/dist/src/content-routing/utils.js +3 -1
- package/dist/src/content-routing/utils.js.map +1 -1
- package/dist/src/fetch/index.d.ts +13 -35
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/fetch/index.js +7 -9
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/identify/identify.d.ts +53 -0
- package/dist/src/identify/identify.d.ts.map +1 -0
- package/dist/src/identify/identify.js +405 -0
- package/dist/src/identify/identify.js.map +1 -0
- package/dist/src/identify/index.d.ts +12 -58
- package/dist/src/identify/index.d.ts.map +1 -1
- package/dist/src/identify/index.js +5 -388
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/index.d.ts +13 -68
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/insecure/index.js.map +1 -1
- package/dist/src/libp2p.d.ts +11 -42
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +137 -196
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/peer-routing.d.ts +1 -38
- package/dist/src/peer-routing.d.ts.map +1 -1
- package/dist/src/peer-routing.js +0 -59
- package/dist/src/peer-routing.js.map +1 -1
- package/dist/src/ping/constants.d.ts +4 -0
- package/dist/src/ping/constants.d.ts.map +1 -1
- package/dist/src/ping/constants.js +10 -0
- package/dist/src/ping/constants.js.map +1 -1
- package/dist/src/ping/index.d.ts +10 -27
- package/dist/src/ping/index.d.ts.map +1 -1
- package/dist/src/ping/index.js +18 -21
- package/dist/src/ping/index.js.map +1 -1
- package/dist/src/registrar.d.ts +5 -2
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/registrar.js +27 -25
- package/dist/src/registrar.js.map +1 -1
- package/dist/src/transport-manager.d.ts +11 -4
- package/dist/src/transport-manager.d.ts.map +1 -1
- package/dist/src/transport-manager.js +19 -10
- package/dist/src/transport-manager.js.map +1 -1
- package/dist/src/upgrader.d.ts +15 -10
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +39 -48
- package/dist/src/upgrader.js.map +1 -1
- package/dist/src/upnp-nat/index.d.ts +42 -0
- package/dist/src/upnp-nat/index.d.ts.map +1 -0
- package/dist/src/{nat-manager.js → upnp-nat/index.js} +11 -7
- package/dist/src/upnp-nat/index.js.map +1 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/typedoc-urls.json +25 -10
- package/package.json +61 -45
- package/src/address-manager/index.ts +50 -8
- package/src/address-manager/utils.ts +14 -0
- package/src/autonat/constants.ts +17 -2
- package/src/autonat/index.ts +53 -45
- package/src/circuit-relay/server/advert-service.ts +2 -2
- package/src/circuit-relay/server/index.ts +11 -3
- package/src/circuit-relay/transport/discovery.ts +5 -3
- package/src/circuit-relay/transport/index.ts +9 -4
- package/src/circuit-relay/transport/listener.ts +38 -28
- package/src/circuit-relay/transport/reservation-store.ts +34 -20
- package/src/components.ts +71 -234
- package/src/config/connection-gater.browser.ts +31 -0
- package/src/config/connection-gater.ts +19 -0
- package/src/config.ts +3 -64
- package/src/connection-manager/auto-dial.ts +44 -15
- package/src/connection-manager/connection-pruner.ts +28 -8
- package/src/connection-manager/dial-queue.ts +41 -21
- package/src/connection-manager/index.ts +31 -43
- package/src/content-routing/index.ts +7 -55
- package/src/content-routing/utils.ts +3 -1
- package/src/fetch/index.ts +51 -14
- package/src/identify/identify.ts +518 -0
- package/src/identify/index.ts +17 -507
- package/src/index.ts +14 -77
- package/src/insecure/index.ts +4 -4
- package/src/libp2p.ts +139 -260
- package/src/peer-routing.ts +1 -101
- package/src/ping/constants.ts +11 -0
- package/src/ping/index.ts +32 -28
- package/src/registrar.ts +31 -27
- package/src/transport-manager.ts +27 -13
- package/src/upgrader.ts +62 -58
- package/src/{nat-manager.ts → upnp-nat/index.ts} +16 -17
- package/src/version.ts +1 -1
- package/dist/src/dht/dht-content-routing.d.ts +0 -17
- package/dist/src/dht/dht-content-routing.d.ts.map +0 -1
- package/dist/src/dht/dht-content-routing.js +0 -32
- package/dist/src/dht/dht-content-routing.js.map +0 -1
- package/dist/src/dht/dht-peer-routing.d.ts +0 -15
- package/dist/src/dht/dht-peer-routing.d.ts.map +0 -1
- package/dist/src/dht/dht-peer-routing.js +0 -26
- package/dist/src/dht/dht-peer-routing.js.map +0 -1
- package/dist/src/dht/dummy-dht.d.ts +0 -20
- package/dist/src/dht/dummy-dht.d.ts.map +0 -1
- package/dist/src/dht/dummy-dht.js +0 -46
- package/dist/src/dht/dummy-dht.js.map +0 -1
- package/dist/src/nat-manager.d.ts +0 -74
- package/dist/src/nat-manager.d.ts.map +0 -1
- package/dist/src/nat-manager.js.map +0 -1
- package/dist/src/peer-record-updater.d.ts +0 -24
- package/dist/src/peer-record-updater.d.ts.map +0 -1
- package/dist/src/peer-record-updater.js +0 -44
- package/dist/src/peer-record-updater.js.map +0 -1
- package/src/dht/dht-content-routing.ts +0 -44
- package/src/dht/dht-peer-routing.ts +0 -36
- package/src/dht/dummy-dht.ts +0 -60
- package/src/peer-record-updater.ts +0 -65
|
@@ -4,7 +4,8 @@ import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
|
4
4
|
import { PeerMap } from '@libp2p/peer-collections'
|
|
5
5
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
6
6
|
import { MAX_CONNECTIONS } from './constants.js'
|
|
7
|
-
import {
|
|
7
|
+
import type { EventEmitter } from '@libp2p/interfaces/events'
|
|
8
|
+
import type { Libp2pEvents } from '@libp2p/interface-libp2p'
|
|
8
9
|
|
|
9
10
|
const log = logger('libp2p:connection-manager:connection-pruner')
|
|
10
11
|
|
|
@@ -16,6 +17,7 @@ interface ConnectionPrunerInit {
|
|
|
16
17
|
interface ConnectionPrunerComponents {
|
|
17
18
|
connectionManager: ConnectionManager
|
|
18
19
|
peerStore: PeerStore
|
|
20
|
+
events: EventEmitter<Libp2pEvents>
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
const defaultOptions = {
|
|
@@ -31,12 +33,22 @@ export class ConnectionPruner {
|
|
|
31
33
|
private readonly connectionManager: ConnectionManager
|
|
32
34
|
private readonly peerStore: PeerStore
|
|
33
35
|
private readonly allow: Multiaddr[]
|
|
36
|
+
private readonly events: EventEmitter<Libp2pEvents>
|
|
34
37
|
|
|
35
38
|
constructor (components: ConnectionPrunerComponents, init: ConnectionPrunerInit = {}) {
|
|
36
39
|
this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections
|
|
37
40
|
this.allow = init.allow ?? defaultOptions.allow
|
|
38
41
|
this.connectionManager = components.connectionManager
|
|
39
42
|
this.peerStore = components.peerStore
|
|
43
|
+
this.events = components.events
|
|
44
|
+
|
|
45
|
+
// check the max connection limit whenever a peer connects
|
|
46
|
+
components.events.addEventListener('connection:open', () => {
|
|
47
|
+
this.maybePruneConnections()
|
|
48
|
+
.catch(err => {
|
|
49
|
+
log.error(err)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
40
52
|
}
|
|
41
53
|
|
|
42
54
|
/**
|
|
@@ -48,7 +60,7 @@ export class ConnectionPruner {
|
|
|
48
60
|
const numConnections = connections.length
|
|
49
61
|
const toPrune = Math.max(numConnections - this.maxConnections, 0)
|
|
50
62
|
|
|
51
|
-
log
|
|
63
|
+
log('checking max connections limit %d/%d', numConnections, this.maxConnections)
|
|
52
64
|
if (numConnections <= this.maxConnections) {
|
|
53
65
|
return
|
|
54
66
|
}
|
|
@@ -64,12 +76,20 @@ export class ConnectionPruner {
|
|
|
64
76
|
continue
|
|
65
77
|
}
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
peerValues.set(remotePeer, 0)
|
|
68
80
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
81
|
+
try {
|
|
82
|
+
const peer = await this.peerStore.get(remotePeer)
|
|
83
|
+
|
|
84
|
+
// sum all tag values
|
|
85
|
+
peerValues.set(remotePeer, [...peer.tags.values()].reduce((acc, curr) => {
|
|
86
|
+
return acc + curr.value
|
|
87
|
+
}, 0))
|
|
88
|
+
} catch (err: any) {
|
|
89
|
+
if (err.code !== 'ERR_NOT_FOUND') {
|
|
90
|
+
log.error('error loading peer tags', err)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
73
93
|
}
|
|
74
94
|
|
|
75
95
|
// sort by value, lowest to highest
|
|
@@ -132,6 +152,6 @@ export class ConnectionPruner {
|
|
|
132
152
|
)
|
|
133
153
|
|
|
134
154
|
// despatch prune event
|
|
135
|
-
this.
|
|
155
|
+
this.events.safeDispatchEvent('connection:prune', { detail: toClose })
|
|
136
156
|
}
|
|
137
157
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { logger } from '@libp2p/logger'
|
|
2
2
|
import { AbortError, CodeError } from '@libp2p/interfaces/errors'
|
|
3
3
|
import { Multiaddr, Resolver, resolvers } from '@multiformats/multiaddr'
|
|
4
|
-
import { TimeoutController } from 'timeout-abort-controller'
|
|
5
4
|
import { publicAddressesFirst } from '@libp2p/utils/address-sort'
|
|
6
5
|
import { codes } from '../errors.js'
|
|
7
6
|
import {
|
|
@@ -14,7 +13,7 @@ import type { Connection } from '@libp2p/interface-connection'
|
|
|
14
13
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
15
14
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
16
15
|
import { getPeerAddress } from '../get-peer.js'
|
|
17
|
-
import type { Address,
|
|
16
|
+
import type { Address, PeerStore } from '@libp2p/interface-peer-store'
|
|
18
17
|
import type { Metric, Metrics } from '@libp2p/interface-metrics'
|
|
19
18
|
import type { TransportManager } from '@libp2p/interface-transport'
|
|
20
19
|
import type { ConnectionGater } from '@libp2p/interface-connection-gater'
|
|
@@ -22,7 +21,9 @@ import PQueue from 'p-queue'
|
|
|
22
21
|
import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
|
|
23
22
|
import { combineSignals, resolveMultiaddrs } from './utils.js'
|
|
24
23
|
import pDefer from 'p-defer'
|
|
25
|
-
import
|
|
24
|
+
import { ClearableSignal, anySignal } from 'any-signal'
|
|
25
|
+
import type { AddressSorter } from '@libp2p/interface-libp2p'
|
|
26
|
+
import { setMaxListeners } from 'events'
|
|
26
27
|
|
|
27
28
|
const log = logger('libp2p:connection-manager:dial-queue')
|
|
28
29
|
|
|
@@ -100,6 +101,11 @@ export class DialQueue {
|
|
|
100
101
|
this.transportManager = components.transportManager
|
|
101
102
|
this.shutDownController = new AbortController()
|
|
102
103
|
|
|
104
|
+
try {
|
|
105
|
+
// This emitter gets listened to a lot
|
|
106
|
+
setMaxListeners?.(Infinity, this.shutDownController.signal)
|
|
107
|
+
} catch {}
|
|
108
|
+
|
|
103
109
|
this.pendingDialCount = components.metrics?.registerMetric('libp2p_dialler_pending_dials')
|
|
104
110
|
this.inProgressDialCount = components.metrics?.registerMetric('libp2p_dialler_in_progress_dials')
|
|
105
111
|
this.pendingDials = []
|
|
@@ -175,7 +181,7 @@ export class DialQueue {
|
|
|
175
181
|
|
|
176
182
|
// create abort conditions - need to do this before `calculateMultiaddrs` as we may be about to
|
|
177
183
|
// resolve a dns addr which can time out
|
|
178
|
-
const
|
|
184
|
+
const signal = this.createDialAbortControllers(options.signal)
|
|
179
185
|
let addrsToDial: Address[]
|
|
180
186
|
|
|
181
187
|
try {
|
|
@@ -186,7 +192,6 @@ export class DialQueue {
|
|
|
186
192
|
})
|
|
187
193
|
} catch (err) {
|
|
188
194
|
signal.clear()
|
|
189
|
-
timeoutController.clear()
|
|
190
195
|
throw err
|
|
191
196
|
}
|
|
192
197
|
|
|
@@ -209,7 +214,6 @@ export class DialQueue {
|
|
|
209
214
|
if (existingDial != null) {
|
|
210
215
|
log('joining existing dial target for %p', peerId)
|
|
211
216
|
signal.clear()
|
|
212
|
-
timeoutController.clear()
|
|
213
217
|
return await existingDial.promise
|
|
214
218
|
}
|
|
215
219
|
|
|
@@ -232,13 +236,12 @@ export class DialQueue {
|
|
|
232
236
|
|
|
233
237
|
// clean up abort signals/controllers
|
|
234
238
|
signal.clear()
|
|
235
|
-
timeoutController.clear()
|
|
236
239
|
})
|
|
237
240
|
.catch(err => {
|
|
238
|
-
log.error('dial failed to %s',
|
|
241
|
+
log.error('dial failed to %s', pendingDial.multiaddrs.map(ma => ma.toString()).join(', '), err)
|
|
239
242
|
|
|
240
243
|
// Error is a timeout
|
|
241
|
-
if (
|
|
244
|
+
if (signal.aborted) {
|
|
242
245
|
const error = new CodeError(err.message, codes.ERR_TIMEOUT)
|
|
243
246
|
throw error
|
|
244
247
|
}
|
|
@@ -252,18 +255,21 @@ export class DialQueue {
|
|
|
252
255
|
return await pendingDial.promise
|
|
253
256
|
}
|
|
254
257
|
|
|
255
|
-
private createDialAbortControllers (userSignal?: AbortSignal):
|
|
256
|
-
// ensure we throw if the dial takes longer than the dial timeout
|
|
257
|
-
const timeoutController = new TimeoutController(this.dialTimeout)
|
|
258
|
-
|
|
258
|
+
private createDialAbortControllers (userSignal?: AbortSignal): ClearableSignal {
|
|
259
259
|
// let any signal abort the dial
|
|
260
|
-
const signal =
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
260
|
+
const signal = anySignal(
|
|
261
|
+
[AbortSignal.timeout(this.dialTimeout),
|
|
262
|
+
this.shutDownController.signal,
|
|
263
|
+
userSignal
|
|
264
|
+
]
|
|
264
265
|
)
|
|
265
266
|
|
|
266
|
-
|
|
267
|
+
try {
|
|
268
|
+
// This emitter gets listened to a lot
|
|
269
|
+
setMaxListeners?.(Infinity, signal)
|
|
270
|
+
} catch {}
|
|
271
|
+
|
|
272
|
+
return signal
|
|
267
273
|
}
|
|
268
274
|
|
|
269
275
|
private async calculateMultiaddrs (peerId?: PeerId, addrs: Address[] = [], options: DialOptions = {}): Promise<Address[]> {
|
|
@@ -280,8 +286,15 @@ export class DialQueue {
|
|
|
280
286
|
// if just a peer id was passed, load available multiaddrs for this peer from the address book
|
|
281
287
|
if (addrs.length === 0) {
|
|
282
288
|
log('loading multiaddrs for %p', peerId)
|
|
283
|
-
|
|
284
|
-
|
|
289
|
+
try {
|
|
290
|
+
const peer = await this.peerStore.get(peerId)
|
|
291
|
+
addrs.push(...peer.addresses)
|
|
292
|
+
log('loaded multiaddrs for %p', peerId, addrs.map(({ multiaddr }) => multiaddr.toString()))
|
|
293
|
+
} catch (err: any) {
|
|
294
|
+
if (err.code !== codes.ERR_NOT_FOUND) {
|
|
295
|
+
throw err
|
|
296
|
+
}
|
|
297
|
+
}
|
|
285
298
|
}
|
|
286
299
|
}
|
|
287
300
|
|
|
@@ -371,7 +384,14 @@ export class DialQueue {
|
|
|
371
384
|
gatedAdrs.push(addr)
|
|
372
385
|
}
|
|
373
386
|
|
|
374
|
-
|
|
387
|
+
const sortedGatedAddrs = gatedAdrs.sort(this.addressSorter)
|
|
388
|
+
|
|
389
|
+
// make sure we actually have some addresses to dial
|
|
390
|
+
if (sortedGatedAddrs.length === 0) {
|
|
391
|
+
throw new CodeError('The connection gater denied all addresses in the dial request', codes.ERR_NO_VALID_ADDRESSES)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return sortedGatedAddrs
|
|
375
395
|
}
|
|
376
396
|
|
|
377
397
|
private async performDial (pendingDial: PendingDial, options: DialOptions = {}): Promise<Connection> {
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { logger } from '@libp2p/logger'
|
|
2
2
|
import { CodeError } from '@libp2p/interfaces/errors'
|
|
3
3
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
4
|
-
import {
|
|
4
|
+
import type { EventEmitter } from '@libp2p/interfaces/events'
|
|
5
5
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
6
6
|
import { codes } from '../errors.js'
|
|
7
7
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
8
|
-
import { setMaxListeners } from 'events'
|
|
9
8
|
import type { Connection, MultiaddrConnection } from '@libp2p/interface-connection'
|
|
10
|
-
import type { ConnectionManager
|
|
11
|
-
import type {
|
|
9
|
+
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
10
|
+
import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
12
11
|
import { Multiaddr, Resolver, multiaddr } from '@multiformats/multiaddr'
|
|
13
12
|
import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
|
|
14
13
|
import { RateLimiterMemory } from 'rate-limiter-flexible'
|
|
15
14
|
import type { Metrics } from '@libp2p/interface-metrics'
|
|
16
|
-
import type { TransportManager
|
|
15
|
+
import type { TransportManager } from '@libp2p/interface-transport'
|
|
17
16
|
import { getPeerAddress } from '../get-peer.js'
|
|
18
17
|
import { AutoDial } from './auto-dial.js'
|
|
19
18
|
import { DialQueue } from './dial-queue.js'
|
|
@@ -23,7 +22,7 @@ import { PeerMap } from '@libp2p/peer-collections'
|
|
|
23
22
|
import { publicAddressesFirst } from '@libp2p/utils/address-sort'
|
|
24
23
|
import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js'
|
|
25
24
|
import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
|
|
26
|
-
import type { PendingDial } from '
|
|
25
|
+
import type { PendingDial, AddressSorter, Libp2pEvents } from '@libp2p/interface-libp2p'
|
|
27
26
|
|
|
28
27
|
const log = logger('libp2p:connection-manager')
|
|
29
28
|
|
|
@@ -143,10 +142,10 @@ const defaultOptions = {
|
|
|
143
142
|
export interface DefaultConnectionManagerComponents {
|
|
144
143
|
peerId: PeerId
|
|
145
144
|
metrics?: Metrics
|
|
146
|
-
upgrader: Upgrader
|
|
147
145
|
peerStore: PeerStore
|
|
148
146
|
transportManager: TransportManager
|
|
149
147
|
connectionGater: ConnectionGater
|
|
148
|
+
events: EventEmitter<Libp2pEvents>
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
export interface OpenConnectionOptions extends AbortOptions {
|
|
@@ -156,7 +155,7 @@ export interface OpenConnectionOptions extends AbortOptions {
|
|
|
156
155
|
/**
|
|
157
156
|
* Responsible for managing known connections.
|
|
158
157
|
*/
|
|
159
|
-
export class DefaultConnectionManager
|
|
158
|
+
export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
160
159
|
private started: boolean
|
|
161
160
|
private readonly connections: PeerMap<Connection[]>
|
|
162
161
|
private readonly allow: Multiaddr[]
|
|
@@ -172,10 +171,9 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
172
171
|
|
|
173
172
|
private readonly peerStore: PeerStore
|
|
174
173
|
private readonly metrics?: Metrics
|
|
174
|
+
private readonly events: EventEmitter<Libp2pEvents>
|
|
175
175
|
|
|
176
176
|
constructor (components: DefaultConnectionManagerComponents, init: ConnectionManagerInit = {}) {
|
|
177
|
-
super()
|
|
178
|
-
|
|
179
177
|
this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections
|
|
180
178
|
const minConnections = init.minConnections ?? defaultOptions.minConnections
|
|
181
179
|
|
|
@@ -189,17 +187,14 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
189
187
|
this.connections = new PeerMap()
|
|
190
188
|
|
|
191
189
|
this.started = false
|
|
192
|
-
|
|
193
|
-
try {
|
|
194
|
-
// This emitter gets listened to a lot
|
|
195
|
-
setMaxListeners?.(Infinity, this)
|
|
196
|
-
} catch {}
|
|
197
|
-
|
|
198
190
|
this.peerStore = components.peerStore
|
|
199
191
|
this.metrics = components.metrics
|
|
192
|
+
this.events = components.events
|
|
200
193
|
|
|
201
194
|
this.onConnect = this.onConnect.bind(this)
|
|
202
195
|
this.onDisconnect = this.onDisconnect.bind(this)
|
|
196
|
+
this.events.addEventListener('connection:open', this.onConnect)
|
|
197
|
+
this.events.addEventListener('connection:close', this.onDisconnect)
|
|
203
198
|
|
|
204
199
|
// allow/deny lists
|
|
205
200
|
this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
|
|
@@ -217,35 +212,23 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
217
212
|
// controls what happens when we don't have enough connections
|
|
218
213
|
this.autoDial = new AutoDial({
|
|
219
214
|
connectionManager: this,
|
|
220
|
-
peerStore: components.peerStore
|
|
215
|
+
peerStore: components.peerStore,
|
|
216
|
+
events: components.events
|
|
221
217
|
}, {
|
|
222
218
|
minConnections,
|
|
223
219
|
autoDialConcurrency: init.autoDialConcurrency ?? defaultOptions.autoDialConcurrency,
|
|
224
220
|
autoDialPriority: init.autoDialPriority ?? defaultOptions.autoDialPriority
|
|
225
221
|
})
|
|
226
|
-
// check the min connection limit whenever a peer disconnects
|
|
227
|
-
this.addEventListener('peer:disconnect', () => {
|
|
228
|
-
this.autoDial.autoDial()
|
|
229
|
-
.catch(err => {
|
|
230
|
-
log.error(err)
|
|
231
|
-
})
|
|
232
|
-
})
|
|
233
222
|
|
|
234
223
|
// controls what happens when we have too many connections
|
|
235
224
|
this.connectionPruner = new ConnectionPruner({
|
|
236
225
|
connectionManager: this,
|
|
237
|
-
peerStore: components.peerStore
|
|
226
|
+
peerStore: components.peerStore,
|
|
227
|
+
events: components.events
|
|
238
228
|
}, {
|
|
239
229
|
maxConnections: this.maxConnections,
|
|
240
230
|
allow: this.allow
|
|
241
231
|
})
|
|
242
|
-
// check the max connection limit whenever a peer connects
|
|
243
|
-
this.addEventListener('peer:connect', () => {
|
|
244
|
-
this.connectionPruner.maybePruneConnections()
|
|
245
|
-
.catch(err => {
|
|
246
|
-
log.error(err)
|
|
247
|
-
})
|
|
248
|
-
})
|
|
249
232
|
|
|
250
233
|
this.dialQueue = new DialQueue({
|
|
251
234
|
peerId: components.peerId,
|
|
@@ -262,9 +245,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
262
245
|
dnsaddr: dnsaddrResolver
|
|
263
246
|
}
|
|
264
247
|
})
|
|
265
|
-
|
|
266
|
-
components.upgrader.addEventListener('connection', this.onConnect)
|
|
267
|
-
components.upgrader.addEventListener('connectionEnd', this.onDisconnect)
|
|
268
248
|
}
|
|
269
249
|
|
|
270
250
|
isStarted (): boolean {
|
|
@@ -367,10 +347,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
367
347
|
const keepAlivePeers: PeerId[] = []
|
|
368
348
|
|
|
369
349
|
for (const peer of await this.peerStore.all()) {
|
|
370
|
-
|
|
371
|
-
const hasKeepAlive = tags.filter(tag => tag.name === KEEP_ALIVE).length > 0
|
|
372
|
-
|
|
373
|
-
if (hasKeepAlive) {
|
|
350
|
+
if (peer.tags.has(KEEP_ALIVE)) {
|
|
374
351
|
keepAlivePeers.push(peer.id)
|
|
375
352
|
}
|
|
376
353
|
}
|
|
@@ -439,18 +416,25 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
439
416
|
|
|
440
417
|
const peerId = connection.remotePeer
|
|
441
418
|
const storedConns = this.connections.get(peerId)
|
|
419
|
+
let isNewPeer = false
|
|
442
420
|
|
|
443
421
|
if (storedConns != null) {
|
|
444
422
|
storedConns.push(connection)
|
|
445
423
|
} else {
|
|
424
|
+
isNewPeer = true
|
|
446
425
|
this.connections.set(peerId, [connection])
|
|
447
426
|
}
|
|
448
427
|
|
|
449
|
-
|
|
450
|
-
|
|
428
|
+
// only need to store RSA public keys, all other types are embedded in the peer id
|
|
429
|
+
if (peerId.publicKey != null && peerId.type === 'RSA') {
|
|
430
|
+
await this.peerStore.patch(peerId, {
|
|
431
|
+
publicKey: peerId.publicKey
|
|
432
|
+
})
|
|
451
433
|
}
|
|
452
434
|
|
|
453
|
-
|
|
435
|
+
if (isNewPeer) {
|
|
436
|
+
this.events.safeDispatchEvent('peer:connect', { detail: connection.remotePeer })
|
|
437
|
+
}
|
|
454
438
|
}
|
|
455
439
|
|
|
456
440
|
/**
|
|
@@ -472,7 +456,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
472
456
|
this.connections.set(peerId, storedConn)
|
|
473
457
|
} else if (storedConn != null) {
|
|
474
458
|
this.connections.delete(peerId)
|
|
475
|
-
this.
|
|
459
|
+
this.events.safeDispatchEvent('peer:disconnect', { detail: connection.remotePeer })
|
|
476
460
|
}
|
|
477
461
|
}
|
|
478
462
|
|
|
@@ -495,6 +479,10 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
495
479
|
}
|
|
496
480
|
|
|
497
481
|
async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise<Connection> {
|
|
482
|
+
if (!this.isStarted()) {
|
|
483
|
+
throw new CodeError('Not started', codes.ERR_NODE_NOT_STARTED)
|
|
484
|
+
}
|
|
485
|
+
|
|
498
486
|
const { peerId } = getPeerAddress(peerIdOrMultiaddr)
|
|
499
487
|
|
|
500
488
|
if (peerId != null) {
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
uniquePeers,
|
|
6
6
|
requirePeers
|
|
7
7
|
} from './utils.js'
|
|
8
|
-
import drain from 'it-drain'
|
|
9
8
|
import merge from 'it-merge'
|
|
10
9
|
import { pipe } from 'it-pipe'
|
|
11
10
|
import type { ContentRouting } from '@libp2p/interface-content-routing'
|
|
@@ -13,9 +12,7 @@ import type { AbortOptions } from '@libp2p/interfaces'
|
|
|
13
12
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
14
13
|
import type { CID } from 'multiformats/cid'
|
|
15
14
|
import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
16
|
-
import type { DualDHT } from '@libp2p/interface-dht'
|
|
17
15
|
import type { PeerInfo } from '@libp2p/interface-peer-info'
|
|
18
|
-
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
19
16
|
|
|
20
17
|
export interface CompoundContentRoutingInit {
|
|
21
18
|
routers: ContentRouting[]
|
|
@@ -23,7 +20,6 @@ export interface CompoundContentRoutingInit {
|
|
|
23
20
|
|
|
24
21
|
export interface CompoundContentRoutingComponents {
|
|
25
22
|
peerStore: PeerStore
|
|
26
|
-
dht?: DualDHT
|
|
27
23
|
}
|
|
28
24
|
|
|
29
25
|
export class CompoundContentRouting implements ContentRouting, Startable {
|
|
@@ -54,7 +50,7 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
54
50
|
*/
|
|
55
51
|
async * findProviders (key: CID, options: AbortOptions = {}): AsyncIterable<PeerInfo> {
|
|
56
52
|
if (this.routers.length === 0) {
|
|
57
|
-
throw new CodeError('No content
|
|
53
|
+
throw new CodeError('No content routers available', codes.ERR_NO_ROUTERS_AVAILABLE)
|
|
58
54
|
}
|
|
59
55
|
|
|
60
56
|
yield * pipe(
|
|
@@ -87,11 +83,9 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
87
83
|
throw new CodeError(messages.NOT_STARTED_YET, codes.DHT_NOT_STARTED)
|
|
88
84
|
}
|
|
89
85
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
await drain(dht.put(key, value, options))
|
|
94
|
-
}
|
|
86
|
+
await Promise.all(this.routers.map(async (router) => {
|
|
87
|
+
await router.put(key, value, options)
|
|
88
|
+
}))
|
|
95
89
|
}
|
|
96
90
|
|
|
97
91
|
/**
|
|
@@ -103,50 +97,8 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
103
97
|
throw new CodeError(messages.NOT_STARTED_YET, codes.DHT_NOT_STARTED)
|
|
104
98
|
}
|
|
105
99
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
for await (const event of dht.get(key, options)) {
|
|
110
|
-
if (event.name === 'VALUE') {
|
|
111
|
-
return event.value
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
throw new CodeError(messages.NOT_FOUND, codes.ERR_NOT_FOUND)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Get the `n` values to the given key without sorting
|
|
121
|
-
*/
|
|
122
|
-
async * getMany (key: Uint8Array, nVals: number, options: AbortOptions): AsyncIterable<{ from: PeerId, val: Uint8Array }> {
|
|
123
|
-
if (!this.isStarted()) {
|
|
124
|
-
throw new CodeError(messages.NOT_STARTED_YET, codes.DHT_NOT_STARTED)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (nVals == null || nVals === 0) {
|
|
128
|
-
return
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
let gotValues = 0
|
|
132
|
-
const dht = this.components.dht
|
|
133
|
-
|
|
134
|
-
if (dht != null) {
|
|
135
|
-
for await (const event of dht.get(key, options)) {
|
|
136
|
-
if (event.name === 'VALUE') {
|
|
137
|
-
yield { from: event.from, val: event.value }
|
|
138
|
-
|
|
139
|
-
gotValues++
|
|
140
|
-
|
|
141
|
-
if (gotValues === nVals) {
|
|
142
|
-
break
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (gotValues === 0) {
|
|
149
|
-
throw new CodeError(messages.NOT_FOUND, codes.ERR_NOT_FOUND)
|
|
150
|
-
}
|
|
100
|
+
return await Promise.any(this.routers.map(async (router) => {
|
|
101
|
+
return await router.get(key, options)
|
|
102
|
+
}))
|
|
151
103
|
}
|
|
152
104
|
}
|
|
@@ -11,7 +11,9 @@ import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
|
11
11
|
export async function * storeAddresses (source: Source<PeerInfo>, peerStore: PeerStore): AsyncIterable<PeerInfo> {
|
|
12
12
|
yield * map(source, async (peer) => {
|
|
13
13
|
// ensure we have the addresses for a given peer
|
|
14
|
-
await peerStore.
|
|
14
|
+
await peerStore.merge(peer.id, {
|
|
15
|
+
multiaddrs: peer.multiaddrs
|
|
16
|
+
})
|
|
15
17
|
|
|
16
18
|
return peer
|
|
17
19
|
})
|
package/src/fetch/index.ts
CHANGED
|
@@ -12,7 +12,6 @@ import type { AbortOptions } from '@libp2p/interfaces'
|
|
|
12
12
|
import { abortableDuplex } from 'abortable-iterator'
|
|
13
13
|
import { pipe } from 'it-pipe'
|
|
14
14
|
import first from 'it-first'
|
|
15
|
-
import { TimeoutController } from 'timeout-abort-controller'
|
|
16
15
|
import { setMaxListeners } from 'events'
|
|
17
16
|
import { fromString as uint8arrayFromString } from 'uint8arrays/from-string'
|
|
18
17
|
import { toString as uint8arrayToString } from 'uint8arrays/to-string'
|
|
@@ -20,15 +19,17 @@ import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
|
20
19
|
|
|
21
20
|
const log = logger('libp2p:fetch')
|
|
22
21
|
|
|
22
|
+
const DEFAULT_TIMEOUT = 10000
|
|
23
|
+
|
|
23
24
|
export interface FetchServiceInit {
|
|
24
|
-
protocolPrefix
|
|
25
|
-
maxInboundStreams
|
|
26
|
-
maxOutboundStreams
|
|
25
|
+
protocolPrefix?: string
|
|
26
|
+
maxInboundStreams?: number
|
|
27
|
+
maxOutboundStreams?: number
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* How long we should wait for a remote peer to send any data
|
|
30
31
|
*/
|
|
31
|
-
timeout
|
|
32
|
+
timeout?: number
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
export interface HandleMessageOptions {
|
|
@@ -45,13 +46,51 @@ export interface FetchServiceComponents {
|
|
|
45
46
|
connectionManager: ConnectionManager
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
export interface FetchService {
|
|
50
|
+
/**
|
|
51
|
+
* The protocol name used by this fetch service
|
|
52
|
+
*/
|
|
53
|
+
protocol: string
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sends a request to fetch the value associated with the given key from the given peer
|
|
57
|
+
*/
|
|
58
|
+
fetch: (peer: PeerId, key: string, options?: AbortOptions) => Promise<Uint8Array | null>
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Registers a new lookup callback that can map keys to values, for a given set of keys that
|
|
62
|
+
* share the same prefix
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
*
|
|
66
|
+
* ```js
|
|
67
|
+
* // ...
|
|
68
|
+
* libp2p.fetchService.registerLookupFunction('/prefix', (key) => { ... })
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
registerLookupFunction: (prefix: string, lookup: LookupFunction) => void
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Registers a new lookup callback that can map keys to values, for a given set of keys that
|
|
75
|
+
* share the same prefix.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
*
|
|
79
|
+
* ```js
|
|
80
|
+
* // ...
|
|
81
|
+
* libp2p.fetchService.unregisterLookupFunction('/prefix')
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
unregisterLookupFunction: (prefix: string, lookup?: LookupFunction) => void
|
|
85
|
+
}
|
|
86
|
+
|
|
48
87
|
/**
|
|
49
88
|
* A simple libp2p protocol for requesting a value corresponding to a key from a peer.
|
|
50
89
|
* Developers can register one or more lookup function for retrieving the value corresponding to
|
|
51
90
|
* a given key. Each lookup function must act on a distinct part of the overall key space, defined
|
|
52
91
|
* by a fixed prefix that all keys that should be routed to that lookup function will start with.
|
|
53
92
|
*/
|
|
54
|
-
|
|
93
|
+
class DefaultFetchService implements Startable, FetchService {
|
|
55
94
|
public readonly protocol: string
|
|
56
95
|
private readonly components: FetchServiceComponents
|
|
57
96
|
private readonly lookupFunctions: Map<string, LookupFunction>
|
|
@@ -99,19 +138,17 @@ export class FetchService implements Startable {
|
|
|
99
138
|
log('dialing %s to %p', this.protocol, peer)
|
|
100
139
|
|
|
101
140
|
const connection = await this.components.connectionManager.openConnection(peer, options)
|
|
102
|
-
let timeoutController
|
|
103
141
|
let signal = options.signal
|
|
104
142
|
let stream: Stream | undefined
|
|
105
143
|
|
|
106
144
|
// create a timeout if no abort signal passed
|
|
107
145
|
if (signal == null) {
|
|
108
146
|
log('using default timeout of %d ms', this.init.timeout)
|
|
109
|
-
|
|
110
|
-
signal = timeoutController.signal
|
|
147
|
+
signal = AbortSignal.timeout(this.init.timeout ?? DEFAULT_TIMEOUT)
|
|
111
148
|
|
|
112
149
|
try {
|
|
113
150
|
// fails on node < 15.4
|
|
114
|
-
setMaxListeners?.(Infinity,
|
|
151
|
+
setMaxListeners?.(Infinity, signal)
|
|
115
152
|
} catch {}
|
|
116
153
|
}
|
|
117
154
|
|
|
@@ -163,10 +200,6 @@ export class FetchService implements Startable {
|
|
|
163
200
|
|
|
164
201
|
return result ?? null
|
|
165
202
|
} finally {
|
|
166
|
-
if (timeoutController != null) {
|
|
167
|
-
timeoutController.clear()
|
|
168
|
-
}
|
|
169
|
-
|
|
170
203
|
if (stream != null) {
|
|
171
204
|
stream.close()
|
|
172
205
|
}
|
|
@@ -274,3 +307,7 @@ export class FetchService implements Startable {
|
|
|
274
307
|
this.lookupFunctions.delete(prefix)
|
|
275
308
|
}
|
|
276
309
|
}
|
|
310
|
+
|
|
311
|
+
export function fetchService (init: FetchServiceInit = {}): (components: FetchServiceComponents) => FetchService {
|
|
312
|
+
return (components) => new DefaultFetchService(components, init)
|
|
313
|
+
}
|