libp2p 2.9.0 → 2.10.0-8484de8a2

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 (119) hide show
  1. package/dist/index.min.js +13 -17
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/address-manager/dns-mappings.d.ts +1 -2
  4. package/dist/src/address-manager/dns-mappings.d.ts.map +1 -1
  5. package/dist/src/address-manager/dns-mappings.js +40 -44
  6. package/dist/src/address-manager/dns-mappings.js.map +1 -1
  7. package/dist/src/address-manager/index.d.ts.map +1 -1
  8. package/dist/src/address-manager/index.js +31 -14
  9. package/dist/src/address-manager/index.js.map +1 -1
  10. package/dist/src/address-manager/ip-mappings.d.ts +1 -0
  11. package/dist/src/address-manager/ip-mappings.d.ts.map +1 -1
  12. package/dist/src/address-manager/ip-mappings.js +51 -40
  13. package/dist/src/address-manager/ip-mappings.js.map +1 -1
  14. package/dist/src/address-manager/observed-addresses.d.ts.map +1 -1
  15. package/dist/src/address-manager/observed-addresses.js +1 -3
  16. package/dist/src/address-manager/observed-addresses.js.map +1 -1
  17. package/dist/src/address-manager/transport-addresses.d.ts.map +1 -1
  18. package/dist/src/address-manager/transport-addresses.js +6 -8
  19. package/dist/src/address-manager/transport-addresses.js.map +1 -1
  20. package/dist/src/config/connection-gater.browser.d.ts.map +1 -1
  21. package/dist/src/config/connection-gater.browser.js +3 -9
  22. package/dist/src/config/connection-gater.browser.js.map +1 -1
  23. package/dist/src/config.js +1 -1
  24. package/dist/src/config.js.map +1 -1
  25. package/dist/src/connection-manager/address-sorter.d.ts.map +1 -1
  26. package/dist/src/connection-manager/address-sorter.js +1 -2
  27. package/dist/src/connection-manager/address-sorter.js.map +1 -1
  28. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
  29. package/dist/src/connection-manager/connection-pruner.js +7 -3
  30. package/dist/src/connection-manager/connection-pruner.js.map +1 -1
  31. package/dist/src/connection-manager/constants.defaults.d.ts +4 -0
  32. package/dist/src/connection-manager/constants.defaults.d.ts.map +1 -1
  33. package/dist/src/connection-manager/constants.defaults.js +4 -0
  34. package/dist/src/connection-manager/constants.defaults.js.map +1 -1
  35. package/dist/src/connection-manager/dial-queue.d.ts +2 -2
  36. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
  37. package/dist/src/connection-manager/dial-queue.js +13 -25
  38. package/dist/src/connection-manager/dial-queue.js.map +1 -1
  39. package/dist/src/connection-manager/index.d.ts +10 -2
  40. package/dist/src/connection-manager/index.d.ts.map +1 -1
  41. package/dist/src/connection-manager/index.js +45 -27
  42. package/dist/src/connection-manager/index.js.map +1 -1
  43. package/dist/src/connection-manager/reconnect-queue.js +1 -1
  44. package/dist/src/connection-manager/reconnect-queue.js.map +1 -1
  45. package/dist/src/connection-manager/utils.d.ts +31 -3
  46. package/dist/src/connection-manager/utils.d.ts.map +1 -1
  47. package/dist/src/connection-manager/utils.js +99 -18
  48. package/dist/src/connection-manager/utils.js.map +1 -1
  49. package/dist/src/connection-monitor.d.ts +1 -1
  50. package/dist/src/connection-monitor.d.ts.map +1 -1
  51. package/dist/src/connection-monitor.js +2 -3
  52. package/dist/src/connection-monitor.js.map +1 -1
  53. package/dist/src/connection.d.ts +62 -0
  54. package/dist/src/connection.d.ts.map +1 -0
  55. package/dist/src/connection.js +239 -0
  56. package/dist/src/connection.js.map +1 -0
  57. package/dist/src/get-peer.js +3 -3
  58. package/dist/src/get-peer.js.map +1 -1
  59. package/dist/src/index.d.ts +2 -2
  60. package/dist/src/index.js +2 -2
  61. package/dist/src/libp2p.d.ts.map +1 -1
  62. package/dist/src/libp2p.js +5 -5
  63. package/dist/src/libp2p.js.map +1 -1
  64. package/dist/src/peer-routing.js +1 -1
  65. package/dist/src/peer-routing.js.map +1 -1
  66. package/dist/src/random-walk.d.ts.map +1 -1
  67. package/dist/src/random-walk.js +13 -3
  68. package/dist/src/random-walk.js.map +1 -1
  69. package/dist/src/registrar.d.ts +3 -3
  70. package/dist/src/registrar.d.ts.map +1 -1
  71. package/dist/src/registrar.js +50 -41
  72. package/dist/src/registrar.js.map +1 -1
  73. package/dist/src/transport-manager.js +15 -2
  74. package/dist/src/transport-manager.js.map +1 -1
  75. package/dist/src/upgrader.d.ts +27 -25
  76. package/dist/src/upgrader.d.ts.map +1 -1
  77. package/dist/src/upgrader.js +97 -336
  78. package/dist/src/upgrader.js.map +1 -1
  79. package/dist/src/utils.d.ts +3 -0
  80. package/dist/src/utils.d.ts.map +1 -0
  81. package/dist/src/utils.js +25 -0
  82. package/dist/src/utils.js.map +1 -0
  83. package/dist/src/version.d.ts +1 -1
  84. package/dist/src/version.d.ts.map +1 -1
  85. package/dist/src/version.js +1 -1
  86. package/dist/src/version.js.map +1 -1
  87. package/package.json +26 -30
  88. package/src/address-manager/dns-mappings.ts +51 -51
  89. package/src/address-manager/index.ts +37 -17
  90. package/src/address-manager/ip-mappings.ts +64 -44
  91. package/src/address-manager/observed-addresses.ts +1 -3
  92. package/src/address-manager/transport-addresses.ts +7 -9
  93. package/src/config/connection-gater.browser.ts +3 -12
  94. package/src/config.ts +1 -1
  95. package/src/connection-manager/address-sorter.ts +1 -2
  96. package/src/connection-manager/connection-pruner.ts +8 -3
  97. package/src/connection-manager/constants.defaults.ts +5 -0
  98. package/src/connection-manager/dial-queue.ts +14 -29
  99. package/src/connection-manager/index.ts +62 -29
  100. package/src/connection-manager/reconnect-queue.ts +1 -1
  101. package/src/connection-manager/utils.ts +129 -21
  102. package/src/connection-monitor.ts +3 -4
  103. package/src/connection.ts +316 -0
  104. package/src/get-peer.ts +3 -3
  105. package/src/index.ts +2 -2
  106. package/src/libp2p.ts +5 -6
  107. package/src/peer-routing.ts +1 -1
  108. package/src/random-walk.ts +13 -3
  109. package/src/registrar.ts +67 -54
  110. package/src/transport-manager.ts +18 -2
  111. package/src/upgrader.ts +143 -421
  112. package/src/utils.ts +31 -0
  113. package/src/version.ts +1 -1
  114. package/dist/src/connection/index.d.ts +0 -84
  115. package/dist/src/connection/index.d.ts.map +0 -1
  116. package/dist/src/connection/index.js +0 -144
  117. package/dist/src/connection/index.js.map +0 -1
  118. package/dist/typedoc-urls.json +0 -24
  119. package/src/connection/index.ts +0 -199
