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.
Files changed (188) hide show
  1. package/dist/index.min.js +30 -30
  2. package/dist/src/address-manager/index.d.ts +8 -4
  3. package/dist/src/address-manager/index.d.ts.map +1 -1
  4. package/dist/src/address-manager/index.js +37 -6
  5. package/dist/src/address-manager/index.js.map +1 -1
  6. package/dist/src/address-manager/utils.d.ts +2 -0
  7. package/dist/src/address-manager/utils.d.ts.map +1 -0
  8. package/dist/src/address-manager/utils.js +12 -0
  9. package/dist/src/address-manager/utils.js.map +1 -0
  10. package/dist/src/autonat/constants.d.ts +16 -2
  11. package/dist/src/autonat/constants.d.ts.map +1 -1
  12. package/dist/src/autonat/constants.js +16 -2
  13. package/dist/src/autonat/constants.js.map +1 -1
  14. package/dist/src/autonat/index.d.ts +12 -33
  15. package/dist/src/autonat/index.d.ts.map +1 -1
  16. package/dist/src/autonat/index.js +36 -30
  17. package/dist/src/autonat/index.js.map +1 -1
  18. package/dist/src/circuit-relay/server/advert-service.d.ts.map +1 -1
  19. package/dist/src/circuit-relay/server/advert-service.js +2 -2
  20. package/dist/src/circuit-relay/server/advert-service.js.map +1 -1
  21. package/dist/src/circuit-relay/server/index.d.ts.map +1 -1
  22. package/dist/src/circuit-relay/server/index.js +10 -3
  23. package/dist/src/circuit-relay/server/index.js.map +1 -1
  24. package/dist/src/circuit-relay/transport/discovery.d.ts.map +1 -1
  25. package/dist/src/circuit-relay/transport/discovery.js +4 -2
  26. package/dist/src/circuit-relay/transport/discovery.js.map +1 -1
  27. package/dist/src/circuit-relay/transport/index.d.ts +3 -0
  28. package/dist/src/circuit-relay/transport/index.d.ts.map +1 -1
  29. package/dist/src/circuit-relay/transport/index.js +6 -4
  30. package/dist/src/circuit-relay/transport/index.js.map +1 -1
  31. package/dist/src/circuit-relay/transport/listener.d.ts.map +1 -1
  32. package/dist/src/circuit-relay/transport/listener.js +30 -26
  33. package/dist/src/circuit-relay/transport/listener.js.map +1 -1
  34. package/dist/src/circuit-relay/transport/reservation-store.d.ts +5 -4
  35. package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
  36. package/dist/src/circuit-relay/transport/reservation-store.js +37 -30
  37. package/dist/src/circuit-relay/transport/reservation-store.js.map +1 -1
  38. package/dist/src/components.d.ts +6 -63
  39. package/dist/src/components.d.ts.map +1 -1
  40. package/dist/src/components.js +60 -164
  41. package/dist/src/components.js.map +1 -1
  42. package/dist/src/config/connection-gater.browser.d.ts +8 -0
  43. package/dist/src/config/connection-gater.browser.d.ts.map +1 -0
  44. package/dist/src/config/connection-gater.browser.js +27 -0
  45. package/dist/src/config/connection-gater.browser.js.map +1 -0
  46. package/dist/src/config/connection-gater.d.ts +6 -0
  47. package/dist/src/config/connection-gater.d.ts.map +1 -0
  48. package/dist/src/config/connection-gater.js +18 -0
  49. package/dist/src/config/connection-gater.js.map +1 -0
  50. package/dist/src/config.d.ts +2 -1
  51. package/dist/src/config.d.ts.map +1 -1
  52. package/dist/src/config.js +0 -62
  53. package/dist/src/config.js.map +1 -1
  54. package/dist/src/connection-manager/auto-dial.d.ts +3 -0
  55. package/dist/src/connection-manager/auto-dial.d.ts.map +1 -1
  56. package/dist/src/connection-manager/auto-dial.js +36 -13
  57. package/dist/src/connection-manager/auto-dial.js.map +1 -1
  58. package/dist/src/connection-manager/connection-pruner.d.ts +4 -0
  59. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
  60. package/dist/src/connection-manager/connection-pruner.js +23 -8
  61. package/dist/src/connection-manager/connection-pruner.js.map +1 -1
  62. package/dist/src/connection-manager/dial-queue.d.ts +2 -1
  63. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
  64. package/dist/src/connection-manager/dial-queue.js +36 -14
  65. package/dist/src/connection-manager/dial-queue.js.map +1 -1
  66. package/dist/src/connection-manager/index.d.ts +8 -7
  67. package/dist/src/connection-manager/index.d.ts.map +1 -1
  68. package/dist/src/connection-manager/index.js +23 -34
  69. package/dist/src/connection-manager/index.js.map +1 -1
  70. package/dist/src/content-routing/index.d.ts +0 -10
  71. package/dist/src/content-routing/index.d.ts.map +1 -1
  72. package/dist/src/content-routing/index.js +7 -42
  73. package/dist/src/content-routing/index.js.map +1 -1
  74. package/dist/src/content-routing/utils.d.ts.map +1 -1
  75. package/dist/src/content-routing/utils.js +3 -1
  76. package/dist/src/content-routing/utils.js.map +1 -1
  77. package/dist/src/fetch/index.d.ts +13 -35
  78. package/dist/src/fetch/index.d.ts.map +1 -1
  79. package/dist/src/fetch/index.js +7 -9
  80. package/dist/src/fetch/index.js.map +1 -1
  81. package/dist/src/identify/identify.d.ts +53 -0
  82. package/dist/src/identify/identify.d.ts.map +1 -0
  83. package/dist/src/identify/identify.js +405 -0
  84. package/dist/src/identify/identify.js.map +1 -0
  85. package/dist/src/identify/index.d.ts +12 -58
  86. package/dist/src/identify/index.d.ts.map +1 -1
  87. package/dist/src/identify/index.js +5 -388
  88. package/dist/src/identify/index.js.map +1 -1
  89. package/dist/src/index.d.ts +13 -68
  90. package/dist/src/index.d.ts.map +1 -1
  91. package/dist/src/index.js +2 -1
  92. package/dist/src/index.js.map +1 -1
  93. package/dist/src/insecure/index.js.map +1 -1
  94. package/dist/src/libp2p.d.ts +11 -42
  95. package/dist/src/libp2p.d.ts.map +1 -1
  96. package/dist/src/libp2p.js +137 -196
  97. package/dist/src/libp2p.js.map +1 -1
  98. package/dist/src/peer-routing.d.ts +1 -38
  99. package/dist/src/peer-routing.d.ts.map +1 -1
  100. package/dist/src/peer-routing.js +0 -59
  101. package/dist/src/peer-routing.js.map +1 -1
  102. package/dist/src/ping/constants.d.ts +4 -0
  103. package/dist/src/ping/constants.d.ts.map +1 -1
  104. package/dist/src/ping/constants.js +10 -0
  105. package/dist/src/ping/constants.js.map +1 -1
  106. package/dist/src/ping/index.d.ts +10 -27
  107. package/dist/src/ping/index.d.ts.map +1 -1
  108. package/dist/src/ping/index.js +18 -21
  109. package/dist/src/ping/index.js.map +1 -1
  110. package/dist/src/registrar.d.ts +5 -2
  111. package/dist/src/registrar.d.ts.map +1 -1
  112. package/dist/src/registrar.js +27 -25
  113. package/dist/src/registrar.js.map +1 -1
  114. package/dist/src/transport-manager.d.ts +11 -4
  115. package/dist/src/transport-manager.d.ts.map +1 -1
  116. package/dist/src/transport-manager.js +19 -10
  117. package/dist/src/transport-manager.js.map +1 -1
  118. package/dist/src/upgrader.d.ts +15 -10
  119. package/dist/src/upgrader.d.ts.map +1 -1
  120. package/dist/src/upgrader.js +39 -48
  121. package/dist/src/upgrader.js.map +1 -1
  122. package/dist/src/upnp-nat/index.d.ts +42 -0
  123. package/dist/src/upnp-nat/index.d.ts.map +1 -0
  124. package/dist/src/{nat-manager.js → upnp-nat/index.js} +11 -7
  125. package/dist/src/upnp-nat/index.js.map +1 -0
  126. package/dist/src/version.d.ts +1 -1
  127. package/dist/src/version.d.ts.map +1 -1
  128. package/dist/src/version.js +1 -1
  129. package/dist/src/version.js.map +1 -1
  130. package/dist/typedoc-urls.json +25 -10
  131. package/package.json +61 -45
  132. package/src/address-manager/index.ts +50 -8
  133. package/src/address-manager/utils.ts +14 -0
  134. package/src/autonat/constants.ts +17 -2
  135. package/src/autonat/index.ts +53 -45
  136. package/src/circuit-relay/server/advert-service.ts +2 -2
  137. package/src/circuit-relay/server/index.ts +11 -3
  138. package/src/circuit-relay/transport/discovery.ts +5 -3
  139. package/src/circuit-relay/transport/index.ts +9 -4
  140. package/src/circuit-relay/transport/listener.ts +38 -28
  141. package/src/circuit-relay/transport/reservation-store.ts +34 -20
  142. package/src/components.ts +71 -234
  143. package/src/config/connection-gater.browser.ts +31 -0
  144. package/src/config/connection-gater.ts +19 -0
  145. package/src/config.ts +3 -64
  146. package/src/connection-manager/auto-dial.ts +44 -15
  147. package/src/connection-manager/connection-pruner.ts +28 -8
  148. package/src/connection-manager/dial-queue.ts +41 -21
  149. package/src/connection-manager/index.ts +31 -43
  150. package/src/content-routing/index.ts +7 -55
  151. package/src/content-routing/utils.ts +3 -1
  152. package/src/fetch/index.ts +51 -14
  153. package/src/identify/identify.ts +518 -0
  154. package/src/identify/index.ts +17 -507
  155. package/src/index.ts +14 -77
  156. package/src/insecure/index.ts +4 -4
  157. package/src/libp2p.ts +139 -260
  158. package/src/peer-routing.ts +1 -101
  159. package/src/ping/constants.ts +11 -0
  160. package/src/ping/index.ts +32 -28
  161. package/src/registrar.ts +31 -27
  162. package/src/transport-manager.ts +27 -13
  163. package/src/upgrader.ts +62 -58
  164. package/src/{nat-manager.ts → upnp-nat/index.ts} +16 -17
  165. package/src/version.ts +1 -1
  166. package/dist/src/dht/dht-content-routing.d.ts +0 -17
  167. package/dist/src/dht/dht-content-routing.d.ts.map +0 -1
  168. package/dist/src/dht/dht-content-routing.js +0 -32
  169. package/dist/src/dht/dht-content-routing.js.map +0 -1
  170. package/dist/src/dht/dht-peer-routing.d.ts +0 -15
  171. package/dist/src/dht/dht-peer-routing.d.ts.map +0 -1
  172. package/dist/src/dht/dht-peer-routing.js +0 -26
  173. package/dist/src/dht/dht-peer-routing.js.map +0 -1
  174. package/dist/src/dht/dummy-dht.d.ts +0 -20
  175. package/dist/src/dht/dummy-dht.d.ts.map +0 -1
  176. package/dist/src/dht/dummy-dht.js +0 -46
  177. package/dist/src/dht/dummy-dht.js.map +0 -1
  178. package/dist/src/nat-manager.d.ts +0 -74
  179. package/dist/src/nat-manager.d.ts.map +0 -1
  180. package/dist/src/nat-manager.js.map +0 -1
  181. package/dist/src/peer-record-updater.d.ts +0 -24
  182. package/dist/src/peer-record-updater.d.ts.map +0 -1
  183. package/dist/src/peer-record-updater.js +0 -44
  184. package/dist/src/peer-record-updater.js.map +0 -1
  185. package/src/dht/dht-content-routing.ts +0 -44
  186. package/src/dht/dht-peer-routing.ts +0 -36
  187. package/src/dht/dummy-dht.ts +0 -60
  188. 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 { CustomEvent } from '@libp2p/interfaces/events'
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.trace('checking max connections limit %d/%d', numConnections, this.maxConnections)
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
- const tags = await this.peerStore.getTags(remotePeer)
79
+ peerValues.set(remotePeer, 0)
68
80
 
