@libp2p/circuit-relay-v2 3.2.23 → 3.2.24-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 (52) hide show
  1. package/dist/index.min.js +1 -1
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/constants.d.ts +0 -4
  4. package/dist/src/constants.d.ts.map +1 -1
  5. package/dist/src/constants.js +0 -4
  6. package/dist/src/constants.js.map +1 -1
  7. package/dist/src/index.d.ts +170 -7
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js +12 -2
  10. package/dist/src/index.js.map +1 -1
  11. package/dist/src/server/index.d.ts +41 -45
  12. package/dist/src/server/index.d.ts.map +1 -1
  13. package/dist/src/server/index.js +30 -47
  14. package/dist/src/server/index.js.map +1 -1
  15. package/dist/src/server/reservation-store.d.ts +2 -36
  16. package/dist/src/server/reservation-store.d.ts.map +1 -1
  17. package/dist/src/server/reservation-store.js.map +1 -1
  18. package/dist/src/transport/discovery.d.ts +2 -17
  19. package/dist/src/transport/discovery.d.ts.map +1 -1
  20. package/dist/src/transport/discovery.js +2 -2
  21. package/dist/src/transport/discovery.js.map +1 -1
  22. package/dist/src/transport/index.d.ts +34 -42
  23. package/dist/src/transport/index.d.ts.map +1 -1
  24. package/dist/src/transport/index.js +291 -5
  25. package/dist/src/transport/index.js.map +1 -1
  26. package/dist/src/transport/reservation-store.d.ts +3 -37
  27. package/dist/src/transport/reservation-store.d.ts.map +1 -1
  28. package/dist/src/transport/reservation-store.js +4 -6
  29. package/dist/src/transport/reservation-store.js.map +1 -1
  30. package/dist/src/transport/stream-to-conn.d.ts +19 -0
  31. package/dist/src/transport/stream-to-conn.d.ts.map +1 -0
  32. package/dist/src/transport/stream-to-conn.js +60 -0
  33. package/dist/src/transport/stream-to-conn.js.map +1 -0
  34. package/dist/src/utils.d.ts.map +1 -1
  35. package/dist/src/utils.js +36 -59
  36. package/dist/src/utils.js.map +1 -1
  37. package/package.json +19 -24
  38. package/src/constants.ts +0 -5
  39. package/src/index.ts +207 -8
  40. package/src/server/index.ts +35 -100
  41. package/src/server/reservation-store.ts +2 -42
  42. package/src/transport/discovery.ts +4 -22
  43. package/src/transport/index.ts +338 -46
  44. package/src/transport/reservation-store.ts +8 -46
  45. package/src/transport/stream-to-conn.ts +91 -0
  46. package/src/utils.ts +37 -66
  47. package/dist/src/transport/transport.d.ts +0 -54
  48. package/dist/src/transport/transport.d.ts.map +0 -1
  49. package/dist/src/transport/transport.js +0 -314
  50. package/dist/src/transport/transport.js.map +0 -1
  51. package/dist/typedoc-urls.json +0 -23
  52. package/src/transport/transport.ts +0 -378