package/src/upgrader.ts CHANGED
@@ -1,37 +1,38 @@
1
- import { InvalidMultiaddrError, TooManyInboundProtocolStreamsError, TooManyOutboundProtocolStreamsError, LimitedConnectionError, InvalidPeerIdError } from '@libp2p/interface'
1
+ import { InvalidMultiaddrError, InvalidPeerIdError } from '@libp2p/interface'
2
2
  import * as mss from '@libp2p/multistream-select'
3
3
  import { peerIdFromString } from '@libp2p/peer-id'
4
- import { trackedMap } from '@libp2p/utils/tracked-map'
4
+ import { trackedMap } from '@libp2p/utils'
5
+ import { CODE_P2P } from '@multiformats/multiaddr'
5
6
  import { anySignal } from 'any-signal'
6
7
  import { setMaxListeners } from 'main-event'
7
8
  import { CustomProgressEvent } from 'progress-events'
8
9
  import { raceSignal } from 'race-signal'
9
- import { createConnection } from './connection/index.js'
10
- import { PROTOCOL_NEGOTIATION_TIMEOUT, INBOUND_UPGRADE_TIMEOUT } from './connection-manager/constants.js'
10
+ import { PROTOCOL_NEGOTIATION_TIMEOUT, INBOUND_UPGRADE_TIMEOUT, CONNECTION_CLOSE_TIMEOUT } from './connection-manager/constants.js'
11
+ import { createConnection } from './connection.js'
11
12
  import { ConnectionDeniedError, ConnectionInterceptedError, EncryptionFailedError, MuxerUnavailableError } from './errors.js'
12
- import { DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS } from './registrar.js'
13
- import type { Libp2pEvents, AbortOptions, ComponentLogger, MultiaddrConnection, Connection, Stream, ConnectionProtector, NewStreamOptions, ConnectionEncrypter, SecuredConnection, ConnectionGater, Metrics, PeerId, PeerStore, StreamMuxer, StreamMuxerFactory, Upgrader as UpgraderInterface, UpgraderOptions, ConnectionLimits, SecureConnectionOptions, CounterGroup, ClearableSignal } from '@libp2p/interface'
13
+ import type { Libp2pEvents, AbortOptions, ComponentLogger, MultiaddrConnection, Connection, ConnectionProtector, ConnectionEncrypter, ConnectionGater, Metrics, PeerId, PeerStore, StreamMuxerFactory, Upgrader as UpgraderInterface, UpgraderOptions, ConnectionLimits, CounterGroup, ClearableSignal, MessageStream, SecuredConnection, StreamMuxer, UpgraderWithoutEncryptionOptions, SecureConnectionOptions } from '@libp2p/interface'
14
14
  import type { ConnectionManager, Registrar } from '@libp2p/interface-internal'
