libp2p 2.10.0 → 3.0.0-049bfa0fa

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 (121) hide show
  1. package/README.md +39 -37
  2. package/dist/index.min.js +14 -17
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/address-manager/dns-mappings.d.ts +1 -2
  5. package/dist/src/address-manager/dns-mappings.d.ts.map +1 -1
  6. package/dist/src/address-manager/dns-mappings.js +39 -43
  7. package/dist/src/address-manager/dns-mappings.js.map +1 -1
  8. package/dist/src/address-manager/index.d.ts.map +1 -1
  9. package/dist/src/address-manager/index.js +31 -14
  10. package/dist/src/address-manager/index.js.map +1 -1
  11. package/dist/src/address-manager/ip-mappings.d.ts +1 -0
  12. package/dist/src/address-manager/ip-mappings.d.ts.map +1 -1
  13. package/dist/src/address-manager/ip-mappings.js +51 -40
  14. package/dist/src/address-manager/ip-mappings.js.map +1 -1
  15. package/dist/src/address-manager/observed-addresses.d.ts.map +1 -1
  16. package/dist/src/address-manager/observed-addresses.js +1 -3
  17. package/dist/src/address-manager/observed-addresses.js.map +1 -1
  18. package/dist/src/address-manager/transport-addresses.d.ts.map +1 -1
  19. package/dist/src/address-manager/transport-addresses.js +6 -8
  20. package/dist/src/address-manager/transport-addresses.js.map +1 -1
  21. package/dist/src/config/connection-gater.browser.d.ts.map +1 -1
  22. package/dist/src/config/connection-gater.browser.js +8 -22
  23. package/dist/src/config/connection-gater.browser.js.map +1 -1
  24. package/dist/src/config/connection-gater.d.ts.map +1 -1
  25. package/dist/src/config/connection-gater.js +1 -12
  26. package/dist/src/config/connection-gater.js.map +1 -1
  27. package/dist/src/config.d.ts.map +1 -1
  28. package/dist/src/config.js +3 -22
  29. package/dist/src/config.js.map +1 -1
  30. package/dist/src/connection-manager/address-sorter.d.ts.map +1 -1
  31. package/dist/src/connection-manager/address-sorter.js +1 -2
  32. package/dist/src/connection-manager/address-sorter.js.map +1 -1
  33. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
  34. package/dist/src/connection-manager/connection-pruner.js +7 -3
  35. package/dist/src/connection-manager/connection-pruner.js.map +1 -1
  36. package/dist/src/connection-manager/constants.defaults.d.ts +4 -0
  37. package/dist/src/connection-manager/constants.defaults.d.ts.map +1 -1
  38. package/dist/src/connection-manager/constants.defaults.js +4 -0
  39. package/dist/src/connection-manager/constants.defaults.js.map +1 -1
  40. package/dist/src/connection-manager/dial-queue.d.ts +2 -2
  41. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
  42. package/dist/src/connection-manager/dial-queue.js +11 -23
  43. package/dist/src/connection-manager/dial-queue.js.map +1 -1
  44. package/dist/src/connection-manager/index.d.ts +10 -18
  45. package/dist/src/connection-manager/index.d.ts.map +1 -1
  46. package/dist/src/connection-manager/index.js +44 -26
  47. package/dist/src/connection-manager/index.js.map +1 -1
  48. package/dist/src/connection-manager/reconnect-queue.js +1 -1
  49. package/dist/src/connection-manager/reconnect-queue.js.map +1 -1
  50. package/dist/src/connection-manager/utils.d.ts +31 -3
  51. package/dist/src/connection-manager/utils.d.ts.map +1 -1
  52. package/dist/src/connection-manager/utils.js +99 -18
  53. package/dist/src/connection-manager/utils.js.map +1 -1
  54. package/dist/src/connection-monitor.d.ts +1 -1
  55. package/dist/src/connection-monitor.d.ts.map +1 -1
  56. package/dist/src/connection-monitor.js +2 -3
  57. package/dist/src/connection-monitor.js.map +1 -1
  58. package/dist/src/connection.d.ts +14 -9
  59. package/dist/src/connection.d.ts.map +1 -1
  60. package/dist/src/connection.js +118 -139
  61. package/dist/src/connection.js.map +1 -1
  62. package/dist/src/get-peer.js +3 -3
  63. package/dist/src/get-peer.js.map +1 -1
  64. package/dist/src/index.d.ts +2 -2
  65. package/dist/src/index.js +2 -2
  66. package/dist/src/libp2p.d.ts +3 -1
  67. package/dist/src/libp2p.d.ts.map +1 -1
  68. package/dist/src/libp2p.js +13 -7
  69. package/dist/src/libp2p.js.map +1 -1
  70. package/dist/src/peer-routing.js +1 -1
  71. package/dist/src/peer-routing.js.map +1 -1
  72. package/dist/src/random-walk.d.ts.map +1 -1
  73. package/dist/src/random-walk.js +13 -3
  74. package/dist/src/random-walk.js.map +1 -1
  75. package/dist/src/registrar.d.ts +8 -4
  76. package/dist/src/registrar.d.ts.map +1 -1
  77. package/dist/src/registrar.js +66 -46
  78. package/dist/src/registrar.js.map +1 -1
  79. package/dist/src/transport-manager.js +15 -2
  80. package/dist/src/transport-manager.js.map +1 -1
  81. package/dist/src/upgrader.d.ts +26 -16
  82. package/dist/src/upgrader.d.ts.map +1 -1
  83. package/dist/src/upgrader.js +88 -122
  84. package/dist/src/upgrader.js.map +1 -1
  85. package/dist/src/utils.d.ts +3 -0
  86. package/dist/src/utils.d.ts.map +1 -0
  87. package/dist/src/utils.js +25 -0
  88. package/dist/src/utils.js.map +1 -0
  89. package/dist/src/version.d.ts +1 -1
  90. package/dist/src/version.d.ts.map +1 -1
  91. package/dist/src/version.js +1 -1
  92. package/dist/src/version.js.map +1 -1
  93. package/package.json +27 -30
  94. package/src/address-manager/dns-mappings.ts +50 -50
  95. package/src/address-manager/index.ts +37 -17
  96. package/src/address-manager/ip-mappings.ts +64 -44
  97. package/src/address-manager/observed-addresses.ts +1 -3
  98. package/src/address-manager/transport-addresses.ts +7 -9
  99. package/src/config/connection-gater.browser.ts +8 -24
  100. package/src/config/connection-gater.ts +1 -12
  101. package/src/config.ts +3 -25
  102. package/src/connection-manager/address-sorter.ts +1 -2
  103. package/src/connection-manager/connection-pruner.ts +8 -3
  104. package/src/connection-manager/constants.defaults.ts +5 -0
  105. package/src/connection-manager/dial-queue.ts +12 -27
  106. package/src/connection-manager/index.ts +60 -45
  107. package/src/connection-manager/reconnect-queue.ts +1 -1
  108. package/src/connection-manager/utils.ts +129 -21
  109. package/src/connection-monitor.ts +3 -4
  110. package/src/connection.ts +142 -179
  111. package/src/get-peer.ts +3 -3
  112. package/src/index.ts +2 -2
  113. package/src/libp2p.ts +16 -9
  114. package/src/peer-routing.ts +1 -1
  115. package/src/random-walk.ts +13 -3
  116. package/src/registrar.ts +87 -61
  117. package/src/transport-manager.ts +18 -2
  118. package/src/upgrader.ts +132 -149
  119. package/src/utils.ts +31 -0
  120. package/src/version.ts +1 -1
  121. package/dist/typedoc-urls.json +0 -24