@@ -1,65 +1,357 @@
1
- import { CircuitRelayTransport } from './transport.js'
2
- import type { RelayDiscoveryComponents } from './discovery.js'
3
- import type { ReservationStoreInit } from './reservation-store.js'
4
- import type { Transport, Upgrader, Libp2pEvents, ConnectionGater, PeerId, TopologyFilter } from '@libp2p/interface'
5
- import type { AddressManager, Registrar } from '@libp2p/interface-internal'
6
- import type { TypedEventTarget } from 'main-event'
7
-
8
- export interface CircuitRelayTransportComponents extends RelayDiscoveryComponents {
9
- peerId: PeerId
10
- registrar: Registrar
11
- upgrader: Upgrader
12
- addressManager: AddressManager
13
- connectionGater: ConnectionGater
14
- events: TypedEventTarget<Libp2pEvents>
1
+ import { DialError, InvalidMessageError, serviceCapabilities, serviceDependencies, start, stop, transportSymbol } from '@libp2p/interface'
2
+ import { peerFilter } from '@libp2p/peer-collections'
3
+ import { peerIdFromMultihash, peerIdFromString } from '@libp2p/peer-id'
4
+ import { pbStream } from '@libp2p/utils'
5
+ import { CODE_P2P, multiaddr } from '@multiformats/multiaddr'
6
+ import { Circuit } from '@multiformats/multiaddr-matcher'
7
+ import { setMaxListeners } from 'main-event'
8
+ import * as Digest from 'multiformats/hashes/digest'
9
+ import { CustomProgressEvent } from 'progress-events'
10
+ import { DEFAULT_DISCOVERY_FILTER_ERROR_RATE, DEFAULT_DISCOVERY_FILTER_SIZE, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js'
11
+ import { StopMessage, HopMessage, Status } from '../pb/index.js'
12
+ import { CircuitListen, CircuitSearch, LimitTracker } from '../utils.js'
13
+ import { RelayDiscovery } from './discovery.js'
14
+ import { createListener } from './listener.js'
15
+ import { ReservationStore } from './reservation-store.js'
16
+ import { streamToMaConnection } from './stream-to-conn.js'
17
+ import type { CircuitRelayTransportComponents, CircuitRelayTransportInit } from '../index.ts'
18
+ import type { Transport, CreateListenerOptions, Listener, Logger, Connection, Stream, OutboundConnectionUpgradeEvents, DialTransportOptions, OpenConnectionProgressEvents } from '@libp2p/interface'
19
+ import type { Multiaddr } from '@multiformats/multiaddr'
20
+ import type { ProgressEvent } from 'progress-events'
21
+
22
+ const isValidStop = (request: StopMessage): request is Required<StopMessage> => {
23
+ if (request.peer == null) {
24
+ return false
25
+ }
26
+
27
+ try {
28
+ request.peer.addrs.forEach(multiaddr)
29
+ } catch {
30
+ return false
31
+ }
32
+
33
+ return true
15
34
  }
16
35
 
17
- /**
18
- * RelayConfig configures the circuit v2 relay transport.
19
- */
20
- export interface CircuitRelayTransportInit extends ReservationStoreInit {
36
+ const defaults = {
37
+ maxInboundStopStreams: MAX_CONNECTIONS,
38
+ maxOutboundStopStreams: MAX_CONNECTIONS,
39
+ stopTimeout: 30000
40
+ }
41
+
42
+ export type CircuitRelayDialEvents =
43
+ OutboundConnectionUpgradeEvents |
44
+ OpenConnectionProgressEvents |
45
+ ProgressEvent<'circuit-relay:open-connection'> |
46
+ ProgressEvent<'circuit-relay:reuse-connection'> |
47
+ ProgressEvent<'circuit-relay:open-hop-stream'> |
48
+ ProgressEvent<'circuit-relay:write-connect-message'> |
49
+ ProgressEvent<'circuit-relay:read-connect-response'>
50
+
51
+ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents> {
52
+ private readonly components: CircuitRelayTransportComponents
53
+ private readonly discovery?: RelayDiscovery
54
+ public readonly reservationStore: ReservationStore
55
+ private readonly maxInboundStopStreams: number
56
+ private readonly maxOutboundStopStreams?: number
57
+ private started: boolean
58
+ private readonly log: Logger
59
+ private shutdownController: AbortController
60
+
61
+ constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit = {}) {
62
+ this.components = components
63
+ this.log = components.logger.forComponent('libp2p:circuit-relay:transport')
64
+ this.maxInboundStopStreams = init.maxInboundStopStreams ?? defaults.maxInboundStopStreams
65
+ this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams
66
+ this.shutdownController = new AbortController()
67
+
68
+ this.discovery = new RelayDiscovery(components, {
69
+ filter: init.discoveryFilter ?? peerFilter(DEFAULT_DISCOVERY_FILTER_SIZE, DEFAULT_DISCOVERY_FILTER_ERROR_RATE)
70
+ })
71
+ this.discovery.addEventListener('relay:discover', (evt) => {
72
+ this.reservationStore.addRelay(evt.detail, 'discovered')
73
+ .catch(err => {
74
+ if (err.name !== 'HadEnoughRelaysError' && err.name !== 'RelayQueueFullError') {
75
+ this.log.error('could not add discovered relay %p', evt.detail, err)
76
+ }
77
+ })
78
+ })
79
+ this.reservationStore = new ReservationStore(components, init)
80
+ this.reservationStore.addEventListener('relay:not-enough-relays', () => {
81
+ this.discovery?.startDiscovery()
82
+ })
83
+ this.reservationStore.addEventListener('relay:found-enough-relays', () => {
84
+ this.discovery?.stopDiscovery()
85
+ })
86
+
87
+ this.started = false
88
+
89
+ this.onStop = this.onStop.bind(this)
90
+ }
91
+
92
+ readonly [Symbol.toStringTag] = '@libp2p/circuit-relay-v2-transport'
93
+
94
+ readonly [serviceCapabilities]: string[] = [
95
+ '@libp2p/transport',
96
+ '@libp2p/circuit-relay-v2-transport'
97
+ ]
98
+
99
+ get [serviceDependencies] (): string[] {
100
+ // we only need identify if discovery is enabled
101
+ if (this.discovery != null) {
102
+ return [
103
+ '@libp2p/identify'
104
+ ]
105
+ }
106
+
107
+ return []
108
+ }
109
+
110
+ readonly [transportSymbol] = true
111
+
112
+ isStarted (): boolean {
113
+ return this.started
114
+ }
115
+
116
+ async start (): Promise<void> {
117
+ this.shutdownController = new AbortController()
118
+ setMaxListeners(Infinity, this.shutdownController.signal)
119
+
120
+ await this.components.registrar.handle(RELAY_V2_STOP_CODEC, this.onStop, {
121
+ maxInboundStreams: this.maxInboundStopStreams,
122
+ maxOutboundStreams: this.maxOutboundStopStreams,
123
+ runOnLimitedConnection: true
124
+ })
125
+
126
+ await start(this.discovery, this.reservationStore)
127
+
128
+ this.started = true
129
+ }
130
+
131
+ async stop (): Promise<void> {
132
+ this.shutdownController.abort()
133
+ await stop(this.discovery, this.reservationStore)
134
+ await this.components.registrar.unhandle(RELAY_V2_STOP_CODEC)
135
+
136
+ this.started = false
137
+ }
138
+
21
139
  /**
22
- * An optional filter used to prevent duplicate attempts to reserve relay
23
- * slots on the same peer
140
+ * Dial a peer over a relay
24
141
  */
25
- discoveryFilter?: TopologyFilter
142
+ async dial (ma: Multiaddr, options: DialTransportOptions<CircuitRelayDialEvents>): Promise<Connection> {
143
+ // Check the multiaddr to see if it contains a relay and a destination peer
144
+ const addrs = ma.toString().split('/p2p-circuit')
145
+ const relayAddr = multiaddr(addrs[0])
146
+ const destinationAddr = multiaddr(addrs[addrs.length - 1])
147
+ const relayId = relayAddr.getComponents().find(c => c.code === CODE_P2P)?.value
148
+ const destinationId = destinationAddr.getComponents().find(c => c.code === CODE_P2P)?.value
149
+
150
+ if (relayId == null || destinationId == null) {
151
+ const errMsg = `ircuit relay dial to ${ma.toString()} failed as address did not have both relay and destination PeerIDs`
152
+ this.log.error(`c${errMsg}`)
153
+ throw new DialError(`C${errMsg}`)
154
+ }
155
+
156
+ const relayPeer = peerIdFromString(relayId)
157
+ const destinationPeer = peerIdFromString(destinationId)
158
+
159
+ const relayConnections = this.components.connectionManager.getConnections(relayPeer)
160
+ let relayConnection = relayConnections[0]
161
+
162
+ if (relayConnection == null) {
163
+ await this.components.peerStore.merge(relayPeer, {
164
+ multiaddrs: [relayAddr]
165
+ })
166
+
167
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:open-connection'))
168
+ relayConnection = await this.components.connectionManager.openConnection(relayPeer, options)
169
+ } else {
170
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:reuse-connection'))
171
+ }
172
+
173
+ let stream: Stream | undefined
174
+
175
+ try {
176
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:open-hop-stream'))
177
+ stream = await relayConnection.newStream(RELAY_V2_HOP_CODEC, options)
178
+
179
+ const hopstr = pbStream(stream).pb(HopMessage)
180
+
181
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:write-connect-message'))
182
+ await hopstr.write({
183
+ type: HopMessage.Type.CONNECT,
184
+ peer: {
185
+ id: destinationPeer.toMultihash().bytes,
186
+ addrs: [multiaddr(destinationAddr).bytes]
187
+ }
188
+ }, options)
189
+
190
+ options.onProgress?.(new CustomProgressEvent('circuit-relay:read-connect-response'))
191
+ const status = await hopstr.read(options)
192
+
193
+ if (status.status !== Status.OK) {
194
+ throw new InvalidMessageError(`failed to connect via relay with status ${status?.status?.toString() ?? 'undefined'}`)
195
+ }
196
+
197
+ const limits = new LimitTracker(status.limit)
198
+
199
+ const maConn = streamToMaConnection({
200
+ stream: hopstr.unwrap().unwrap(),
201
+ remoteAddr: ma,
202
+ localAddr: relayAddr.encapsulate(`/p2p-circuit/p2p/${this.components.peerId.toString()}`),
203
+ onDataRead: limits.onData,
204
+ onDataWrite: limits.onData,
205
+ log: stream.log.newScope('circuit-relay:connection')
206
+ })
207
+
208
+ const conn = await this.components.upgrader.upgradeOutbound(maConn, {
209
+ ...options,
210
+ limits: limits.getLimits()
211
+ })
212
+
213
+ conn.log('outbound relayed connection established to %p with limits %o, over connection %s', conn.remotePeer, status.limit ?? 'none', relayConnection.id)
214
+
215
+ return conn
216
+ } catch (err: any) {
217
+ this.log.error('circuit relay dial to destination %p via relay %p failed', destinationPeer, relayPeer, err)
218
+ stream?.abort(err)
219
+
220
+ throw err
221
+ }
222
+ }
26
223
 
27
224
  /**
28
- * The maximum number of simultaneous STOP inbound streams that can be open at
29
- * once - each inbound relayed connection uses a STOP stream
30
- *
31
- * @default 300
225
+ * Create a listener
32
226
  */
33
- maxInboundStopStreams?: number
227
+ createListener (options: CreateListenerOptions): Listener {
228
+ return createListener({
229
+ peerId: this.components.peerId,
230
+ connectionManager: this.components.connectionManager,
231
+ addressManager: this.components.addressManager,
232
+ reservationStore: this.reservationStore,
233
+ logger: this.components.logger
234
+ })
235
+ }
34
236
 
35
237
  /**
36
- * The maximum number of simultaneous STOP outbound streams that can be open
37
- * at once. If this transport is used along with the relay server these
38
- * settings should be set to the same value
39
- *
40
- * @default 300
238
+ * Filter check for all Multiaddrs that this transport can listen on
41
239
  */
42
- maxOutboundStopStreams?: number
240
+ listenFilter (multiaddrs: Multiaddr[]): Multiaddr[] {
241
+ multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
242
+
243
+ return multiaddrs.filter((ma) => {
244
+ return CircuitListen.exactMatch(ma) || CircuitSearch.exactMatch(ma)
245
+ })
246
+ }
43
247
 
44
248
  /**
45
- * Incoming STOP requests (e.g. when a remote peer wants to dial us via a
46
- * relay) must finish the initial protocol negotiation within this timeout in
47
- * ms
48
- *
49
- * @deprecated Configure `connectionManager.inboundUpgradeTimeout` instead
249
+ * Filter check for all Multiaddrs that this transport can dial
50
250
  */
51
- stopTimeout?: number
251
+ dialFilter (multiaddrs: Multiaddr[]): Multiaddr[] {
252
+ multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
253
+
254
+ return multiaddrs.filter((ma) => {
255
+ return Circuit.exactMatch(ma)
256
+ })
257
+ }
52
258
 
53
259
  /**
54
- * When creating a reservation it must complete within this number of ms
55
- *
56
- * @default 10_000
260
+ * An incoming STOP request means a remote peer wants to dial us via a relay
57
261
  */
58
- reservationCompletionTimeout?: number
59
- }
262
+ async onStop (stream: Stream, connection: Connection): Promise<void> {
263
+ const signal = this.components.upgrader.createInboundAbortSignal(this.shutdownController.signal)
264
+
265
+ try {
266
+ if (!this.reservationStore.hasReservation(connection.remotePeer)) {
267
+ try {
268
+ this.log('dialed via relay we did not have a reservation on, start listening on that relay address')
269
+ await this.components.transportManager.listen([connection.remoteAddr.encapsulate('/p2p-circuit')])
270
+ } catch (err: any) {
271
+ // failed to refresh our hitherto unknown relay reservation but allow the connection attempt anyway
272
+ this.log.error('failed to listen on a relay peer we were dialed via but did not have a reservation on', err)
273
+ }
274
+ }
275
+
276
+ const stopStream = pbStream(stream).pb(StopMessage)
277
+ const request = await stopStream.read({
278
+ signal
279
+ })
280
+
281
+ this.log('new circuit relay v2 stop stream from %p with type %s', connection.remotePeer, request.type)
282
+
283
+ if (request?.type === undefined) {
284
+ this.log.error('type was missing from circuit v2 stop protocol request from %s', connection.remotePeer)
285
+ await stopStream.write({ type: StopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE }, {
286
+ signal
287
+ })
288
+ await stream.close({
289
+ signal
290
+ })
291
+ return
292
+ }
293
+
294
+ // Validate the STOP request has the required input
295
+ if (request.type !== StopMessage.Type.CONNECT) {
296
+ this.log.error('invalid stop connect request via peer %p', connection.remotePeer)
297
+ await stopStream.write({ type: StopMessage.Type.STATUS, status: Status.UNEXPECTED_MESSAGE }, {
298
+ signal
299
+ })
300
+ await stream.close({
301
+ signal
302
+ })
303
+ return
304
+ }
305
+
306
+ if (!isValidStop(request)) {
307
+ this.log.error('invalid stop connect request via peer %p', connection.remotePeer)
308
+ await stopStream.write({ type: StopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE }, {
309
+ signal
310
+ })
311
+ await stream.close({
312
+ signal
313
+ })
314
+ return
315
+ }
316
+
317
+ const remotePeerId = peerIdFromMultihash(Digest.decode(request.peer.id))
318
+
319
+ if ((await this.components.connectionGater.denyInboundRelayedConnection?.(connection.remotePeer, remotePeerId)) === true) {
320
+ this.log.error('connection gater denied inbound relayed connection from %p', connection.remotePeer)
321
+ await stopStream.write({ type: StopMessage.Type.STATUS, status: Status.PERMISSION_DENIED }, {
322
+ signal
323
+ })
324
+ await stream.close({
325
+ signal
326
+ })
327
+ return
328
+ }
329
+
330
+ this.log.trace('sending success response to %p', connection.remotePeer)
331
+ await stopStream.write({ type: StopMessage.Type.STATUS, status: Status.OK }, {
332
+ signal
333
+ })
334
+
335
+ const limits = new LimitTracker(request.limit)
336
+ const remoteAddr = connection.remoteAddr.encapsulate(`/p2p-circuit/p2p/${remotePeerId.toString()}`)
337
+ const localAddr = this.components.addressManager.getAddresses()[0]
338
+ const maConn = streamToMaConnection({
339
+ stream: stopStream.unwrap().unwrap(),
340
+ remoteAddr,
341
+ localAddr,
342
+ onDataRead: limits.onData,
343
+ onDataWrite: limits.onData,
344
+ log: stream.log.newScope('circuit-relay:connection')
345
+ })
346
+
347
+ await this.components.upgrader.upgradeInbound(maConn, {
348
+ limits: limits.getLimits(),
349
+ signal
350
+ })
60
351
 
61
- export function circuitRelayTransport (init: CircuitRelayTransportInit = {}): (components: CircuitRelayTransportComponents) => Transport {
62
- return (components) => {
63
- return new CircuitRelayTransport(components, init)
352
+ maConn.log('inbound relayed connection established to %p with limits %o, over connection %s', remotePeerId, request.limit ?? 'none', connection.id)
353
+ } finally {
354
+ signal?.clear()
355
+ }
64
356
  }
65
357
  }
@@ -1,20 +1,19 @@
1
1
  import { ListenError } from '@libp2p/interface'
2
2
  import { PeerMap } from '@libp2p/peer-collections'
3
- import { createScalableCuckooFilter } from '@libp2p/utils/filters'
4
- import { PeerQueue } from '@libp2p/utils/peer-queue'
5
- import { multiaddr } from '@multiformats/multiaddr'
3
+ import { createScalableCuckooFilter, PeerQueue, pbStream } from '@libp2p/utils'
4
+ import { CODE_P2P, multiaddr } from '@multiformats/multiaddr'
6
5
  import { Circuit } from '@multiformats/multiaddr-matcher'
7
- import { pbStream } from 'it-protobuf-stream'
8
6
  import { TypedEventEmitter, setMaxListeners } from 'main-event'
9
7
  import { nanoid } from 'nanoid'
10
8
  import { DEFAULT_MAX_RESERVATION_QUEUE_LENGTH, DEFAULT_RESERVATION_COMPLETION_TIMEOUT, DEFAULT_RESERVATION_CONCURRENCY, KEEP_ALIVE_TAG, RELAY_V2_HOP_CODEC } from '../constants.js'
11
9
  import { DoubleRelayError, HadEnoughRelaysError, RelayQueueFullError } from '../errors.js'
12
10
  import { HopMessage, Status } from '../pb/index.js'
13
11
  import { getExpirationMilliseconds } from '../utils.js'
12
+ import type { TransportReservationStoreComponents, TransportReservationStoreInit } from '../index.ts'
14
13
  import type { Reservation } from '../pb/index.js'
15
- import type { AbortOptions, Libp2pEvents, ComponentLogger, Logger, PeerId, PeerStore, Startable, Metrics, Peer, Connection } from '@libp2p/interface'
14
+ import type { AbortOptions, Libp2pEvents, Logger, PeerId, PeerStore, Startable, Peer, Connection } from '@libp2p/interface'
16
15
  import type { ConnectionManager } from '@libp2p/interface-internal'
17
- import type { Filter } from '@libp2p/utils/filters'
16
+ import type { Filter } from '@libp2p/utils'
18
17
  import type { TypedEventTarget } from 'main-event'
19
18
 
20
19
  // allow refreshing a relay reservation if it will expire in the next 10 minutes
@@ -26,43 +25,6 @@ const REFRESH_TIMEOUT = (60 * 1000) * 5
26
25
  // minimum duration before which a reservation must not be refreshed
27
26
  const REFRESH_TIMEOUT_MIN = 30 * 1000
28
27
 
29
- export interface ReservationStoreComponents {
30
- peerId: PeerId
31
- connectionManager: ConnectionManager
32
- peerStore: PeerStore
33
- events: TypedEventTarget<Libp2pEvents>
34
- logger: ComponentLogger
35
- metrics?: Metrics
36
- }
37
-
38
- export interface ReservationStoreInit {
39
- /**
40
- * Multiple relays may be discovered simultaneously - to prevent listening
41
- * on too many relays, this value controls how many to attempt to reserve a
42
- * slot on at once. If set to more than one, we may end up listening on
43
- * more relays than the `maxReservations` value, but on networks with poor
44
- * connectivity the user may wish to attempt to reserve on multiple relays
45
- * simultaneously.
46
- *
47
- * @default 1
48
- */
49
- reservationConcurrency?: number
50
-
51
- /**
52
- * Limit the number of potential relays we will dial
53
- *
54
- * @default 100
55
- */
56
- maxReservationQueueLength?: number
57
-
58
- /**
59
- * When creating a reservation it must complete within this number of ms
60
- *
61
- * @default 5000
62
- */
63
- reservationCompletionTimeout?: number
64
- }
65
-
66
28
  export type RelayType = 'discovered' | 'configured'
67
29
 
68
30
  export interface DiscoveredRelayEntry {
@@ -120,7 +82,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
120
82
  private readonly log: Logger
121
83
  private relayFilter: Filter
122
84
 
123
- constructor (components: ReservationStoreComponents, init?: ReservationStoreInit) {
85
+ constructor (components: TransportReservationStoreComponents, init?: TransportReservationStoreInit) {
124
86
  super()
125
87
 
126
88
  this.log = components.logger.forComponent('libp2p:circuit-relay:transport:reservation-store')
@@ -453,7 +415,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
453
415
  }
454
416
  }
455
417
 
456
- this.log.trace('read response %o', response)
418
+ this.log.trace('read response %s', response.status)
457
419
 
458
420
  if (response.status === Status.OK && response.reservation != null) {
459
421
  // check that the returned relay has the relay address - this can be
@@ -465,7 +427,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
465
427
  for (const buf of response.reservation.addrs) {
466
428
  let ma = multiaddr(buf)
467
429
 
468
- if (ma.getPeerId() == null) {
430
+ if (ma.getComponents().find(c => c.code === CODE_P2P) == null) {
469
431
  ma = ma.encapsulate(`/p2p/${connection.remotePeer}`)
470
432
  }
471
433
 
@@ -0,0 +1,91 @@
1
+ import { AbstractMultiaddrConnection } from '@libp2p/utils'
2
+ import { Uint8ArrayList } from 'uint8arraylist'
3
+ import type { AbortOptions, MultiaddrConnection, Stream } from '@libp2p/interface'
4
+ import type { AbstractMultiaddrConnectionInit, SendResult } from '@libp2p/utils'
5
+
6
+ export interface StreamMultiaddrConnectionInit extends Omit<AbstractMultiaddrConnectionInit, 'direction'> {
7
+ stream: Stream
8
+
9
+ /**
10
+ * A callback invoked when data is read from the stream
11
+ */
12
+ onDataRead?(buf: Uint8ArrayList | Uint8Array): void
13
+
14
+ /**
15
+ * A callback invoked when data is written to the stream
16
+ */
17
+ onDataWrite?(buf: Uint8ArrayList | Uint8Array): void
18
+ }
19
+
20
+ class StreamMultiaddrConnection extends AbstractMultiaddrConnection {
21
+ private stream: Stream
22
+ private init: StreamMultiaddrConnectionInit
23
+
24
+ constructor (init: StreamMultiaddrConnectionInit) {
25
+ super({
26
+ ...init,
27
+ direction: init.stream.direction
28
+
29
+ })
30
+
31
+ this.init = init
32
+ this.stream = init.stream
33
+
34
+ this.stream.addEventListener('close', (evt) => {
35
+ this.onTransportClosed(evt.error)
36
+ })
37
+
38
+ this.stream.addEventListener('remoteCloseWrite', (evt) => {
39
+ this.onRemoteCloseWrite()
40
+
41
+ // close our end when the remote closes
42
+ this.close()
43
+ .catch(err => {
44
+ this.abort(err)
45
+ })
46
+ })
47
+
48
+ // count incoming bytes
49
+ this.stream.addEventListener('message', (evt) => {
50
+ init.onDataRead?.(evt.data)
51
+ this.onData(evt.data)
52
+ })
53
+
54
+ // forward drain events
55
+ this.stream.addEventListener('drain', () => {
56
+ this.safeDispatchEvent('drain')
57
+ })
58
+ }
59
+
60
+ sendData (data: Uint8ArrayList): SendResult {
61
+ this.init.onDataWrite?.(data)
62
+
63
+ return {
64
+ sentBytes: data.byteLength,
65
+ canSendMore: this.stream.send(data)
66
+ }
67
+ }
68
+
69
+ async sendClose (options?: AbortOptions): Promise<void> {
70
+ await this.stream.close(options)
71
+ }
72
+
73
+ sendReset (): void {
74
+ this.stream.abort(new Error('An error occurred'))
75
+ }
76
+
77
+ sendPause (): void {
78
+ this.stream.pause()
79
+ }
80
+
81
+ sendResume (): void {
82
+ this.stream.resume()
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Convert a Stream into a MultiaddrConnection.
88
+ */
89
+ export function streamToMaConnection (init: StreamMultiaddrConnectionInit): MultiaddrConnection {
90
+ return new StreamMultiaddrConnection(init)
91
+ }