69
- // sum all tag values
70
- peerValues.set(remotePeer, tags.reduce((acc, curr) => {
71
- return acc + curr.value
72
- }, 0))
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.connectionManager.dispatchEvent(new CustomEvent('peer:prune', { detail: toClose.map(conn => conn.remotePeer) }))
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, AddressSorter, PeerStore } from '@libp2p/interface-peer-store'
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 type { ClearableSignal } from 'any-signal'
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 { timeoutController, signal } = this.createDialAbortControllers(options.signal)
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', addrsToDial.map(({ multiaddr }) => multiaddr.toString()).join(', '), err)
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 (timeoutController.signal.aborted) {
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): { timeoutController: TimeoutController, signal: ClearableSignal } {
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 = combineSignals(
261
- timeoutController.signal,
262
- this.shutDownController.signal,
263
- userSignal
260
+ const signal = anySignal(
261
+ [AbortSignal.timeout(this.dialTimeout),
262
+ this.shutDownController.signal,
263
+ userSignal
264
+ ]
264
265
  )
265
266
 
266
- return { timeoutController, signal }
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
- addrs.push(...(await this.peerStore.addressBook.get(peerId)))
284
- log('loaded multiaddrs for %p', peerId, addrs.map(({ multiaddr }) => multiaddr.toString()))
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
- return gatedAdrs.sort(this.addressSorter)
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 { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
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, ConnectionManagerEvents } from '@libp2p/interface-connection-manager'
11
- import type { AddressSorter, PeerStore } from '@libp2p/interface-peer-store'
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, Upgrader } from '@libp2p/interface-transport'
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 '../libp2p.js'
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 extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager, Startable {
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
- const tags = await this.peerStore.getTags(peer.id)
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
- if (peerId.publicKey != null) {
450
- await this.peerStore.keyBook.set(peerId, peerId.publicKey)
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
- this.dispatchEvent(new CustomEvent<Connection>('peer:connect', { detail: connection }))
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.dispatchEvent(new CustomEvent<Connection>('peer:disconnect', { detail: connection }))
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 this.routers available', codes.ERR_NO_ROUTERS_AVAILABLE)
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
- const dht = this.components.dht
91
-
92
- if (dht != null) {
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
- const dht = this.components.dht
107
-
108
- if (dht != null) {
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.addressBook.add(peer.id, peer.multiaddrs)
14
+ await peerStore.merge(peer.id, {
15
+ multiaddrs: peer.multiaddrs
16
+ })
15
17
 
16
18
  return peer
17
19
  })
@@ -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: string
25
- maxInboundStreams: number
26
- maxOutboundStreams: number
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: number
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
- export class FetchService implements Startable {
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
- timeoutController = new TimeoutController(this.init.timeout)
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, timeoutController.signal)
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
+ }