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.
Files changed (150) hide show
  1. package/README.md +5 -0
  2. package/dist/src/address-manager/index.d.ts +18 -2
  3. package/dist/src/address-manager/index.d.ts.map +1 -1
  4. package/dist/src/address-manager/index.js +18 -5
  5. package/dist/src/address-manager/index.js.map +1 -1
  6. package/dist/src/circuit/auto-relay.d.ts +2 -2
  7. package/dist/src/circuit/auto-relay.d.ts.map +1 -1
  8. package/dist/src/circuit/auto-relay.js +12 -12
  9. package/dist/src/circuit/auto-relay.js.map +1 -1
  10. package/dist/src/circuit/index.d.ts +13 -3
  11. package/dist/src/circuit/index.d.ts.map +1 -1
  12. package/dist/src/circuit/index.js +1 -1
  13. package/dist/src/circuit/index.js.map +1 -1
  14. package/dist/src/circuit/pb/index.d.ts.map +1 -1
  15. package/dist/src/circuit/pb/index.js +29 -34
  16. package/dist/src/circuit/pb/index.js.map +1 -1
  17. package/dist/src/circuit/transport.d.ts +22 -7
  18. package/dist/src/circuit/transport.d.ts.map +1 -1
  19. package/dist/src/circuit/transport.js +26 -17
  20. package/dist/src/circuit/transport.js.map +1 -1
  21. package/dist/src/components.d.ts +110 -0
  22. package/dist/src/components.d.ts.map +1 -0
  23. package/dist/src/components.js +199 -0
  24. package/dist/src/components.js.map +1 -0
  25. package/dist/src/connection-manager/auto-dialler.d.ts +9 -2
  26. package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
  27. package/dist/src/connection-manager/auto-dialler.js +6 -6
  28. package/dist/src/connection-manager/auto-dialler.js.map +1 -1
  29. package/dist/src/connection-manager/dialer/index.d.ts +12 -5
  30. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  31. package/dist/src/connection-manager/dialer/index.js +9 -9
  32. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  33. package/dist/src/connection-manager/index.d.ts +41 -9
  34. package/dist/src/connection-manager/index.d.ts.map +1 -1
  35. package/dist/src/connection-manager/index.js +82 -39
  36. package/dist/src/connection-manager/index.js.map +1 -1
  37. package/dist/src/content-routing/index.d.ts +7 -2
  38. package/dist/src/content-routing/index.d.ts.map +1 -1
  39. package/dist/src/content-routing/index.js +4 -4
  40. package/dist/src/content-routing/index.js.map +1 -1
  41. package/dist/src/content-routing/utils.d.ts +1 -1
  42. package/dist/src/content-routing/utils.d.ts.map +1 -1
  43. package/dist/src/errors.d.ts +2 -1
  44. package/dist/src/errors.d.ts.map +1 -1
  45. package/dist/src/errors.js +1 -0
  46. package/dist/src/errors.js.map +1 -1
  47. package/dist/src/fetch/index.d.ts +7 -3
  48. package/dist/src/fetch/index.d.ts.map +1 -1
  49. package/dist/src/fetch/index.js +3 -3
  50. package/dist/src/fetch/index.js.map +1 -1
  51. package/dist/src/fetch/pb/proto.d.ts.map +1 -1
  52. package/dist/src/fetch/pb/proto.js +24 -35
  53. package/dist/src/fetch/pb/proto.js.map +1 -1
  54. package/dist/src/identify/index.d.ts +13 -3
  55. package/dist/src/identify/index.d.ts.map +1 -1
  56. package/dist/src/identify/index.js +41 -41
  57. package/dist/src/identify/index.js.map +1 -1
  58. package/dist/src/identify/pb/message.d.ts.map +1 -1
  59. package/dist/src/identify/pb/message.js +23 -34
  60. package/dist/src/identify/pb/message.js.map +1 -1
  61. package/dist/src/index.d.ts +10 -9
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js.map +1 -1
  64. package/dist/src/insecure/index.d.ts +2 -8
  65. package/dist/src/insecure/index.d.ts.map +1 -1
  66. package/dist/src/insecure/index.js +5 -3
  67. package/dist/src/insecure/index.js.map +1 -1
  68. package/dist/src/insecure/pb/proto.d.ts.map +1 -1
  69. package/dist/src/insecure/pb/proto.js +24 -29
  70. package/dist/src/insecure/pb/proto.js.map +1 -1
  71. package/dist/src/keychain/index.d.ts +6 -2
  72. package/dist/src/keychain/index.d.ts.map +1 -1
  73. package/dist/src/keychain/index.js +19 -19
  74. package/dist/src/keychain/index.js.map +1 -1
  75. package/dist/src/libp2p.d.ts +1 -2
  76. package/dist/src/libp2p.d.ts.map +1 -1
  77. package/dist/src/libp2p.js +48 -71
  78. package/dist/src/libp2p.js.map +1 -1
  79. package/dist/src/nat-manager.d.ts +9 -2
  80. package/dist/src/nat-manager.d.ts.map +1 -1
  81. package/dist/src/nat-manager.js +3 -3
  82. package/dist/src/nat-manager.js.map +1 -1
  83. package/dist/src/peer-record-updater.d.ts +11 -2
  84. package/dist/src/peer-record-updater.d.ts.map +1 -1
  85. package/dist/src/peer-record-updater.js +10 -10
  86. package/dist/src/peer-record-updater.js.map +1 -1
  87. package/dist/src/peer-routing.d.ts +6 -2
  88. package/dist/src/peer-routing.d.ts.map +1 -1
  89. package/dist/src/peer-routing.js +4 -4
  90. package/dist/src/peer-routing.js.map +1 -1
  91. package/dist/src/ping/index.d.ts +7 -3
  92. package/dist/src/ping/index.d.ts.map +1 -1
  93. package/dist/src/ping/index.js +3 -3
  94. package/dist/src/ping/index.js.map +1 -1
  95. package/dist/src/pnet/index.d.ts +2 -17
  96. package/dist/src/pnet/index.d.ts.map +1 -1
  97. package/dist/src/pnet/index.js +4 -1
  98. package/dist/src/pnet/index.js.map +1 -1
  99. package/dist/src/pubsub/dummy-pubsub.d.ts +2 -1
  100. package/dist/src/pubsub/dummy-pubsub.d.ts.map +1 -1
  101. package/dist/src/pubsub/dummy-pubsub.js +4 -0
  102. package/dist/src/pubsub/dummy-pubsub.js.map +1 -1
  103. package/dist/src/registrar.d.ts +9 -3
  104. package/dist/src/registrar.d.ts.map +1 -1
  105. package/dist/src/registrar.js +6 -6
  106. package/dist/src/registrar.js.map +1 -1
  107. package/dist/src/transport-manager.d.ts +9 -3
  108. package/dist/src/transport-manager.d.ts.map +1 -1
  109. package/dist/src/transport-manager.js +4 -4
  110. package/dist/src/transport-manager.js.map +1 -1
  111. package/dist/src/upgrader.d.ts +17 -5
  112. package/dist/src/upgrader.d.ts.map +1 -1
  113. package/dist/src/upgrader.js +55 -43
  114. package/dist/src/upgrader.js.map +1 -1
  115. package/package.json +37 -37
  116. package/src/address-manager/index.ts +31 -8
  117. package/src/circuit/auto-relay.ts +15 -15
  118. package/src/circuit/index.ts +16 -5
  119. package/src/circuit/pb/index.ts +29 -35
  120. package/src/circuit/transport.ts +49 -20
  121. package/src/components.ts +332 -0
  122. package/src/connection-manager/auto-dialler.ts +17 -9
  123. package/src/connection-manager/dialer/index.ts +23 -15
  124. package/src/connection-manager/index.ts +139 -47
  125. package/src/content-routing/index.ts +13 -7
  126. package/src/errors.ts +2 -1
  127. package/src/fetch/index.ts +12 -7
  128. package/src/fetch/pb/proto.ts +24 -35
  129. package/src/identify/index.ts +57 -53
  130. package/src/identify/pb/message.ts +23 -35
  131. package/src/index.ts +10 -9
  132. package/src/insecure/index.ts +6 -3
  133. package/src/insecure/pb/proto.ts +24 -29
  134. package/src/keychain/index.ts +27 -22
  135. package/src/libp2p.ts +49 -77
  136. package/src/nat-manager.ts +14 -6
  137. package/src/peer-record-updater.ts +23 -13
  138. package/src/peer-routing.ts +12 -7
  139. package/src/ping/index.ts +12 -7
  140. package/src/pnet/index.ts +5 -1
  141. package/src/pubsub/dummy-pubsub.ts +3 -1
  142. package/src/registrar.ts +17 -10
  143. package/src/transport-manager.ts +15 -8
  144. package/src/upgrader.ts +75 -49
  145. package/src/version.ts +1 -1
  146. package/dist/src/connection-manager/dialer/auto-dialer.d.ts +0 -16
  147. package/dist/src/connection-manager/dialer/auto-dialer.d.ts.map +0 -1
  148. package/dist/src/connection-manager/dialer/auto-dialer.js +0 -43
  149. package/dist/src/connection-manager/dialer/auto-dialer.js.map +0 -1
  150. 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 type { Resolver } from '@multiformats/multiaddr'
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, Initializable {
146
- private components = new 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
- init (components: Components): void {
193
- this.components = components
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.getMetrics()?.updateComponentMetric({
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.getMetrics()?.updateComponentMetric({
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.getMetrics()?.updateComponentMetric({
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.getUpgrader().addEventListener('connection', this.onConnect)
308
- this.components.getUpgrader().addEventListener('connectionEnd', this.onDisconnect)
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.getPeerStore().all()) {
316
- const tags = await this.components.getPeerStore().getTags(peer.id)
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.getUpgrader().removeEventListener('connection', this.onConnect)
355
- this.components.getUpgrader().removeEventListener('connectionEnd', this.onDisconnect)
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.getMetrics()
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.getPeerStore().keyBook.set(peerId, peerId.publicKey)
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.getMetrics()?.onPeerDisconnected(connection.remotePeer)
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.getDialer().dial(peerId, options)
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.getPeerId(), name, value, limit, toPrune)
601
- await this._maybePruneConnections(toPrune)
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 _maybePruneConnections (toPrune: number) {
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.getPeerStore().getTags(remotePeer)
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
- return true
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 { Components } from '@libp2p/components'
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: Components
30
+ private readonly components: CompoundContentRoutingComponents
25
31
 
26
- constructor (components: Components, init: CompoundContentRoutingInit) {
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.getPeerStore()),
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.getDHT()
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.getDHT()
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.getDHT()
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
  }
@@ -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: 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: Components, init: FetchServiceInit) {
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.getRegistrar().handle(this.protocol, (data) => {
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.getRegistrar().unhandle(this.protocol)
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.getConnectionManager().openConnection(peer, options)
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
@@ -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, writer, opts = {}) => {
19
+ _codec = message<FetchRequest>((obj, w, opts = {}) => {
18
20
  if (opts.lengthDelimited !== false) {
19
- writer.fork()
21
+ w.fork()
20
22
  }
21
23
 
22
- if (obj.identifier != null) {
23
- writer.uint32(10)
24
- writer.string(obj.identifier)
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
- writer.ldelim()
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, writer, opts = {}) => {
96
+ _codec = message<FetchResponse>((obj, w, opts = {}) => {
99
97
  if (opts.lengthDelimited !== false) {
100
- writer.fork()
98
+ w.fork()
101
99
  }
102
100
 
103
- if (obj.status != null) {
104
- writer.uint32(8)
105
- FetchResponse.StatusCode.codec().encode(obj.status, writer)
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
- writer.uint32(18)
112
- writer.bytes(obj.data)
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
- writer.ldelim()
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
  }