15
15
  import type { TypedEventTarget } from 'main-event'
16
16
 
17
17
  interface CreateConnectionOptions {
18
+ id: string
18
19
  cryptoProtocol: string
19
20
  direction: 'inbound' | 'outbound'
21
+
22
+ /**
23
+ * The raw underlying connection
24
+ */
20
25
  maConn: MultiaddrConnection
21
- upgradedConn: MultiaddrConnection
22
- remotePeer: PeerId
23
- muxerFactory?: StreamMuxerFactory
24
- limits?: ConnectionLimits
25
- }
26
26
 
27
- interface OnStreamOptions {
28
- connection: Connection
29
- stream: Stream
30
- protocol: string
31
- }
27
+ /**
28
+ * The encrypted, multiplexed connection
29
+ */
30
+ stream: MessageStream
32
31
 
33
- export interface CryptoResult extends SecuredConnection<MultiaddrConnection> {
34
- protocol: string
32
+ remotePeer: PeerId
33
+ muxer?: StreamMuxer
34
+ limits?: ConnectionLimits
35
+ closeTimeout?: number
35
36
  }
36
37
 
37
38
  export interface UpgraderInit {
@@ -60,48 +61,13 @@ export interface UpgraderInit {
60
61
  * @default 2000
61
62
  */
62
63
  outboundStreamProtocolNegotiationTimeout?: number
63
- }
64
-
65
- function findIncomingStreamLimit (protocol: string, registrar: Registrar): number | undefined {
66
- try {
67
- const { options } = registrar.getHandler(protocol)
68
-
69
- return options.maxInboundStreams
70
- } catch (err: any) {
71
- if (err.name !== 'UnhandledProtocolError') {
72
- throw err
73
- }
74
- }
75
64
 
76
- return DEFAULT_MAX_INBOUND_STREAMS
77
- }
78
-
79
- function findOutgoingStreamLimit (protocol: string, registrar: Registrar, options: NewStreamOptions = {}): number {
80
- try {
81
- const { options } = registrar.getHandler(protocol)
82
-
83
- if (options.maxOutboundStreams != null) {
84
- return options.maxOutboundStreams
85
- }
86
- } catch (err: any) {
87
- if (err.name !== 'UnhandledProtocolError') {
88
- throw err
89
- }
90
- }
91
-
92
- return options.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
93
- }
94
-
95
- function countStreams (protocol: string, direction: 'inbound' | 'outbound', connection: Connection): number {
96
- let streamCount = 0
97
-
98
- connection.streams.forEach(stream => {
99
- if (stream.direction === direction && stream.protocol === protocol) {
100
- streamCount++
101
- }
102
- })
103
-
104
- return streamCount
65
+ /**
66
+ * How long to wait before closing a connection
67
+ *
68
+ * @default 1_000
69
+ */
70
+ connectionCloseTimeout?: number
105
71
  }
106
72
 
107
73
  export interface UpgraderComponents {
@@ -116,6 +82,10 @@ export interface UpgraderComponents {
116
82
  logger: ComponentLogger
117
83
  }
118
84
 
85
+ interface EncryptedConnection extends SecuredConnection {
86
+ protocol: string
87
+ }
88
+
119
89
  type ConnectionDeniedType = keyof Pick<ConnectionGater, 'denyOutboundConnection' | 'denyInboundEncryptedConnection' | 'denyOutboundEncryptedConnection' | 'denyInboundUpgradedConnection' | 'denyOutboundUpgradedConnection'>
120
90
 
121
91
  export class Upgrader implements UpgraderInterface {
@@ -133,6 +103,8 @@ export class Upgrader implements UpgraderInterface {
133
103
  outboundErrors?: CounterGroup
134
104
  }
135
105
 
106
+ private readonly connectionCloseTimeout?: number
107
+
136
108
  constructor (components: UpgraderComponents, init: UpgraderInit) {
137
109
  this.components = components
138
110
  this.connectionEncrypters = trackedMap({
@@ -156,6 +128,7 @@ export class Upgrader implements UpgraderInterface {
156
128
  this.inboundUpgradeTimeout = init.inboundUpgradeTimeout ?? INBOUND_UPGRADE_TIMEOUT
157
129
  this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
158
130
  this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
131
+ this.connectionCloseTimeout = init.connectionCloseTimeout ?? CONNECTION_CLOSE_TIMEOUT
159
132
  this.events = components.events
160
133
  this.metrics = {
161
134
  dials: components.metrics?.registerCounterGroup('libp2p_connection_manager_dials_total'),
@@ -196,7 +169,9 @@ export class Upgrader implements UpgraderInterface {
196
169
  /**
197
170
  * Upgrades an inbound connection
198
171
  */
199
- async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<void> {
172
+ async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<void>
173
+ async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise<void>
174
+ async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise<void> {
200
175
  let accepted = false
201
176
 
202
177
  // always apply upgrade timeout for incoming upgrades
@@ -207,7 +182,7 @@ export class Upgrader implements UpgraderInterface {
207
182
  inbound: true
208
183
  })
209
184
 
210
- accepted = await raceSignal(this.components.connectionManager.acceptIncomingConnection(maConn), signal)
185
+ accepted = this.components.connectionManager.acceptIncomingConnection(maConn)
211
186
 
212
187
  if (!accepted) {
213
188
  throw new ConnectionDeniedError('Connection denied')
@@ -240,13 +215,15 @@ export class Upgrader implements UpgraderInterface {
240
215
  /**
241
216
  * Upgrades an outbound connection
242
217
  */
243
- async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<Connection> {
218
+ async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise<Connection>
219
+ async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise<Connection>
220
+ async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise<Connection> {
244
221
  try {
245
222
  this.metrics.dials?.increment({
246
223
  outbound: true
247
224
  })
248
225
 
249
- const idStr = maConn.remoteAddr.getPeerId()
226
+ const idStr = maConn.remoteAddr.getComponents().findLast(c => c.code === CODE_P2P)?.value
250
227
  let remotePeerId: PeerId | undefined
251
228
 
252
229
  if (idStr != null) {
@@ -274,62 +251,64 @@ export class Upgrader implements UpgraderInterface {
274
251
  }
275
252
  }
276
253
 
277
- private async _performUpgrade (maConn: MultiaddrConnection, direction: 'inbound' | 'outbound', opts: UpgraderOptions): Promise<Connection> {
278
- let encryptedConn: MultiaddrConnection
254
+ private async _performUpgrade (maConn: MultiaddrConnection, direction: 'inbound' | 'outbound', opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise<Connection> {
255
+ let stream: MessageStream = maConn
279
256
  let remotePeer: PeerId
280
- let upgradedConn: MultiaddrConnection
281
257
  let muxerFactory: StreamMuxerFactory | undefined
258
+ let muxer: StreamMuxer | undefined
282
259
  let cryptoProtocol
283
260
 
261
+ const id = `${(parseInt(String(Math.random() * 1e9))).toString(36)}${Date.now()}`
262
+ maConn.log = maConn.log.newScope(`${direction}:${id}`)
263
+
284
264
  this.components.metrics?.trackMultiaddrConnection(maConn)
285
265
 
286
266
  maConn.log.trace('starting the %s connection upgrade', direction)
287
267
 
288
268
  // Protect
289
- let protectedConn = maConn
290
-
291
269
  if (opts?.skipProtection !== true) {
292
270
  const protector = this.components.connectionProtector
293
271
 
294
272
  if (protector != null) {
295
273
  maConn.log('protecting the %s connection', direction)
296
- protectedConn = await protector.protect(maConn, opts)
274
+ stream = await protector.protect(stream, opts)
297
275
  }
298
276
  }
299
277
 
300
278
  try {
301
279
  // Encrypt the connection
302
- encryptedConn = protectedConn
303
- if (opts?.skipEncryption !== true) {
280
+ if (isEncryptionSkipped(opts)) {
281
+ if (opts.remotePeer == null) {
282
+ throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`)
283
+ }
284
+
285
+ cryptoProtocol = 'native'
286
+ remotePeer = opts.remotePeer
287
+ } else {
288
+ const peerIdString = maConn.remoteAddr.getComponents().findLast(c => c.code === CODE_P2P)?.value
289
+ let remotePeerFromMultiaddr: PeerId | undefined
290
+
291
+ if (peerIdString != null) {
292
+ remotePeerFromMultiaddr = peerIdFromString(peerIdString)
293
+ }
294
+
304
295
  opts?.onProgress?.(new CustomProgressEvent(`upgrader:encrypt-${direction}-connection`));
305
296
 
306
297
  ({
307
- conn: encryptedConn,
298
+ connection: stream,
308
299
  remotePeer,
309
300
  protocol: cryptoProtocol,
310
301
  streamMuxer: muxerFactory
311
302
  } = await (direction === 'inbound'
312
- ? this._encryptInbound(protectedConn, opts)
313
- : this._encryptOutbound(protectedConn, opts)
303
+ ? this._encryptInbound(stream, {
304
+ ...opts,
305
+ remotePeer: remotePeerFromMultiaddr
306
+ })
307
+ : this._encryptOutbound(stream, {
308
+ ...opts,
309
+ remotePeer: remotePeerFromMultiaddr
310
+ })
314
311
  ))
315
-
316
- const maConn: MultiaddrConnection = {
317
- ...protectedConn,
318
- ...encryptedConn
319
- }
320
-
321
- await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundEncryptedConnection' : 'denyOutboundEncryptedConnection', remotePeer, maConn)
322
- } else {
323
- const idStr = maConn.remoteAddr.getPeerId()
324
-
325
- if (idStr == null) {
326
- throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`)
327
- }
328
-
329
- const remotePeerId = peerIdFromString(idStr)
330
-
331
- cryptoProtocol = 'native'
332
- remotePeer = remotePeerId
333
312
  }
334
313
 
335
314
  // this can happen if we dial a multiaddr without a peer id, we only find
@@ -340,353 +319,98 @@ export class Upgrader implements UpgraderInterface {
340
319
  throw err
341
320
  }
342
321
 
343
- upgradedConn = encryptedConn
322
+ // stream.pause()
323
+ await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundEncryptedConnection' : 'denyOutboundEncryptedConnection', remotePeer, maConn)
324
+ // stream.resume()
325
+
344
326
  if (opts?.muxerFactory != null) {
345
327
  muxerFactory = opts.muxerFactory
346
328
  } else if (muxerFactory == null && this.streamMuxers.size > 0) {
347
329
  opts?.onProgress?.(new CustomProgressEvent(`upgrader:multiplex-${direction}-connection`))
348
330
 
349
331
  // Multiplex the connection
350
- const multiplexed = await (direction === 'inbound'
351
- ? this._multiplexInbound({
352
- ...protectedConn,
353
- ...encryptedConn
354
- }, this.streamMuxers, opts)
355
- : this._multiplexOutbound({
356
- ...protectedConn,
357
- ...encryptedConn
358
- }, this.streamMuxers, opts))
359
- muxerFactory = multiplexed.muxerFactory
360
- upgradedConn = multiplexed.stream
332
+ muxerFactory = await (direction === 'inbound'
333
+ ? this._multiplexInbound(stream, this.streamMuxers, opts)
334
+ : this._multiplexOutbound(stream, this.streamMuxers, opts))
361
335
  }
362
336
  } catch (err: any) {
363
- maConn.log.error('failed to upgrade inbound connection %s %a - %e', direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err)
337
+ maConn.log.error('failed to upgrade %s connection %s %a - %e', direction, direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err)
364
338
  throw err
365
339
  }
366
340
 
367
- await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn)
341
+ // create the connection muxer if one is configured
342
+ if (muxerFactory != null) {
343
+ maConn.log('create muxer %s', muxerFactory.protocol)
344
+ muxer = muxerFactory.createStreamMuxer(stream)
345
+ }
368
346
 
369
- maConn.log('successfully upgraded %s connection', direction)
347
+ // stream.pause()
348
+ await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn)
370
349
 
371
- return this._createConnection({
350
+ const conn = this._createConnection({
351
+ id,
372
352
  cryptoProtocol,
373
353
  direction,
374
354
  maConn,
375
- upgradedConn,
376
- muxerFactory,
355
+ stream,
356
+ muxer,
377
357
  remotePeer,
378
- limits: opts?.limits
358
+ limits: opts?.limits,
359
+ closeTimeout: this.connectionCloseTimeout
379
360
  })
361
+
362
+ conn.log('successfully upgraded connection')
363
+
364
+ // stream.resume()
365
+
366
+ return conn
380
367
  }
381
368
 
382
369
  /**
383
370
  * A convenience method for generating a new `Connection`
384
371
  */
385
372
  _createConnection (opts: CreateConnectionOptions): Connection {
386
- const {
387
- cryptoProtocol,
388
- direction,
389
- maConn,
390
- upgradedConn,
391
- remotePeer,
392
- muxerFactory,
393
- limits
394
- } = opts
395
-
396
- let muxer: StreamMuxer | undefined
397
- let newStream: ((multicodecs: string[], options?: AbortOptions) => Promise<Stream>) | undefined
398
- let connection: Connection // eslint-disable-line prefer-const
399
-
400
- if (muxerFactory != null) {
401
- // Create the muxer
402
- muxer = muxerFactory.createStreamMuxer({
403
- direction,
404
- // Run anytime a remote stream is created
405
- onIncomingStream: muxedStream => {
406
- if (connection == null) {
407
- return
408
- }
409
-
410
- const signal = AbortSignal.timeout(this.inboundStreamProtocolNegotiationTimeout)
411
- setMaxListeners(Infinity, signal)
412
-
413
- void Promise.resolve()
414
- .then(async () => {
415
- const protocols = this.components.registrar.getProtocols()
416
-
417
- const { stream, protocol } = await mss.handle(muxedStream, protocols, {
418
- signal,
419
- log: muxedStream.log,
420
- yieldBytes: false
421
- })
422
-
423
- if (connection == null) {
424
- return
425
- }
426
-
427
- connection.log('incoming stream opened on %s', protocol)
428
-
429
- const incomingLimit = findIncomingStreamLimit(protocol, this.components.registrar)
430
- const streamCount = countStreams(protocol, 'inbound', connection)
431
-
432
- if (streamCount === incomingLimit) {
433
- const err = new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${protocol}" - limit ${incomingLimit}`)
434
- muxedStream.abort(err)
435
-
436
- throw err
437
- }
438
-
439
- // after the handshake the returned stream can have early data so override
440
- // the source/sink
441
- muxedStream.source = stream.source
442
- muxedStream.sink = stream.sink
443
- muxedStream.protocol = protocol
444
-
445
- // allow closing the write end of a not-yet-negotiated stream
446
- if (stream.closeWrite != null) {
447
- muxedStream.closeWrite = stream.closeWrite
448
- }
449
-
450
- // allow closing the read end of a not-yet-negotiated stream
451
- if (stream.closeRead != null) {
452
- muxedStream.closeRead = stream.closeRead
453
- }
454
-
455
- // make sure we don't try to negotiate a stream we are closing
456
- if (stream.close != null) {
457
- muxedStream.close = stream.close
458
- }
459
-
460
- // If a protocol stream has been successfully negotiated and is to be passed to the application,
461
- // the peer store should ensure that the peer is registered with that protocol
462
- await this.components.peerStore.merge(remotePeer, {
463
- protocols: [protocol]
464
- }, {
465
- signal
466
- })
467
-
468
- this.components.metrics?.trackProtocolStream(muxedStream, connection)
469
-
470
- this._onStream({ connection, stream: muxedStream, protocol })
471
- })
472
- .catch(async err => {
473
- connection.log.error('error handling incoming stream id %s - %e', muxedStream.id, err)
474
-
475
- if (muxedStream.timeline.close == null) {
476
- await muxedStream.close({
477
- signal
478
- })
479
- .catch(err => muxedStream.abort(err))
480
- }
481
- })
482
- }
483
- })
484
-
485
- newStream = async (protocols: string[], options: NewStreamOptions = {}): Promise<Stream> => {
486
- if (muxer == null) {
487
- throw new MuxerUnavailableError('Connection is not multiplexed')
488
- }
489
-
490
- connection.log.trace('starting new stream for protocols %s', protocols)
491
- const muxedStream = await muxer.newStream()
492
- connection.log.trace('started new stream %s for protocols %s', muxedStream.id, protocols)
493
-
494
- try {
495
- if (options.signal == null) {
496
- muxedStream.log('no abort signal was passed while trying to negotiate protocols %s falling back to default timeout', protocols)
497
-
498
- const signal = AbortSignal.timeout(this.outboundStreamProtocolNegotiationTimeout)
499
- setMaxListeners(Infinity, signal)
500
-
501
- options = {
502
- ...options,
503
- signal
504
- }
505
- }
506
-
507
- muxedStream.log.trace('selecting protocol from protocols %s', protocols)
508
-
509
- const {
510
- stream,
511
- protocol
512
- } = await mss.select(muxedStream, protocols, {
513
- ...options,
514
- log: muxedStream.log,
515
- yieldBytes: true
516
- })
517
-
518
- muxedStream.log.trace('selected protocol %s', protocol)
519
-
520
- const outgoingLimit = findOutgoingStreamLimit(protocol, this.components.registrar, options)
521
- const streamCount = countStreams(protocol, 'outbound', connection)
522
-
523
- if (streamCount >= outgoingLimit) {
524
- const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${protocol}" - ${streamCount}/${outgoingLimit}`)
525
- muxedStream.abort(err)
526
-
527
- throw err
528
- }
529
-
530
- // If a protocol stream has been successfully negotiated and is to be passed to the application,
531
- // the peer store should ensure that the peer is registered with that protocol
532
- await this.components.peerStore.merge(remotePeer, {
533
- protocols: [protocol]
534
- })
535
-
536
- // after the handshake the returned stream can have early data so override
537
- // the source/sink
538
- muxedStream.source = stream.source
539
- muxedStream.sink = stream.sink
540
- muxedStream.protocol = protocol
541
-
542
- // allow closing the write end of a not-yet-negotiated stream
543
- if (stream.closeWrite != null) {
544
- muxedStream.closeWrite = stream.closeWrite
545
- }
546
-
547
- // allow closing the read end of a not-yet-negotiated stream
548
- if (stream.closeRead != null) {
549
- muxedStream.closeRead = stream.closeRead
550
- }
551
-
552
- // make sure we don't try to negotiate a stream we are closing
553
- if (stream.close != null) {
554
- muxedStream.close = stream.close
555
- }
556
-
557
- this.components.metrics?.trackProtocolStream(muxedStream, connection)
558
-
559
- return muxedStream
560
- } catch (err: any) {
561
- connection.log.error('could not create new outbound stream on connection %s %a for protocols %s - %e', direction === 'inbound' ? 'from' : 'to', opts.maConn.remoteAddr, protocols, err)
562
-
563
- if (muxedStream.timeline.close == null) {
564
- muxedStream.abort(err)
565
- }
566
-
567
- throw err
568
- }
569
- }
570
-
571
- // Pipe all data through the muxer
572
- void Promise.all([
573
- muxer.sink(upgradedConn.source),
574
- upgradedConn.sink(muxer.source)
575
- ]).catch(err => {
576
- connection.log.error('error piping data through muxer - %e', err)
577
- })
578
- }
579
-
580
- const _timeline = maConn.timeline
581
- maConn.timeline = new Proxy(_timeline, {
582
- set: (...args) => {
583
- if (args[1] === 'close' && args[2] != null && _timeline.close == null) {
584
- // Wait for close to finish before notifying of the closure
585
- (async () => {
586
- try {
587
- if (connection.status === 'open') {
588
- await connection.close()
589
- }
590
- } catch (err: any) {
591
- connection.log.error('error closing connection after timeline close %e', err)
592
- } finally {
593
- this.events.safeDispatchEvent('connection:close', {
594
- detail: connection
595
- })
596
- }
597
- })().catch(err => {
598
- connection.log.error('error thrown while dispatching connection:close event %e', err)
599
- })
600
- }
601
-
602
- return Reflect.set(...args)
603
- }
604
- })
605
- maConn.timeline.upgraded = Date.now()
606
-
607
- const errConnectionNotMultiplexed = (): any => {
608
- throw new MuxerUnavailableError('Connection is not multiplexed')
609
- }
610
-
611
373
  // Create the connection
612
- connection = createConnection({
613
- remoteAddr: maConn.remoteAddr,
614
- remotePeer,
615
- status: 'open',
616
- direction,
617
- timeline: maConn.timeline,
618
- multiplexer: muxer?.protocol,
619
- encryption: cryptoProtocol,
620
- limits,
621
- logger: this.components.logger,
622
- newStream: newStream ?? errConnectionNotMultiplexed,
623
- getStreams: () => {
624
- return muxer?.streams ?? []
625
- },
626
- close: async (options?: AbortOptions) => {
627
- // ensure remaining streams are closed gracefully
628
- await muxer?.close(options)
629
-
630
- // close the underlying transport
631
- await maConn.close(options)
632
- },
633
- abort: (err) => {
634
- maConn.abort(err)
374
+ const connection = createConnection(this.components, {
375
+ ...opts,
376
+ outboundStreamProtocolNegotiationTimeout: this.outboundStreamProtocolNegotiationTimeout,
377
+ inboundStreamProtocolNegotiationTimeout: this.inboundStreamProtocolNegotiationTimeout
378
+ })
635
379
 
636
- // ensure remaining streams are aborted
637
- muxer?.abort(err)
638
- }
380
+ connection.addEventListener('close', () => {
381
+ this.events.safeDispatchEvent('connection:close', {
382
+ detail: connection
383
+ })
639
384
  })
640
385
 
641
386
  this.events.safeDispatchEvent('connection:open', {
642
387
  detail: connection
643
388
  })
644
389
 
645
- // @ts-expect-error nah
646
- connection.__maConnTimeline = _timeline
647
-
648
390
  return connection
649
391
  }
650
392
 
651
- /**
652
- * Routes incoming streams to the correct handler
653
- */
654
- _onStream (opts: OnStreamOptions): void {
655
- const { connection, stream, protocol } = opts
656
- const { handler, options } = this.components.registrar.getHandler(protocol)
657
-
658
- if (connection.limits != null && options.runOnLimitedConnection !== true) {
659
- throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
660
- }
661
-
662
- handler({ connection, stream })
663
- }
664
-
665
393
  /**
666
394
  * Attempts to encrypt the incoming `connection` with the provided `cryptos`
667
395
  */
668
- async _encryptInbound (connection: MultiaddrConnection, options?: AbortOptions): Promise<CryptoResult> {
396
+ async _encryptInbound (connection: MessageStream, options?: SecureConnectionOptions): Promise<EncryptedConnection> {
669
397
  const protocols = Array.from(this.connectionEncrypters.keys())
670
398
 
671
399
  try {
672
- const { stream, protocol } = await mss.handle(connection, protocols, {
673
- ...options,
674
- log: connection.log
675
- })
400
+ const protocol = await mss.handle(connection, protocols, options)
676
401
  const encrypter = this.connectionEncrypters.get(protocol)
677
402
 
678
403
  if (encrypter == null) {
679
404
  throw new EncryptionFailedError(`no crypto module found for ${protocol}`)
680
405
  }
681
406
 
682
- connection.log('encrypting inbound connection to %a using %s', connection.remoteAddr, protocol)
407
+ connection.log('encrypting inbound connection using %s', protocol)
683
408
 
684
409
  return {
685
- ...await encrypter.secureInbound(stream, options),
410
+ ...await encrypter.secureInbound(connection, options),
686
411
  protocol
687
412
  }
688
413
  } catch (err: any) {
689
- connection.log.error('encrypting inbound connection from %a failed', connection.remoteAddr, err)
690
414
  throw new EncryptionFailedError(err.message)
691
415
  }
692
416
  }
@@ -695,31 +419,26 @@ export class Upgrader implements UpgraderInterface {
695
419
  * Attempts to encrypt the given `connection` with the provided connection encrypters.
696
420
  * The first `ConnectionEncrypter` module to succeed will be used
697
421
  */
698
- async _encryptOutbound (connection: MultiaddrConnection, options: SecureConnectionOptions): Promise<CryptoResult> {
422
+ async _encryptOutbound (connection: MessageStream, options?: SecureConnectionOptions): Promise<EncryptedConnection> {
699
423
  const protocols = Array.from(this.connectionEncrypters.keys())
700
424
 
701
425
  try {
702
426
  connection.log.trace('selecting encrypter from %s', protocols)
703
427
 
704
- const { stream, protocol } = await mss.select(connection, protocols, {
705
- ...options,
706
- log: connection.log,
707
- yieldBytes: true
708
- })
428
+ const protocol = await mss.select(connection, protocols, options)
709
429
  const encrypter = this.connectionEncrypters.get(protocol)
710
430
 
711
431
  if (encrypter == null) {
712
432
  throw new EncryptionFailedError(`no crypto module found for ${protocol}`)
713
433
  }
714
434
 
715
- connection.log('encrypting outbound connection to %a using %s', connection.remoteAddr, protocol)
435
+ connection.log('encrypting outbound connection using %s', protocol)
716
436
 
717
437
  return {
718
- ...await encrypter.secureOutbound(stream, options),
438
+ ...await encrypter.secureOutbound(connection, options),
719
439
  protocol
720
440
  }
721
441
  } catch (err: any) {
722
- connection.log.error('encrypting outbound connection to %a failed', connection.remoteAddr, err)
723
442
  throw new EncryptionFailedError(err.message)
724
443
  }
725
444
  }
@@ -728,27 +447,23 @@ export class Upgrader implements UpgraderInterface {
728
447
  * Selects one of the given muxers via multistream-select. That
729
448
  * muxer will be used for all future streams on the connection.
730
449
  */
731
- async _multiplexOutbound (connection: MultiaddrConnection, muxers: Map<string, StreamMuxerFactory>, options: AbortOptions): Promise<{ stream: MultiaddrConnection, muxerFactory?: StreamMuxerFactory }> {
450
+ async _multiplexOutbound (maConn: MessageStream, muxers: Map<string, StreamMuxerFactory>, options: AbortOptions): Promise<StreamMuxerFactory> {
732
451
  const protocols = Array.from(muxers.keys())
733
- connection.log('outbound selecting muxer %s', protocols)
734
- try {
735
- connection.log.trace('selecting stream muxer from %s', protocols)
452
+ maConn.log('outbound selecting muxer %s', protocols)
736
453
 
737
- const {
738
- stream,
739
- protocol
740
- } = await mss.select(connection, protocols, {
741
- ...options,
742
- log: connection.log,
743
- yieldBytes: true
744
- })
745
-
746
- connection.log('selected %s as muxer protocol', protocol)
454
+ try {
455
+ maConn.log.trace('selecting stream muxer from %s', protocols)
456
+ const protocol = await mss.select(maConn, protocols, options)
747
457
  const muxerFactory = muxers.get(protocol)
748
458
 
749
- return { stream, muxerFactory }
459
+ if (muxerFactory == null) {
460
+ throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`)
461
+ }
462
+
463
+ maConn.log('selected %s as muxer protocol', protocol)
464
+ return muxerFactory
750
465
  } catch (err: any) {
751
- connection.log.error('error multiplexing outbound connection', err)
466
+ maConn.log.error('error multiplexing outbound connection', err)
752
467
  throw new MuxerUnavailableError(String(err))
753
468
  }
754
469
  }
@@ -757,20 +472,23 @@ export class Upgrader implements UpgraderInterface {
757
472
  * Registers support for one of the given muxers via multistream-select. The
758
473
  * selected muxer will be used for all future streams on the connection.
759
474
  */
760
- async _multiplexInbound (connection: MultiaddrConnection, muxers: Map<string, StreamMuxerFactory>, options: AbortOptions): Promise<{ stream: MultiaddrConnection, muxerFactory?: StreamMuxerFactory }> {
475
+ async _multiplexInbound (maConn: MessageStream, muxers: Map<string, StreamMuxerFactory>, options: AbortOptions): Promise<StreamMuxerFactory> {
761
476
  const protocols = Array.from(muxers.keys())
762
- connection.log('inbound handling muxers %s', protocols)
477
+ maConn.log('inbound handling muxers %s', protocols)
763
478
  try {
764
- const { stream, protocol } = await mss.handle(connection, protocols, {
765
- ...options,
766
- log: connection.log
767
- })
479
+ maConn.log.trace('selecting stream muxer from %s', protocols)
480
+ const protocol = await mss.handle(maConn, protocols, options)
768
481
  const muxerFactory = muxers.get(protocol)
769
482
 
770
- return { stream, muxerFactory }
483
+ if (muxerFactory == null) {
484
+ throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`)
485
+ }
486
+
487
+ maConn.log('selected %s as muxer protocol', protocol)
488
+ return muxerFactory
771
489
  } catch (err: any) {
772
- connection.log.error('error multiplexing inbound connection', err)
773
- throw new MuxerUnavailableError(String(err))
490
+ maConn.log.error('error multiplexing inbound connection', err)
491
+ throw err
774
492
  }
775
493
  }
776
494
 
@@ -782,3 +500,7 @@ export class Upgrader implements UpgraderInterface {
782
500
  return this.streamMuxers
783
501
  }
784
502
  }
503
+
504
+ function isEncryptionSkipped (opts?: any): opts is UpgraderWithoutEncryptionOptions {
505
+ return opts.skipEncryption === true
506
+ }