package/src/connection.ts CHANGED
@@ -1,15 +1,15 @@
1
- import { connectionSymbol, LimitedConnectionError, ConnectionClosedError, ConnectionClosingError, TooManyOutboundProtocolStreamsError, TooManyInboundProtocolStreamsError } from '@libp2p/interface'
1
+ import { connectionSymbol, LimitedConnectionError, ConnectionClosedError, TooManyOutboundProtocolStreamsError, TooManyInboundProtocolStreamsError, StreamCloseEvent } from '@libp2p/interface'
2
2
  import * as mss from '@libp2p/multistream-select'
3
- import { setMaxListeners } from 'main-event'
4
- import { PROTOCOL_NEGOTIATION_TIMEOUT } from './connection-manager/constants.defaults.ts'
3
+ import { CODE_P2P } from '@multiformats/multiaddr'
4
+ import { setMaxListeners, TypedEventEmitter } from 'main-event'
5
+ import { CONNECTION_CLOSE_TIMEOUT, PROTOCOL_NEGOTIATION_TIMEOUT } from './connection-manager/constants.defaults.ts'
6
+ import { isDirect } from './connection-manager/utils.ts'
5
7
  import { MuxerUnavailableError } from './errors.ts'
6
8
  import { DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS } from './registrar.ts'
7
- import type { AbortOptions, Logger, Direction, Connection as ConnectionInterface, Stream, ConnectionTimeline, ConnectionStatus, NewStreamOptions, PeerId, ConnectionLimits, StreamMuxerFactory, StreamMuxer, Metrics, PeerStore, MultiaddrConnection } from '@libp2p/interface'
9
+ import type { AbortOptions, Logger, MessageStreamDirection, Connection as ConnectionInterface, Stream, NewStreamOptions, PeerId, ConnectionLimits, StreamMuxer, Metrics, PeerStore, MultiaddrConnection, MessageStreamEvents, MultiaddrConnectionTimeline, ConnectionStatus, MessageStream, StreamMiddleware } from '@libp2p/interface'
8
10
  import type { Registrar } from '@libp2p/interface-internal'
9
11
  import type { Multiaddr } from '@multiformats/multiaddr'
