libp2p 0.39.5 → 0.40.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/README.md +5 -0
- package/dist/src/address-manager/index.d.ts +18 -2
- package/dist/src/address-manager/index.d.ts.map +1 -1
- package/dist/src/address-manager/index.js +18 -5
- package/dist/src/address-manager/index.js.map +1 -1
- package/dist/src/circuit/auto-relay.d.ts +2 -2
- package/dist/src/circuit/auto-relay.d.ts.map +1 -1
- package/dist/src/circuit/auto-relay.js +12 -12
- package/dist/src/circuit/auto-relay.js.map +1 -1
- package/dist/src/circuit/index.d.ts +13 -3
- package/dist/src/circuit/index.d.ts.map +1 -1
- package/dist/src/circuit/index.js +1 -1
- package/dist/src/circuit/index.js.map +1 -1
- package/dist/src/circuit/pb/index.d.ts.map +1 -1
- package/dist/src/circuit/pb/index.js +29 -34
- package/dist/src/circuit/pb/index.js.map +1 -1
- package/dist/src/circuit/transport.d.ts +22 -7
- package/dist/src/circuit/transport.d.ts.map +1 -1
- package/dist/src/circuit/transport.js +26 -17
- package/dist/src/circuit/transport.js.map +1 -1
- package/dist/src/components.d.ts +110 -0
- package/dist/src/components.d.ts.map +1 -0
- package/dist/src/components.js +199 -0
- package/dist/src/components.js.map +1 -0
- package/dist/src/connection-manager/auto-dialler.d.ts +9 -2
- package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
- package/dist/src/connection-manager/auto-dialler.js +6 -6
- package/dist/src/connection-manager/auto-dialler.js.map +1 -1
- package/dist/src/connection-manager/dialer/index.d.ts +12 -5
- package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
- package/dist/src/connection-manager/dialer/index.js +9 -9
- package/dist/src/connection-manager/dialer/index.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +41 -9
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +82 -39
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/content-routing/index.d.ts +7 -2
- package/dist/src/content-routing/index.d.ts.map +1 -1
- package/dist/src/content-routing/index.js +4 -4
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/content-routing/utils.d.ts +1 -1
- package/dist/src/content-routing/utils.d.ts.map +1 -1
- package/dist/src/errors.d.ts +2 -1
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +1 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/fetch/index.d.ts +7 -3
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/fetch/index.js +3 -3
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/fetch/pb/proto.d.ts.map +1 -1
- package/dist/src/fetch/pb/proto.js +24 -35
- package/dist/src/fetch/pb/proto.js.map +1 -1
- package/dist/src/identify/index.d.ts +13 -3
- package/dist/src/identify/index.d.ts.map +1 -1
- package/dist/src/identify/index.js +41 -41
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/identify/pb/message.d.ts.map +1 -1
- package/dist/src/identify/pb/message.js +23 -34
- package/dist/src/identify/pb/message.js.map +1 -1
- package/dist/src/index.d.ts +10 -9
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/insecure/index.d.ts +2 -8
- package/dist/src/insecure/index.d.ts.map +1 -1
- package/dist/src/insecure/index.js +5 -3
- package/dist/src/insecure/index.js.map +1 -1
- package/dist/src/insecure/pb/proto.d.ts.map +1 -1
- package/dist/src/insecure/pb/proto.js +24 -29
- package/dist/src/insecure/pb/proto.js.map +1 -1
- package/dist/src/keychain/index.d.ts +6 -2
- package/dist/src/keychain/index.d.ts.map +1 -1
- package/dist/src/keychain/index.js +19 -19
- package/dist/src/keychain/index.js.map +1 -1
- package/dist/src/libp2p.d.ts +1 -2
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +48 -71
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/nat-manager.d.ts +9 -2
- package/dist/src/nat-manager.d.ts.map +1 -1
- package/dist/src/nat-manager.js +3 -3
- package/dist/src/nat-manager.js.map +1 -1
- package/dist/src/peer-record-updater.d.ts +11 -2
- package/dist/src/peer-record-updater.d.ts.map +1 -1
- package/dist/src/peer-record-updater.js +10 -10
- package/dist/src/peer-record-updater.js.map +1 -1
- package/dist/src/peer-routing.d.ts +6 -2
- package/dist/src/peer-routing.d.ts.map +1 -1
- package/dist/src/peer-routing.js +4 -4
- package/dist/src/peer-routing.js.map +1 -1
- package/dist/src/ping/index.d.ts +7 -3
- package/dist/src/ping/index.d.ts.map +1 -1
- package/dist/src/ping/index.js +3 -3
- package/dist/src/ping/index.js.map +1 -1
- package/dist/src/pnet/index.d.ts +2 -17
- package/dist/src/pnet/index.d.ts.map +1 -1
- package/dist/src/pnet/index.js +4 -1
- package/dist/src/pnet/index.js.map +1 -1
- package/dist/src/pubsub/dummy-pubsub.d.ts +2 -1
- package/dist/src/pubsub/dummy-pubsub.d.ts.map +1 -1
- package/dist/src/pubsub/dummy-pubsub.js +4 -0
- package/dist/src/pubsub/dummy-pubsub.js.map +1 -1
- package/dist/src/registrar.d.ts +9 -3
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/registrar.js +6 -6
- package/dist/src/registrar.js.map +1 -1
- package/dist/src/transport-manager.d.ts +9 -3
- package/dist/src/transport-manager.d.ts.map +1 -1
- package/dist/src/transport-manager.js +4 -4
- package/dist/src/transport-manager.js.map +1 -1
- package/dist/src/upgrader.d.ts +17 -5
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +55 -43
- package/dist/src/upgrader.js.map +1 -1
- package/package.json +37 -37
- package/src/address-manager/index.ts +31 -8
- package/src/circuit/auto-relay.ts +15 -15
- package/src/circuit/index.ts +16 -5
- package/src/circuit/pb/index.ts +29 -35
- package/src/circuit/transport.ts +49 -20
- package/src/components.ts +332 -0
- package/src/connection-manager/auto-dialler.ts +17 -9
- package/src/connection-manager/dialer/index.ts +23 -15
- package/src/connection-manager/index.ts +139 -47
- package/src/content-routing/index.ts +13 -7
- package/src/errors.ts +2 -1
- package/src/fetch/index.ts +12 -7
- package/src/fetch/pb/proto.ts +24 -35
- package/src/identify/index.ts +57 -53
- package/src/identify/pb/message.ts +23 -35
- package/src/index.ts +10 -9
- package/src/insecure/index.ts +6 -3
- package/src/insecure/pb/proto.ts +24 -29
- package/src/keychain/index.ts +27 -22
- package/src/libp2p.ts +49 -77
- package/src/nat-manager.ts +14 -6
- package/src/peer-record-updater.ts +23 -13
- package/src/peer-routing.ts +12 -7
- package/src/ping/index.ts +12 -7
- package/src/pnet/index.ts +5 -1
- package/src/pubsub/dummy-pubsub.ts +3 -1
- package/src/registrar.ts +17 -10
- package/src/transport-manager.ts +15 -8
- package/src/upgrader.ts +75 -49
- package/src/version.ts +1 -1
- package/dist/src/connection-manager/dialer/auto-dialer.d.ts +0 -16
- package/dist/src/connection-manager/dialer/auto-dialer.d.ts.map +0 -1
- package/dist/src/connection-manager/dialer/auto-dialer.js +0 -43
- package/dist/src/connection-manager/dialer/auto-dialer.js.map +0 -1
- package/src/connection-manager/dialer/auto-dialer.ts +0 -65
|
@@ -11,14 +11,16 @@ import { codes } from '../errors.js'
|
|
|
11
11
|
import { isPeerId, PeerId } from '@libp2p/interface-peer-id'
|
|
12
12
|
import { setMaxListeners } from 'events'
|
|
13
13
|
import type { Connection, MultiaddrConnection } from '@libp2p/interface-connection'
|
|
14
|
-
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
15
|
-
import { Components, Initializable } from '@libp2p/components'
|
|
14
|
+
import type { ConnectionManager, Dialer } from '@libp2p/interface-connection-manager'
|
|
16
15
|
import * as STATUS from '@libp2p/interface-connection/status'
|
|
17
|
-
import type { AddressSorter } from '@libp2p/interface-peer-store'
|
|
18
|
-
import
|
|
16
|
+
import type { AddressSorter, PeerStore } from '@libp2p/interface-peer-store'
|
|
17
|
+
import { multiaddr, Multiaddr, Resolver } from '@multiformats/multiaddr'
|
|
19
18
|
import { PeerMap } from '@libp2p/peer-collections'
|
|
20
19
|
import { TimeoutController } from 'timeout-abort-controller'
|
|
21
20
|
import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
|
|
21
|
+
import { RateLimiterMemory } from 'rate-limiter-flexible'
|
|
22
|
+
import type { Metrics } from '@libp2p/interface-metrics'
|
|
23
|
+
import type { Upgrader } from '@libp2p/interface-transport'
|
|
22
24
|
|
|
23
25
|
const log = logger('libp2p:connection-manager')
|
|
24
26
|
|
|
@@ -31,7 +33,9 @@ const defaultOptions: Partial<ConnectionManagerInit> = {
|
|
|
31
33
|
maxEventLoopDelay: Infinity,
|
|
32
34
|
pollInterval: 2000,
|
|
33
35
|
autoDialInterval: 10000,
|
|
34
|
-
movingAverageInterval: 60000
|
|
36
|
+
movingAverageInterval: 60000,
|
|
37
|
+
inboundConnectionThreshold: 5,
|
|
38
|
+
maxIncomingPendingConnections: 10
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
const METRICS_SYSTEM = 'libp2p'
|
|
@@ -132,6 +136,30 @@ export interface ConnectionManagerInit {
|
|
|
132
136
|
* tagged with KEEP_ALIVE up to this timeout in ms. (default: 60000)
|
|
133
137
|
*/
|
|
134
138
|
startupReconnectTimeout?: number
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* A list of multiaddrs that will always be allowed (except if they are in the
|
|
142
|
+
* deny list) to open connections to this node even if we've reached maxConnections
|
|
143
|
+
*/
|
|
144
|
+
allow?: string[]
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A list of multiaddrs that will never be allowed to open connections to
|
|
148
|
+
* this node under any circumstances
|
|
149
|
+
*/
|
|
150
|
+
deny?: string[]
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* If more than this many connections are opened per second by a single
|
|
154
|
+
* host, reject subsequent connections
|
|
155
|
+
*/
|
|
156
|
+
inboundConnectionThreshold?: number
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* The maximum number of parallel incoming connections allowed that have yet to
|
|
160
|
+
* complete the connection upgrade - e.g. choosing connection encryption, muxer, etc
|
|
161
|
+
*/
|
|
162
|
+
maxIncomingPendingConnections?: number
|
|
135
163
|
}
|
|
136
164
|
|
|
137
165
|
export interface ConnectionManagerEvents {
|
|
@@ -139,11 +167,19 @@ export interface ConnectionManagerEvents {
|
|
|
139
167
|
'peer:disconnect': CustomEvent<PeerId>
|
|
140
168
|
}
|
|
141
169
|
|
|
170
|
+
export interface DefaultConnectionManagerComponents {
|
|
171
|
+
peerId: PeerId
|
|
172
|
+
metrics?: Metrics
|
|
173
|
+
upgrader: Upgrader
|
|
174
|
+
peerStore: PeerStore
|
|
175
|
+
dialer: Dialer
|
|
176
|
+
}
|
|
177
|
+
|
|
142
178
|
/**
|
|
143
179
|
* Responsible for managing known connections.
|
|
144
180
|
*/
|
|
145
|
-
export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager, Startable
|
|
146
|
-
private components
|
|
181
|
+
export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager, Startable {
|
|
182
|
+
private readonly components: DefaultConnectionManagerComponents
|
|
147
183
|
private readonly opts: Required<ConnectionManagerInit>
|
|
148
184
|
private readonly connections: Map<string, Connection[]>
|
|
149
185
|
private started: boolean
|
|
@@ -152,8 +188,12 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
152
188
|
private readonly startupReconnectTimeout: number
|
|
153
189
|
private connectOnStartupController?: TimeoutController
|
|
154
190
|
private readonly dialTimeout: number
|
|
191
|
+
private readonly allow: Multiaddr[]
|
|
192
|
+
private readonly deny: Multiaddr[]
|
|
193
|
+
private readonly inboundConnectionRateLimiter: RateLimiterMemory
|
|
194
|
+
private incomingPendingConnections: number
|
|
155
195
|
|
|
156
|
-
constructor (init: ConnectionManagerInit) {
|
|
196
|
+
constructor (components: DefaultConnectionManagerComponents, init: ConnectionManagerInit) {
|
|
157
197
|
super()
|
|
158
198
|
|
|
159
199
|
this.opts = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, init)
|
|
@@ -164,6 +204,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
164
204
|
|
|
165
205
|
log('options: %o', this.opts)
|
|
166
206
|
|
|
207
|
+
this.components = components
|
|
208
|
+
|
|
167
209
|
/**
|
|
168
210
|
* Map of connections per peer
|
|
169
211
|
*/
|
|
@@ -187,13 +229,33 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
187
229
|
|
|
188
230
|
this.startupReconnectTimeout = init.startupReconnectTimeout ?? STARTUP_RECONNECT_TIMEOUT
|
|
189
231
|
this.dialTimeout = init.dialTimeout ?? 30000
|
|
232
|
+
|
|
233
|
+
this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
|
|
234
|
+
this.deny = (init.deny ?? []).map(ma => multiaddr(ma))
|
|
235
|
+
|
|
236
|
+
this.inboundConnectionRateLimiter = new RateLimiterMemory({
|
|
237
|
+
points: this.opts.inboundConnectionThreshold,
|
|
238
|
+
duration: 1
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
this.incomingPendingConnections = 0
|
|
190
242
|
}
|
|
191
243
|
|
|
192
|
-
|
|
193
|
-
this.
|
|
244
|
+
isStarted () {
|
|
245
|
+
return this.started
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Starts the Connection Manager. If Metrics are not enabled on libp2p
|
|
250
|
+
* only event loop and connection limits will be monitored.
|
|
251
|
+
*/
|
|
252
|
+
async start () {
|
|
253
|
+
if (this.components.metrics != null) {
|
|
254
|
+
this.timer = this.timer ?? retimer(this._checkMetrics, this.opts.pollInterval)
|
|
255
|
+
}
|
|
194
256
|
|
|
195
257
|
// track inbound/outbound connections
|
|
196
|
-
this.components.
|
|
258
|
+
this.components.metrics?.updateComponentMetric({
|
|
197
259
|
system: METRICS_SYSTEM,
|
|
198
260
|
component: METRICS_COMPONENT,
|
|
199
261
|
metric: 'connections',
|
|
@@ -219,7 +281,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
219
281
|
})
|
|
220
282
|
|
|
221
283
|
// track total number of streams per protocol
|
|
222
|
-
this.components.
|
|
284
|
+
this.components.metrics?.updateComponentMetric({
|
|
223
285
|
system: METRICS_SYSTEM,
|
|
224
286
|
component: METRICS_COMPONENT,
|
|
225
287
|
metric: 'protocol-streams-total',
|
|
@@ -242,7 +304,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
242
304
|
})
|
|
243
305
|
|
|
244
306
|
// track 90th percentile of streams per protocol
|
|
245
|
-
this.components.
|
|
307
|
+
this.components.metrics?.updateComponentMetric({
|
|
246
308
|
system: METRICS_SYSTEM,
|
|
247
309
|
component: METRICS_COMPONENT,
|
|
248
310
|
metric: 'protocol-streams-per-connection-90th-percentile',
|
|
@@ -279,20 +341,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
279
341
|
return metric
|
|
280
342
|
}
|
|
281
343
|
})
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
isStarted () {
|
|
285
|
-
return this.started
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Starts the Connection Manager. If Metrics are not enabled on libp2p
|
|
290
|
-
* only event loop and connection limits will be monitored.
|
|
291
|
-
*/
|
|
292
|
-
async start () {
|
|
293
|
-
if (this.components.getMetrics() != null) {
|
|
294
|
-
this.timer = this.timer ?? retimer(this._checkMetrics, this.opts.pollInterval)
|
|
295
|
-
}
|
|
296
344
|
|
|
297
345
|
// latency monitor
|
|
298
346
|
this.latencyMonitor.start()
|
|
@@ -304,16 +352,16 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
304
352
|
}
|
|
305
353
|
|
|
306
354
|
async afterStart () {
|
|
307
|
-
this.components.
|
|
308
|
-
this.components.
|
|
355
|
+
this.components.upgrader.addEventListener('connection', this.onConnect)
|
|
356
|
+
this.components.upgrader.addEventListener('connectionEnd', this.onDisconnect)
|
|
309
357
|
|
|
310
358
|
// re-connect to any peers with the KEEP_ALIVE tag
|
|
311
359
|
void Promise.resolve()
|
|
312
360
|
.then(async () => {
|
|
313
361
|
const keepAlivePeers: PeerId[] = []
|
|
314
362
|
|
|
315
|
-
for (const peer of await this.components.
|
|
316
|
-
const tags = await this.components.
|
|
363
|
+
for (const peer of await this.components.peerStore.all()) {
|
|
364
|
+
const tags = await this.components.peerStore.getTags(peer.id)
|
|
317
365
|
const hasKeepAlive = tags.filter(tag => tag.name === KEEP_ALIVE).length > 0
|
|
318
366
|
|
|
319
367
|
if (hasKeepAlive) {
|
|
@@ -351,8 +399,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
351
399
|
async beforeStop () {
|
|
352
400
|
// if we are still dialing KEEP_ALIVE peers, abort those dials
|
|
353
401
|
this.connectOnStartupController?.abort()
|
|
354
|
-
this.components.
|
|
355
|
-
this.components.
|
|
402
|
+
this.components.upgrader.removeEventListener('connection', this.onConnect)
|
|
403
|
+
this.components.upgrader.removeEventListener('connectionEnd', this.onDisconnect)
|
|
356
404
|
}
|
|
357
405
|
|
|
358
406
|
/**
|
|
@@ -399,7 +447,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
399
447
|
* @private
|
|
400
448
|
*/
|
|
401
449
|
async _checkMetrics () {
|
|
402
|
-
const metrics = this.components.
|
|
450
|
+
const metrics = this.components.metrics
|
|
403
451
|
|
|
404
452
|
if (metrics != null) {
|
|
405
453
|
try {
|
|
@@ -446,7 +494,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
446
494
|
}
|
|
447
495
|
|
|
448
496
|
if (peerId.publicKey != null) {
|
|
449
|
-
await this.components.
|
|
497
|
+
await this.components.peerStore.keyBook.set(peerId, peerId.publicKey)
|
|
450
498
|
}
|
|
451
499
|
|
|
452
500
|
const numConnections = this.getConnections().length
|
|
@@ -477,7 +525,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
477
525
|
this.connections.delete(peerId)
|
|
478
526
|
this.dispatchEvent(new CustomEvent<Connection>('peer:disconnect', { detail: connection }))
|
|
479
527
|
|
|
480
|
-
this.components.
|
|
528
|
+
this.components.metrics?.onPeerDisconnected(connection.remotePeer)
|
|
481
529
|
}
|
|
482
530
|
}
|
|
483
531
|
|
|
@@ -518,7 +566,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
518
566
|
}
|
|
519
567
|
|
|
520
568
|
try {
|
|
521
|
-
const connection = await this.components.
|
|
569
|
+
const connection = await this.components.dialer.dial(peerId, options)
|
|
522
570
|
let peerConnections = this.connections.get(peerId.toString())
|
|
523
571
|
|
|
524
572
|
if (peerConnections == null) {
|
|
@@ -597,8 +645,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
597
645
|
const limit = this.opts[name]
|
|
598
646
|
log.trace('checking limit of %s. current value: %d of %d', name, value, limit)
|
|
599
647
|
if (value > limit) {
|
|
600
|
-
log('%s: limit exceeded: %p, %d/%d, pruning %d connection(s)', this.components.
|
|
601
|
-
await this.
|
|
648
|
+
log('%s: limit exceeded: %p, %d/%d, pruning %d connection(s)', this.components.peerId, name, value, limit, toPrune)
|
|
649
|
+
await this._pruneConnections(toPrune)
|
|
602
650
|
}
|
|
603
651
|
}
|
|
604
652
|
|
|
@@ -606,13 +654,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
606
654
|
* If we have more connections than our maximum, select some excess connections
|
|
607
655
|
* to prune based on peer value
|
|
608
656
|
*/
|
|
609
|
-
async
|
|
657
|
+
async _pruneConnections (toPrune: number) {
|
|
610
658
|
const connections = this.getConnections()
|
|
611
|
-
|
|
612
|
-
if (connections.length <= this.opts.minConnections || toPrune < 1) {
|
|
613
|
-
return
|
|
614
|
-
}
|
|
615
|
-
|
|
616
659
|
const peerValues = new PeerMap<number>()
|
|
617
660
|
|
|
618
661
|
// work out peer values
|
|
@@ -623,7 +666,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
623
666
|
continue
|
|
624
667
|
}
|
|
625
668
|
|
|
626
|
-
const tags = await this.components.
|
|
669
|
+
const tags = await this.components.peerStore.getTags(remotePeer)
|
|
627
670
|
|
|
628
671
|
// sum all tag values
|
|
629
672
|
peerValues.set(remotePeer, tags.reduce((acc, curr) => {
|
|
@@ -677,6 +720,55 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
677
720
|
}
|
|
678
721
|
|
|
679
722
|
async acceptIncomingConnection (maConn: MultiaddrConnection): Promise<boolean> {
|
|
680
|
-
|
|
723
|
+
// check deny list
|
|
724
|
+
const denyConnection = this.deny.some(ma => {
|
|
725
|
+
return maConn.remoteAddr.toString().startsWith(ma.toString())
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
if (denyConnection) {
|
|
729
|
+
log('connection from %s refused - connection remote address was in deny list', maConn.remoteAddr)
|
|
730
|
+
return false
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
// check allow list
|
|
734
|
+
const allowConnection = this.allow.some(ma => {
|
|
735
|
+
return maConn.remoteAddr.toString().startsWith(ma.toString())
|
|
736
|
+
})
|
|
737
|
+
|
|
738
|
+
if (allowConnection) {
|
|
739
|
+
this.incomingPendingConnections++
|
|
740
|
+
|
|
741
|
+
return true
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// check pending connections
|
|
745
|
+
if (this.incomingPendingConnections === this.opts.maxIncomingPendingConnections) {
|
|
746
|
+
log('connection from %s refused - incomingPendingConnections exceeded by peer %s', maConn.remoteAddr)
|
|
747
|
+
return false
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
if (maConn.remoteAddr.isThinWaistAddress()) {
|
|
751
|
+
const host = maConn.remoteAddr.nodeAddress().address
|
|
752
|
+
|
|
753
|
+
try {
|
|
754
|
+
await this.inboundConnectionRateLimiter.consume(host, 1)
|
|
755
|
+
} catch {
|
|
756
|
+
log('connection from %s refused - inboundConnectionThreshold exceeded by host %s', host, maConn.remoteAddr)
|
|
757
|
+
return false
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
if (this.getConnections().length < this.opts.maxConnections) {
|
|
762
|
+
this.incomingPendingConnections++
|
|
763
|
+
|
|
764
|
+
return true
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
log('connection from %s refused - maxConnections exceeded', maConn.remoteAddr)
|
|
768
|
+
return false
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
afterUpgradeInbound () {
|
|
772
|
+
this.incomingPendingConnections--
|
|
681
773
|
}
|
|
682
774
|
}
|
|
@@ -12,18 +12,24 @@ import type { ContentRouting } from '@libp2p/interface-content-routing'
|
|
|
12
12
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
13
13
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
14
14
|
import type { CID } from 'multiformats/cid'
|
|
15
|
-
import type {
|
|
15
|
+
import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
16
|
+
import type { DualDHT } from '@libp2p/interface-dht'
|
|
16
17
|
|
|
17
18
|
export interface CompoundContentRoutingInit {
|
|
18
19
|
routers: ContentRouting[]
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
export interface CompoundContentRoutingComponents {
|
|
23
|
+
peerStore: PeerStore
|
|
24
|
+
dht?: DualDHT
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
export class CompoundContentRouting implements ContentRouting, Startable {
|
|
22
28
|
private readonly routers: ContentRouting[]
|
|
23
29
|
private started: boolean
|
|
24
|
-
private readonly components:
|
|
30
|
+
private readonly components: CompoundContentRoutingComponents
|
|
25
31
|
|
|
26
|
-
constructor (components:
|
|
32
|
+
constructor (components: CompoundContentRoutingComponents, init: CompoundContentRoutingInit) {
|
|
27
33
|
this.routers = init.routers ?? []
|
|
28
34
|
this.started = false
|
|
29
35
|
this.components = components
|
|
@@ -53,7 +59,7 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
53
59
|
merge(
|
|
54
60
|
...this.routers.map(router => router.findProviders(key, options))
|
|
55
61
|
),
|
|
56
|
-
(source) => storeAddresses(source, this.components.
|
|
62
|
+
(source) => storeAddresses(source, this.components.peerStore),
|
|
57
63
|
(source) => uniquePeers(source),
|
|
58
64
|
(source) => requirePeers(source)
|
|
59
65
|
)
|
|
@@ -79,7 +85,7 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
79
85
|
throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED)
|
|
80
86
|
}
|
|
81
87
|
|
|
82
|
-
const dht = this.components.
|
|
88
|
+
const dht = this.components.dht
|
|
83
89
|
|
|
84
90
|
if (dht != null) {
|
|
85
91
|
await drain(dht.put(key, value, options))
|
|
@@ -95,7 +101,7 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
95
101
|
throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED)
|
|
96
102
|
}
|
|
97
103
|
|
|
98
|
-
const dht = this.components.
|
|
104
|
+
const dht = this.components.dht
|
|
99
105
|
|
|
100
106
|
if (dht != null) {
|
|
101
107
|
for await (const event of dht.get(key, options)) {
|
|
@@ -121,7 +127,7 @@ export class CompoundContentRouting implements ContentRouting, Startable {
|
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
let gotValues = 0
|
|
124
|
-
const dht = this.components.
|
|
130
|
+
const dht = this.components.dht
|
|
125
131
|
|
|
126
132
|
if (dht != null) {
|
|
127
133
|
for await (const event of dht.get(key, options)) {
|
package/src/errors.ts
CHANGED
|
@@ -73,5 +73,6 @@ export enum codes {
|
|
|
73
73
|
ERR_ALREADY_SUCCEEDED = 'ERR_ALREADY_SUCCEEDED',
|
|
74
74
|
ERR_NO_HANDLER_FOR_PROTOCOL = 'ERR_NO_HANDLER_FOR_PROTOCOL',
|
|
75
75
|
ERR_TOO_MANY_OUTBOUND_PROTOCOL_STREAMS = 'ERR_TOO_MANY_OUTBOUND_PROTOCOL_STREAMS',
|
|
76
|
-
ERR_TOO_MANY_INBOUND_PROTOCOL_STREAMS = 'ERR_TOO_MANY_INBOUND_PROTOCOL_STREAMS'
|
|
76
|
+
ERR_TOO_MANY_INBOUND_PROTOCOL_STREAMS = 'ERR_TOO_MANY_INBOUND_PROTOCOL_STREAMS',
|
|
77
|
+
ERR_CONNECTION_DENIED = 'ERR_CONNECTION_DENIED'
|
|
77
78
|
}
|
package/src/fetch/index.ts
CHANGED
|
@@ -7,14 +7,14 @@ import { PROTOCOL_NAME, PROTOCOL_VERSION } from './constants.js'
|
|
|
7
7
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
8
8
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
9
9
|
import type { Stream } from '@libp2p/interface-connection'
|
|
10
|
-
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
|
11
|
-
import type { Components } from '@libp2p/components'
|
|
10
|
+
import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
|
|
12
11
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
13
12
|
import { abortableDuplex } from 'abortable-iterator'
|
|
14
13
|
import { pipe } from 'it-pipe'
|
|
15
14
|
import first from 'it-first'
|
|
16
15
|
import { TimeoutController } from 'timeout-abort-controller'
|
|
17
16
|
import { setMaxListeners } from 'events'
|
|
17
|
+
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
18
18
|
|
|
19
19
|
const log = logger('libp2p:fetch')
|
|
20
20
|
|
|
@@ -38,6 +38,11 @@ export interface LookupFunction {
|
|
|
38
38
|
(key: string): Promise<Uint8Array | null>
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
export interface FetchServiceComponents {
|
|
42
|
+
registrar: Registrar
|
|
43
|
+
connectionManager: ConnectionManager
|
|
44
|
+
}
|
|
45
|
+
|
|
41
46
|
/**
|
|
42
47
|
* A simple libp2p protocol for requesting a value corresponding to a key from a peer.
|
|
43
48
|
* Developers can register one or more lookup function for retrieving the value corresponding to
|
|
@@ -46,12 +51,12 @@ export interface LookupFunction {
|
|
|
46
51
|
*/
|
|
47
52
|
export class FetchService implements Startable {
|
|
48
53
|
public readonly protocol: string
|
|
49
|
-
private readonly components:
|
|
54
|
+
private readonly components: FetchServiceComponents
|
|
50
55
|
private readonly lookupFunctions: Map<string, LookupFunction>
|
|
51
56
|
private started: boolean
|
|
52
57
|
private readonly init: FetchServiceInit
|
|
53
58
|
|
|
54
|
-
constructor (components:
|
|
59
|
+
constructor (components: FetchServiceComponents, init: FetchServiceInit) {
|
|
55
60
|
this.started = false
|
|
56
61
|
this.components = components
|
|
57
62
|
this.protocol = `/${init.protocolPrefix ?? 'libp2p'}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`
|
|
@@ -61,7 +66,7 @@ export class FetchService implements Startable {
|
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
async start () {
|
|
64
|
-
await this.components.
|
|
69
|
+
await this.components.registrar.handle(this.protocol, (data) => {
|
|
65
70
|
void this.handleMessage(data)
|
|
66
71
|
.catch(err => {
|
|
67
72
|
log.error(err)
|
|
@@ -77,7 +82,7 @@ export class FetchService implements Startable {
|
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
async stop () {
|
|
80
|
-
await this.components.
|
|
85
|
+
await this.components.registrar.unhandle(this.protocol)
|
|
81
86
|
this.started = false
|
|
82
87
|
}
|
|
83
88
|
|
|
@@ -91,7 +96,7 @@ export class FetchService implements Startable {
|
|
|
91
96
|
async fetch (peer: PeerId, key: string, options: AbortOptions = {}): Promise<Uint8Array | null> {
|
|
92
97
|
log('dialing %s to %p', this.protocol, peer)
|
|
93
98
|
|
|
94
|
-
const connection = await this.components.
|
|
99
|
+
const connection = await this.components.connectionManager.openConnection(peer, options)
|
|
95
100
|
let timeoutController
|
|
96
101
|
let signal = options.signal
|
|
97
102
|
let stream: Stream | undefined
|
package/src/fetch/pb/proto.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* eslint-disable import/export */
|
|
2
|
+
/* eslint-disable complexity */
|
|
2
3
|
/* eslint-disable @typescript-eslint/no-namespace */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
|
|
3
5
|
|
|
4
6
|
import { encodeMessage, decodeMessage, message, enumeration } from 'protons-runtime'
|
|
5
7
|
import type { Uint8ArrayList } from 'uint8arraylist'
|
|
@@ -14,23 +16,23 @@ export namespace FetchRequest {
|
|
|
14
16
|
|
|
15
17
|
export const codec = (): Codec<FetchRequest> => {
|
|
16
18
|
if (_codec == null) {
|
|
17
|
-
_codec = message<FetchRequest>((obj,
|
|
19
|
+
_codec = message<FetchRequest>((obj, w, opts = {}) => {
|
|
18
20
|
if (opts.lengthDelimited !== false) {
|
|
19
|
-
|
|
21
|
+
w.fork()
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
if (obj.identifier
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
} else {
|
|
26
|
-
throw new Error('Protocol error: required field "identifier" was not found in object')
|
|
24
|
+
if (opts.writeDefaults === true || obj.identifier !== '') {
|
|
25
|
+
w.uint32(10)
|
|
26
|
+
w.string(obj.identifier)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (opts.lengthDelimited !== false) {
|
|
30
|
-
|
|
30
|
+
w.ldelim()
|
|
31
31
|
}
|
|
32
32
|
}, (reader, length) => {
|
|
33
|
-
const obj: any = {
|
|
33
|
+
const obj: any = {
|
|
34
|
+
identifier: ''
|
|
35
|
+
}
|
|
34
36
|
|
|
35
37
|
const end = length == null ? reader.len : reader.pos + length
|
|
36
38
|
|
|
@@ -47,10 +49,6 @@ export namespace FetchRequest {
|
|
|
47
49
|
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
if (obj.identifier == null) {
|
|
51
|
-
throw new Error('Protocol error: value for required field "identifier" was not found in protobuf')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
52
|
return obj
|
|
55
53
|
})
|
|
56
54
|
}
|
|
@@ -95,30 +93,29 @@ export namespace FetchResponse {
|
|
|
95
93
|
|
|
96
94
|
export const codec = (): Codec<FetchResponse> => {
|
|
97
95
|
if (_codec == null) {
|
|
98
|
-
_codec = message<FetchResponse>((obj,
|
|
96
|
+
_codec = message<FetchResponse>((obj, w, opts = {}) => {
|
|
99
97
|
if (opts.lengthDelimited !== false) {
|
|
100
|
-
|
|
98
|
+
w.fork()
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
if (obj.status != null) {
|
|
104
|
-
|
|
105
|
-
FetchResponse.StatusCode.codec().encode(obj.status,
|
|
106
|
-
} else {
|
|
107
|
-
throw new Error('Protocol error: required field "status" was not found in object')
|
|
101
|
+
if (opts.writeDefaults === true || (obj.status != null && __StatusCodeValues[obj.status] !== 0)) {
|
|
102
|
+
w.uint32(8)
|
|
103
|
+
FetchResponse.StatusCode.codec().encode(obj.status, w)
|
|
108
104
|
}
|
|
109
105
|
|
|
110
|
-
if (obj.data != null) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} else {
|
|
114
|
-
throw new Error('Protocol error: required field "data" was not found in object')
|
|
106
|
+
if (opts.writeDefaults === true || (obj.data != null && obj.data.byteLength > 0)) {
|
|
107
|
+
w.uint32(18)
|
|
108
|
+
w.bytes(obj.data)
|
|
115
109
|
}
|
|
116
110
|
|
|
117
111
|
if (opts.lengthDelimited !== false) {
|
|
118
|
-
|
|
112
|
+
w.ldelim()
|
|
119
113
|
}
|
|
120
114
|
}, (reader, length) => {
|
|
121
|
-
const obj: any = {
|
|
115
|
+
const obj: any = {
|
|
116
|
+
status: StatusCode.OK,
|
|
117
|
+
data: new Uint8Array(0)
|
|
118
|
+
}
|
|
122
119
|
|
|
123
120
|
const end = length == null ? reader.len : reader.pos + length
|
|
124
121
|
|
|
@@ -138,14 +135,6 @@ export namespace FetchResponse {
|
|
|
138
135
|
}
|
|
139
136
|
}
|
|
140
137
|
|
|
141
|
-
if (obj.status == null) {
|
|
142
|
-
throw new Error('Protocol error: value for required field "status" was not found in protobuf')
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (obj.data == null) {
|
|
146
|
-
throw new Error('Protocol error: value for required field "data" was not found in protobuf')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
138
|
return obj
|
|
150
139
|
})
|
|
151
140
|
}
|