10
12
 
11
- const CLOSE_TIMEOUT = 500
12
-
13
13
  export interface ConnectionComponents {
14
14
  peerStore: PeerStore
15
15
  registrar: Registrar
@@ -19,80 +19,74 @@ export interface ConnectionComponents {
19
19
  export interface ConnectionInit {
20
20
  id: string
21
21
  maConn: MultiaddrConnection
22
+ stream: MessageStream
22
23
  remotePeer: PeerId
23
- direction?: Direction
24
- muxerFactory?: StreamMuxerFactory
25
- encryption?: string
24
+ direction?: MessageStreamDirection
25
+ muxer?: StreamMuxer
26
+ cryptoProtocol?: string
26
27
  limits?: ConnectionLimits
27
28
  outboundStreamProtocolNegotiationTimeout?: number
28
29
  inboundStreamProtocolNegotiationTimeout?: number
30
+ closeTimeout?: number
29
31
  }
30
32
 
31
33
  /**
32
34
  * An implementation of the js-libp2p connection.
33
35
  * Any libp2p transport should use an upgrader to return this connection.
34
36
  */
35
- export class Connection implements ConnectionInterface {
37
+ export class Connection extends TypedEventEmitter<MessageStreamEvents> implements ConnectionInterface {
36
38
  public readonly id: string
37
39
  public readonly remoteAddr: Multiaddr
38
40
  public readonly remotePeer: PeerId
39
- public direction: Direction
40
- public timeline: ConnectionTimeline
41
+ public direction: MessageStreamDirection
42
+ public timeline: MultiaddrConnectionTimeline
43
+ public direct: boolean
41
44
  public multiplexer?: string
42
45
  public encryption?: string
43
- public status: ConnectionStatus
44
46
  public limits?: ConnectionLimits
45
47
  public readonly log: Logger
46
- public tags: string[]
47
48
 
48
49
  private readonly maConn: MultiaddrConnection
49
50
  private readonly muxer?: StreamMuxer
50
51
  private readonly components: ConnectionComponents
51
52
  private readonly outboundStreamProtocolNegotiationTimeout: number
52
53
  private readonly inboundStreamProtocolNegotiationTimeout: number
54
+ private readonly closeTimeout: number
53
55
 
54
56
  constructor (components: ConnectionComponents, init: ConnectionInit) {
57
+ super()
58
+
55
59
  this.components = components
56
60
 
57
61
  this.id = init.id
58
62
  this.remoteAddr = init.maConn.remoteAddr
59
63
  this.remotePeer = init.remotePeer
60
64
  this.direction = init.direction ?? 'outbound'
61
- this.status = 'open'
62
65
  this.timeline = init.maConn.timeline
63
- this.encryption = init.encryption
66
+ this.encryption = init.cryptoProtocol
64
67
  this.limits = init.limits
65
68
  this.maConn = init.maConn
66
69
  this.log = init.maConn.log
67
70
  this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
68
71
  this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT
72
+ this.closeTimeout = init.closeTimeout ?? CONNECTION_CLOSE_TIMEOUT
73
+ this.direct = isDirect(init.maConn.remoteAddr)
74
+
75
+ this.onIncomingStream = this.onIncomingStream.bind(this)
69
76
 
70
- if (this.remoteAddr.getPeerId() == null) {
77
+ if (this.remoteAddr.getComponents().find(component => component.code === CODE_P2P) == null) {
71
78
  this.remoteAddr = this.remoteAddr.encapsulate(`/p2p/${this.remotePeer}`)
72
79
  }
73
80
 
74
- this.tags = []
75
-
76
- if (init.muxerFactory != null) {
77
- this.multiplexer = init.muxerFactory.protocol
78
-
79
- this.muxer = init.muxerFactory.createStreamMuxer({
80
- direction: this.direction,
81
- log: this.log,
82
- // Run anytime a remote stream is created
83
- onIncomingStream: (stream) => {
84
- this.onIncomingStream(stream)
85
- }
86
- })
87
-
88
- // Pipe all data through the muxer
89
- void Promise.all([
90
- this.muxer.sink(this.maConn.source),
91
- this.maConn.sink(this.muxer.source)
92
- ]).catch(err => {
93
- this.log.error('error piping data through muxer - %e', err)
94
- })
81
+ if (init.muxer != null) {
82
+ this.multiplexer = init.muxer.protocol
83
+ this.muxer = init.muxer
84
+ this.muxer.addEventListener('stream', this.onIncomingStream)
95
85
  }
86
+
87
+ this.maConn.addEventListener('close', (evt) => {
88
+ this.dispatchEvent(new StreamCloseEvent(evt.local, evt.error))
89
+ })
96
90
  }
97
91
 
98
92
  readonly [Symbol.toStringTag] = 'Connection'
@@ -103,32 +97,43 @@ export class Connection implements ConnectionInterface {
103
97
  return this.muxer?.streams ?? []
104
98
  }
105
99
 
100
+ get status (): ConnectionStatus {
101
+ return this.maConn.status
102
+ }
103
+
106
104
  /**
107
105
  * Create a new stream over this connection
108
106
  */
109
107
  newStream = async (protocols: string[], options: NewStreamOptions = {}): Promise<Stream> => {
110
- if (this.status === 'closing') {
111
- throw new ConnectionClosingError('the connection is being closed')
108
+ if (this.muxer == null) {
109
+ throw new MuxerUnavailableError('Connection is not multiplexed')
112
110
  }
113
111
 
114
- if (this.status === 'closed') {
115
- throw new ConnectionClosedError('the connection is closed')
112
+ if (this.muxer.status !== 'open') {
113
+ throw new ConnectionClosedError(`The connection muxer is "${this.muxer.status}" and not "open"`)
116
114
  }
117
115
 
118
- if (!Array.isArray(protocols)) {
119
- protocols = [protocols]
116
+ if (this.maConn.status !== 'open') {
117
+ throw new ConnectionClosedError(`The connection is "${this.status}" and not "open"`)
120
118
  }
121
119
 
122
120
  if (this.limits != null && options?.runOnLimitedConnection !== true) {
123
121
  throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
124
122
  }
125
123
 
126
- if (this.muxer == null) {
127
- throw new MuxerUnavailableError('Connection is not multiplexed')
124
+ if (!Array.isArray(protocols)) {
125
+ protocols = [protocols]
128
126
  }
129
127
 
130
128
  this.log.trace('starting new stream for protocols %s', protocols)
131
- const muxedStream = await this.muxer.newStream()
129
+ const muxedStream = await this.muxer.createStream({
130
+ ...options,
131
+
132
+ // most underlying transports only support negotiating a single protocol
133
+ // so only pass the early protocol if a single protocol has been requested
134
+ // otherwise fall back to mss
135
+ protocol: protocols.length === 1 ? protocols[0] : undefined
136
+ })
132
137
  this.log.trace('started new stream %s for protocols %s', muxedStream.id, protocols)
133
138
 
134
139
  try {
@@ -144,24 +149,21 @@ export class Connection implements ConnectionInterface {
144
149
  }
145
150
  }
146
151
 
147
- muxedStream.log.trace('selecting protocol from protocols %s', protocols)
152
+ if (muxedStream.protocol === '') {
153
+ muxedStream.log.trace('selecting protocol from protocols %s', protocols)
148
154
 
149
- const {
150
- stream,
151
- protocol
152
- } = await mss.select(muxedStream, protocols, {
153
- ...options,
154
- log: muxedStream.log,
155
- yieldBytes: true
156
- })
155
+ muxedStream.protocol = await mss.select(muxedStream, protocols, options)
157
156
 
158
- muxedStream.log('selected protocol %s', protocol)
157
+ muxedStream.log('negotiated protocol %s', muxedStream.protocol)
158
+ } else {
159
+ muxedStream.log('pre-negotiated protocol %s', muxedStream.protocol)
160
+ }
159
161
 
160
- const outgoingLimit = findOutgoingStreamLimit(protocol, this.components.registrar, options)
161
- const streamCount = countStreams(protocol, 'outbound', this)
162
+ const outgoingLimit = findOutgoingStreamLimit(muxedStream.protocol, this.components.registrar, options)
163
+ const streamCount = countStreams(muxedStream.protocol, 'outbound', this)
162
164
 
163
- if (streamCount >= outgoingLimit) {
164
- const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${protocol}" - ${streamCount}/${outgoingLimit}`)
165
+ if (streamCount > outgoingLimit) {
166
+ const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${muxedStream.protocol}" - ${streamCount}/${outgoingLimit}`)
165
167
  muxedStream.abort(err)
166
168
 
167
169
  throw err
@@ -170,132 +172,120 @@ export class Connection implements ConnectionInterface {
170
172
  // If a protocol stream has been successfully negotiated and is to be passed to the application,
171
173
  // the peer store should ensure that the peer is registered with that protocol
172
174
  await this.components.peerStore.merge(this.remotePeer, {
173
- protocols: [protocol]
175
+ protocols: [muxedStream.protocol]
174
176
  })
175
177
 
176
- // after the handshake the returned stream can have early data so override
177
- // the source/sink
178
- muxedStream.source = stream.source
179
- muxedStream.sink = stream.sink
180
- muxedStream.protocol = protocol
181
-
182
- // allow closing the write end of a not-yet-negotiated stream
183
- if (stream.closeWrite != null) {
184
- muxedStream.closeWrite = stream.closeWrite
185
- }
186
-
187
- // allow closing the read end of a not-yet-negotiated stream
188
- if (stream.closeRead != null) {
189
- muxedStream.closeRead = stream.closeRead
190
- }
191
-
192
- // make sure we don't try to negotiate a stream we are closing
193
- if (stream.close != null) {
194
- muxedStream.close = stream.close
195
- }
196
-
197
- this.components.metrics?.trackProtocolStream(muxedStream, this)
178
+ this.components.metrics?.trackProtocolStream(muxedStream)
198
179
 
199
- muxedStream.direction = 'outbound'
180
+ const middleware = this.components.registrar.getMiddleware(muxedStream.protocol)
200
181
 
201
- return muxedStream
182
+ return await this.runMiddlewareChain(muxedStream, this, middleware)
202
183
  } catch (err: any) {
203
- this.log.error('could not create new outbound stream on connection %s %a for protocols %s - %e', this.direction === 'inbound' ? 'from' : 'to', this.remoteAddr, protocols, err)
204
-
205
- if (muxedStream.timeline.close == null) {
184
+ if (muxedStream.status === 'open') {
206
185
  muxedStream.abort(err)
186
+ } else {
187
+ this.log.error('could not create new outbound stream on connection %s %a for protocols %s - %e', this.direction === 'inbound' ? 'from' : 'to', this.remoteAddr, protocols, err)
207
188
  }
208
189
 
209
190
  throw err
210
191
  }
211
192
  }
212
193
 
213
- private onIncomingStream (muxedStream: Stream): void {
194
+ private async onIncomingStream (evt: CustomEvent<Stream>): Promise<void> {
195
+ const muxedStream = evt.detail
196
+
214
197
  const signal = AbortSignal.timeout(this.inboundStreamProtocolNegotiationTimeout)
215
198
  setMaxListeners(Infinity, signal)
216
199
 
217
- void Promise.resolve()
218
- .then(async () => {
200
+ muxedStream.log('start protocol negotiation, timing out after %dms', this.inboundStreamProtocolNegotiationTimeout)
201
+
202
+ try {
203
+ if (muxedStream.protocol === '') {
219
204
  const protocols = this.components.registrar.getProtocols()
220
205
 
221
- const { stream, protocol } = await mss.handle(muxedStream, protocols, {
222
- signal,
223
- log: muxedStream.log,
224
- yieldBytes: false
225
- })
206
+ muxedStream.log.trace('selecting protocol from protocols %s', protocols)
226
207
 
227
- this.log('incoming %s stream opened', protocol)
208
+ muxedStream.protocol = await mss.handle(muxedStream, protocols, {
209
+ signal
210
+ })
228
211
 
229
- const incomingLimit = findIncomingStreamLimit(protocol, this.components.registrar)
230
- const streamCount = countStreams(protocol, 'inbound', this)
212
+ muxedStream.log('negotiated protocol %s', muxedStream.protocol)
213
+ } else {
214
+ muxedStream.log('pre-negotiated protocol %s', muxedStream.protocol)
215
+ }
231
216
 
232
- if (streamCount === incomingLimit) {
233
- const err = new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${protocol}" - limit ${incomingLimit}`)
234
- muxedStream.abort(err)
217
+ const incomingLimit = findIncomingStreamLimit(muxedStream.protocol, this.components.registrar)
218
+ const streamCount = countStreams(muxedStream.protocol, 'inbound', this)
235
219
 
236
- throw err
237
- }
220
+ if (streamCount > incomingLimit) {
221
+ throw new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${muxedStream.protocol}" - limit ${incomingLimit}`)
222
+ }
238
223
 
239
- // after the handshake the returned stream can have early data so override
240
- // the source/sink
241
- muxedStream.source = stream.source
242
- muxedStream.sink = stream.sink
243
- muxedStream.protocol = protocol
224
+ // If a protocol stream has been successfully negotiated and is to be passed to the application,
225
+ // the peer store should ensure that the peer is registered with that protocol
226
+ await this.components.peerStore.merge(this.remotePeer, {
227
+ protocols: [muxedStream.protocol]
228
+ }, {
229
+ signal
230
+ })
244
231
 
245
- // allow closing the write end of a not-yet-negotiated stream
246
- if (stream.closeWrite != null) {
247
- muxedStream.closeWrite = stream.closeWrite
248
- }
232
+ this.components.metrics?.trackProtocolStream(muxedStream)
249
233
 
250
- // allow closing the read end of a not-yet-negotiated stream
251
- if (stream.closeRead != null) {
252
- muxedStream.closeRead = stream.closeRead
253
- }
234
+ const { handler, options } = this.components.registrar.getHandler(muxedStream.protocol)
254
235
 
255
- // make sure we don't try to negotiate a stream we are closing
256
- if (stream.close != null) {
257
- muxedStream.close = stream.close
258
- }
236
+ if (this.limits != null && options.runOnLimitedConnection !== true) {
237
+ throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
238
+ }
259
239
 
260
- // If a protocol stream has been successfully negotiated and is to be passed to the application,
261
- // the peer store should ensure that the peer is registered with that protocol
262
- await this.components.peerStore.merge(this.remotePeer, {
263
- protocols: [protocol]
264
- }, {
265
- signal
266
- })
240
+ const middleware = this.components.registrar.getMiddleware(muxedStream.protocol)
267
241
 
268
- this.components.metrics?.trackProtocolStream(muxedStream, this)
242
+ middleware.push(async (stream, connection, next) => {
243
+ await handler(stream, connection)
244
+ next(stream, connection)
245
+ })
269
246
 
270
- const { handler, options } = this.components.registrar.getHandler(protocol)
247
+ await this.runMiddlewareChain(muxedStream, this, middleware)
248
+ } catch (err: any) {
249
+ muxedStream.abort(err)
250
+ }
251
+ }
271
252
 
272
- if (this.limits != null && options.runOnLimitedConnection !== true) {
273
- throw new LimitedConnectionError('Cannot open protocol stream on limited connection')
253
+ private async runMiddlewareChain (stream: Stream, connection: ConnectionInterface, middleware: StreamMiddleware[]): Promise<Stream> {
254
+ for (let i = 0; i < middleware.length; i++) {
255
+ const mw = middleware[i]
256
+ stream.log.trace('running middleware', i, mw)
257
+
258
+ // eslint-disable-next-line no-loop-func
259
+ await new Promise<void>((resolve, reject) => {
260
+ try {
261
+ const result = mw(stream, connection, (s, c) => {
262
+ stream = s
263
+ connection = c
264
+ resolve()
265
+ })
266
+
267
+ if (result instanceof Promise) {
268
+ result.catch(reject)
269
+ }
270
+ } catch (err) {
271
+ reject(err)
274
272
  }
275
-
276
- await handler({ connection: this, stream: muxedStream })
277
273
  })
278
- .catch(async err => {
279
- this.log.error('error handling incoming stream id %s - %e', muxedStream.id, err)
280
274
 
281
- muxedStream.abort(err)
282
- })
275
+ stream.log.trace('ran middleware', i, mw)
276
+ }
277
+
278
+ return stream
283
279
  }
284
280
 
285
281
  /**
286
282
  * Close the connection
287
283
  */
288
284
  async close (options: AbortOptions = {}): Promise<void> {
289
- if (this.status === 'closed' || this.status === 'closing') {
290
- return
291
- }
292
-
293
285
  this.log('closing connection to %a', this.remoteAddr)
294
286
 
295
- this.status = 'closing'
296
-
297
287
  if (options.signal == null) {
298
- const signal = AbortSignal.timeout(CLOSE_TIMEOUT)
288
+ const signal = AbortSignal.timeout(this.closeTimeout)
299
289
  setMaxListeners(Infinity, signal)
300
290
 
301
291
  options = {
@@ -304,42 +294,13 @@ export class Connection implements ConnectionInterface {
304
294
  }
305
295
  }
306
296
 
307
- try {
308
- this.log.trace('closing underlying transport')
309
-
310
- // ensure remaining streams are closed gracefully
311
- await this.muxer?.close(options)
312
-
313
- // close the underlying transport
314
- await this.maConn.close(options)
315
-
316
- this.log.trace('updating timeline with close time')
317
-
318
- this.status = 'closed'
319
- this.timeline.close = Date.now()
320
- } catch (err: any) {
321
- this.log.error('error encountered during graceful close of connection to %a', this.remoteAddr, err)
322
- this.abort(err)
323
- }
297
+ await this.muxer?.close(options)
298
+ await this.maConn.close(options)
324
299
  }
325
300
 
326
301
  abort (err: Error): void {
327
- if (this.status === 'closed') {
328
- return
329
- }
330
-
331
- this.log.error('aborting connection to %a due to error', this.remoteAddr, err)
332
-
333
- this.status = 'closing'
334
-
335
- // ensure remaining streams are aborted
336
302
  this.muxer?.abort(err)
337
-
338
- // abort the underlying transport
339
303
  this.maConn.abort(err)
340
-
341
- this.status = 'closed'
342
- this.timeline.close = Date.now()
343
304
  }
344
305
  }
345
306
 
@@ -347,11 +308,13 @@ export function createConnection (components: ConnectionComponents, init: Connec
347
308
  return new Connection(components, init)
348
309
  }
349
310
 
350
- function findIncomingStreamLimit (protocol: string, registrar: Registrar): number | undefined {
311
+ function findIncomingStreamLimit (protocol: string, registrar: Registrar): number {
351
312
  try {
352
313
  const { options } = registrar.getHandler(protocol)
353
314
 
354
- return options.maxInboundStreams
315
+ if (options.maxInboundStreams != null) {
316
+ return options.maxInboundStreams
317
+ }
355
318
  } catch (err: any) {
356
319
  if (err.name !== 'UnhandledProtocolError') {
357
320
  throw err
package/src/get-peer.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { InvalidMultiaddrError, InvalidParametersError, isPeerId } from '@libp2p/interface'
2
2
  import { peerIdFromString } from '@libp2p/peer-id'
3
- import { isMultiaddr } from '@multiformats/multiaddr'
3
+ import { CODE_P2P, isMultiaddr } from '@multiformats/multiaddr'
4
4
  import { PEER_ID } from '@multiformats/multiaddr-matcher'
5
5
  import type { PeerId } from '@libp2p/interface'
6
6
  import type { Multiaddr } from '@multiformats/multiaddr'
@@ -24,7 +24,7 @@ export function getPeerAddress (peer: PeerId | Multiaddr | Multiaddr[]): PeerAdd
24
24
  let peerId: PeerId | undefined
25
25
 
26
26
  if (multiaddrs.length > 0) {
27
- const peerIdStr = multiaddrs[0].getPeerId()
27
+ const peerIdStr = multiaddrs[0].getComponents().findLast(c => c.code === CODE_P2P)?.value
28
28
  peerId = peerIdStr == null ? undefined : peerIdFromString(peerIdStr)
29
29
 
30
30
  // ensure PeerId is either not set or is consistent
@@ -33,7 +33,7 @@ export function getPeerAddress (peer: PeerId | Multiaddr | Multiaddr[]): PeerAdd
33
33
  throw new InvalidMultiaddrError('Invalid multiaddr')
34
34
  }
35
35
 
36
- const maPeerIdStr = ma.getPeerId()
36
+ const maPeerIdStr = ma.getComponents().findLast(c => c.code === CODE_P2P)?.value
37
37
 
38
38
  if (maPeerIdStr == null) {
39
39
  if (peerId != null) {
package/src/index.ts CHANGED
@@ -184,8 +184,8 @@ export type Libp2pOptions<T extends ServiceMap = ServiceMap> = Libp2pInit<T> & {
184
184
  * import { createLibp2p } from 'libp2p'
185
185
  * import { tcp } from '@libp2p/tcp'
186
186
  * import { mplex } from '@libp2p/mplex'
187
- * import { noise } from '@chainsafe/libp2p-noise'
188
- * import { yamux } from '@chainsafe/libp2p-yamux'
187
+ * import { noise } from '@libp2p/noise'
188
+ * import { yamux } from '@libp2p/yamux'
189
189
  *
190
190
  * // specify options
191
191
  * const options = {
package/src/libp2p.ts CHANGED
@@ -4,7 +4,7 @@ import { defaultLogger } from '@libp2p/logger'
4
4
  import { PeerSet } from '@libp2p/peer-collections'
5
5
  import { peerIdFromString } from '@libp2p/peer-id'
6
6
  import { persistentPeerStore } from '@libp2p/peer-store'
7
- import { isMultiaddr } from '@multiformats/multiaddr'
7
+ import { CODE_P2P, isMultiaddr } from '@multiformats/multiaddr'
8
8
  import { MemoryDatastore } from 'datastore-core/memory'
9
9
  import { TypedEventEmitter, setMaxListeners } from 'main-event'
10
10
  import { concat as uint8ArrayConcat } from 'uint8arrays/concat'
@@ -24,7 +24,7 @@ import { userAgent } from './user-agent.js'
24
24
  import * as pkg from './version.js'
25
25
  import type { Components } from './components.js'
26
26
  import type { Libp2p as Libp2pInterface, Libp2pInit } from './index.js'
27
- import type { PeerRouting, ContentRouting, Libp2pEvents, PendingDial, ServiceMap, AbortOptions, ComponentLogger, Logger, Connection, NewStreamOptions, Stream, Metrics, PeerId, PeerInfo, PeerStore, Topology, Libp2pStatus, IsDialableOptions, DialOptions, PublicKey, Ed25519PeerId, Secp256k1PeerId, RSAPublicKey, RSAPeerId, URLPeerId, Ed25519PublicKey, Secp256k1PublicKey, StreamHandler, StreamHandlerOptions } from '@libp2p/interface'
27
+ import type { PeerRouting, ContentRouting, Libp2pEvents, PendingDial, ServiceMap, AbortOptions, ComponentLogger, Logger, Connection, NewStreamOptions, Stream, Metrics, PeerId, PeerInfo, PeerStore, Topology, Libp2pStatus, IsDialableOptions, DialOptions, PublicKey, Ed25519PeerId, Secp256k1PeerId, RSAPublicKey, RSAPeerId, URLPeerId, Ed25519PublicKey, Secp256k1PublicKey, StreamHandler, StreamHandlerOptions, StreamMiddleware } from '@libp2p/interface'
28
28
  import type { Multiaddr } from '@multiformats/multiaddr'
29
29
 
30
30
  export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter<Libp2pEvents> implements Libp2pInterface<T> {
@@ -119,8 +119,9 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
119
119
  connectionEncrypters: (init.connectionEncrypters ?? []).map((fn, index) => this.configureComponent(`connection-encryption-${index}`, fn(this.components))),
120
120
  streamMuxers: (init.streamMuxers ?? []).map((fn, index) => this.configureComponent(`stream-muxers-${index}`, fn(this.components))),
121
121
  inboundUpgradeTimeout: init.connectionManager?.inboundUpgradeTimeout,
122
- inboundStreamProtocolNegotiationTimeout: init.connectionManager?.inboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout,
123
- outboundStreamProtocolNegotiationTimeout: init.connectionManager?.outboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout
122
+ inboundStreamProtocolNegotiationTimeout: init.connectionManager?.inboundStreamProtocolNegotiationTimeout,
123
+ outboundStreamProtocolNegotiationTimeout: init.connectionManager?.outboundStreamProtocolNegotiationTimeout,
124
+ connectionCloseTimeout: init.connectionManager?.connectionCloseTimeout
124
125
  })
125
126
 
126
127
  // Setup the transport manager
@@ -236,7 +237,7 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
236
237
 
237
238
  this.status = 'started'
238
239
  this.safeDispatchEvent('start', { detail: this })
239
- this.log('libp2p has started')
240
+ this.log('libp2p has started with peer id %p', this.peerId)
240
241
  } catch (err: any) {
241
242
  this.log.error('An error occurred starting libp2p', err)
242
243
  // set status to 'started' so this.stop() will stop any running components
@@ -304,9 +305,7 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
304
305
  throw new InvalidParametersError('no protocols were provided to open a stream')
305
306
  }
306
307
 
307
- const connection = await this.dial(peer, options)
308
-
309
- return connection.newStream(protocols, options)
308
+ return this.components.connectionManager.openStream(peer, protocols, options)
310
309
  }
311
310
 
312
311
  getMultiaddrs (): Multiaddr[] {
@@ -319,7 +318,7 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
319
318
 
320
319
  async hangUp (peer: PeerId | Multiaddr, options: AbortOptions = {}): Promise<void> {
321
320
  if (isMultiaddr(peer)) {
322
- peer = peerIdFromString(peer.getPeerId() ?? '')
321
+ peer = peerIdFromString(peer.getComponents().findLast(c => c.code === CODE_P2P)?.value ?? '')
323
322
  }
324
323
 
325
324
  await this.components.connectionManager.closeConnections(peer, options)
@@ -402,6 +401,14 @@ export class Libp2p<T extends ServiceMap = ServiceMap> extends TypedEventEmitter
402
401
  this.components.registrar.unregister(id)
403
402
  }
404
403
 
404
+ use (protocol: string, middleware: StreamMiddleware | StreamMiddleware[]): void {
405
+ this.components.registrar.use(protocol, Array.isArray(middleware) ? middleware : [middleware])
406
+ }
407
+
408
+ unuse (protocol: string): void {
409
+ this.components.registrar.unuse(protocol)
410
+ }
411
+
405
412
  async isDialable (multiaddr: Multiaddr, options: IsDialableOptions = {}): Promise<boolean> {
406
413
  return this.components.connectionManager.isDialable(multiaddr, options)
407
414
  }
@@ -1,5 +1,5 @@
1
1
  import { NotFoundError } from '@libp2p/interface'
2
- import { createScalableCuckooFilter } from '@libp2p/utils/filters'
2
+ import { createScalableCuckooFilter } from '@libp2p/utils'
3
3
  import merge from 'it-merge'
4
4
  import parallel from 'it-parallel'
5
5
  import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
@@ -2,7 +2,7 @@ import { randomBytes } from '@libp2p/crypto'
2
2
  import { anySignal } from 'any-signal'
3
3
  import { TypedEventEmitter, setMaxListeners } from 'main-event'
4
4
  import pDefer from 'p-defer'
5
- import { raceEvent } from 'race-event'
5
+ import { pEvent } from 'p-event'
6
6
  import { raceSignal } from 'race-signal'
7
7
  import type { AbortOptions, ComponentLogger, Logger, PeerInfo, PeerRouting, Startable } from '@libp2p/interface'
8
8
  import type { RandomWalk as RandomWalkInterface } from '@libp2p/interface-internal'
@@ -68,12 +68,22 @@ export class RandomWalk extends TypedEventEmitter<RandomWalkEvents> implements R
68
68
  this.needNext = pDefer()
69
69
 
70
70
  // wait for a walk:peer or walk:error event
71
- const event = await raceEvent<CustomEvent<PeerInfo>>(this, 'walk:peer', signal, {
72
- errorEvent: 'walk:error'
71
+ const event = await pEvent<'walk:peer', CustomEvent<PeerInfo>>(this, 'walk:peer', {
72
+ signal,
73
+ rejectionEvents: [
74
+ 'walk:error'
75
+ ]
73
76
  })
74
77
 
75
78
  yield event.detail
76
79
  }
80
+ } catch (err: any) {
81
+ // test for walk:error event
82
+ if (err.detail != null) {
83
+ throw err.detail
84
+ }
85
+
86
+ throw err
77
87
  } finally {
78
88
  signal.clear()
79
89
  this.walkers--