@libp2p/circuit-relay-v2 2.1.3 → 2.1.4-5d199f9b6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. package/dist/index.min.js +2 -2
  2. package/dist/src/constants.d.ts +4 -6
  3. package/dist/src/constants.d.ts.map +1 -1
  4. package/dist/src/constants.js +5 -6
  5. package/dist/src/constants.js.map +1 -1
  6. package/dist/src/index.d.ts +18 -3
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/pb/index.d.ts +12 -1
  10. package/dist/src/pb/index.d.ts.map +1 -1
  11. package/dist/src/pb/index.js +78 -2
  12. package/dist/src/pb/index.js.map +1 -1
  13. package/dist/src/server/index.d.ts.map +1 -1
  14. package/dist/src/server/index.js +71 -60
  15. package/dist/src/server/index.js.map +1 -1
  16. package/dist/src/server/reservation-store.d.ts +5 -9
  17. package/dist/src/server/reservation-store.d.ts.map +1 -1
  18. package/dist/src/server/reservation-store.js +32 -33
  19. package/dist/src/server/reservation-store.js.map +1 -1
  20. package/dist/src/server/reservation-voucher.d.ts +1 -1
  21. package/dist/src/transport/discovery.js +1 -1
  22. package/dist/src/transport/discovery.js.map +1 -1
  23. package/dist/src/transport/index.d.ts +2 -2
  24. package/dist/src/transport/index.d.ts.map +1 -1
  25. package/dist/src/transport/listener.d.ts.map +1 -1
  26. package/dist/src/transport/listener.js +23 -22
  27. package/dist/src/transport/listener.js.map +1 -1
  28. package/dist/src/transport/reservation-store.d.ts +4 -3
  29. package/dist/src/transport/reservation-store.d.ts.map +1 -1
  30. package/dist/src/transport/reservation-store.js +111 -47
  31. package/dist/src/transport/reservation-store.js.map +1 -1
  32. package/dist/src/transport/transport.d.ts.map +1 -1
  33. package/dist/src/transport/transport.js +11 -8
  34. package/dist/src/transport/transport.js.map +1 -1
  35. package/dist/src/utils.d.ts +7 -1
  36. package/dist/src/utils.d.ts.map +1 -1
  37. package/dist/src/utils.js +19 -8
  38. package/dist/src/utils.js.map +1 -1
  39. package/package.json +12 -12
  40. package/src/constants.ts +7 -7
  41. package/src/index.ts +21 -3
  42. package/src/pb/index.proto +20 -1
  43. package/src/pb/index.ts +99 -3
  44. package/src/server/index.ts +75 -64
  45. package/src/server/reservation-store.ts +38 -42
  46. package/src/server/reservation-voucher.ts +2 -2
  47. package/src/transport/discovery.ts +1 -1
  48. package/src/transport/index.ts +2 -2
  49. package/src/transport/listener.ts +28 -25
  50. package/src/transport/reservation-store.ts +147 -57
  51. package/src/transport/transport.ts +12 -8
  52. package/src/utils.ts +21 -8
  53. package/dist/typedoc-urls.json +0 -23
@@ -1,15 +1,14 @@
1
- import { KEEP_ALIVE, TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
1
+ import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
2
2
  import { PeerMap } from '@libp2p/peer-collections'
3
3
  import { createBloomFilter } from '@libp2p/utils/filters'
4
4
  import { PeerQueue } from '@libp2p/utils/peer-queue'
5
5
  import { multiaddr } from '@multiformats/multiaddr'
6
6
  import { pbStream } from 'it-protobuf-stream'
7
- import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
8
- import { DEFAULT_MAX_RESERVATION_QUEUE_LENGTH, DEFAULT_RESERVATION_COMPLETION_TIMEOUT, DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js'
7
+ import { DEFAULT_MAX_RESERVATION_QUEUE_LENGTH, DEFAULT_RESERVATION_COMPLETION_TIMEOUT, DEFAULT_RESERVATION_CONCURRENCY, KEEP_ALIVE_TAG, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js'
9
8
  import { HopMessage, Status } from '../pb/index.js'
10
9
  import { getExpirationMilliseconds } from '../utils.js'
11
10
  import type { Reservation } from '../pb/index.js'
12
- import type { TypedEventTarget, Libp2pEvents, AbortOptions, ComponentLogger, Logger, Connection, PeerId, PeerStore, Startable, Metrics } from '@libp2p/interface'
11
+ import type { TypedEventTarget, Libp2pEvents, AbortOptions, ComponentLogger, Logger, Connection, PeerId, PeerStore, Startable, Metrics, Peer } from '@libp2p/interface'
13
12
  import type { ConnectionManager, TransportManager } from '@libp2p/interface-internal'
14
13
  import type { Filter } from '@libp2p/utils/filters'
15
14
 
@@ -22,7 +21,7 @@ const REFRESH_TIMEOUT = (60 * 1000) * 5
22
21
  // minimum duration before which a reservation must not be refreshed
23
22
  const REFRESH_TIMEOUT_MIN = 30 * 1000
24
23
 
25
- export interface RelayStoreComponents {
24
+ export interface ReservationStoreComponents {
26
25
  peerId: PeerId
27
26
  connectionManager: ConnectionManager
28
27
  transportManager: TransportManager
@@ -32,7 +31,7 @@ export interface RelayStoreComponents {
32
31
  metrics?: Metrics
33
32
  }
34
33
 
35
- export interface RelayStoreInit {
34
+ export interface ReservationStoreInit {
36
35
  /**
37
36
  * Multiple relays may be discovered simultaneously - to prevent listening
38
37
  * on too many relays, this value controls how many to attempt to reserve a
@@ -71,6 +70,11 @@ interface RelayEntry {
71
70
  timeout: ReturnType<typeof setTimeout>
72
71
  type: RelayType
73
72
  reservation: Reservation
73
+
74
+ /**
75
+ * Stores the id of the connection we have to the relay
76
+ */
77
+ connection: string
74
78
  }
75
79
 
76
80
  export interface ReservationStoreEvents {
@@ -94,7 +98,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
94
98
  private readonly log: Logger
95
99
  private readonly relayFilter: Filter
96
100
 
97
- constructor (components: RelayStoreComponents, init?: RelayStoreInit) {
101
+ constructor (components: ReservationStoreComponents, init?: ReservationStoreInit) {
98
102
  super()
99
103
 
100
104
  this.log = components.logger.forComponent('libp2p:circuit-relay:transport:reservation-store')
@@ -117,11 +121,21 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
117
121
  metrics: components.metrics
118
122
  })
119
123
 
120
- // When a peer disconnects, if we had a reservation on that peer
121
- // remove the reservation and multiaddr and maybe trigger search
122
- // for new relays
123
- this.events.addEventListener('peer:disconnect', (evt) => {
124
- this.#removeRelay(evt.detail)
124
+ // reservations are only valid while we are still connected to the relay.
125
+ // if we had a reservation opened via that connection, remove it and maybe
126
+ // trigger a search for new relays
127
+ this.events.addEventListener('connection:close', (evt) => {
128
+ const reservation = [...this.reservations.values()]
129
+ .find(reservation => reservation.connection === evt.detail.id)
130
+
131
+ if (reservation == null) {
132
+ return
133
+ }
134
+
135
+ this.#removeReservation(evt.detail.remotePeer, reservation)
136
+ .catch(err => {
137
+ this.log('could not remove relay %p - %e', evt.detail, err)
138
+ })
125
139
  })
126
140
  }
127
141
 
@@ -134,10 +148,37 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
134
148
  }
135
149
 
136
150
  afterStart (): void {
137
- if (this.reservations.size < this.maxDiscoveredRelays) {
138
- this.log('not enough relays %d/%d', this.reservations.size, this.maxDiscoveredRelays)
139
- this.safeDispatchEvent('relay:not-enough-relays', {})
140
- }
151
+ // remove old relay tags
152
+ void Promise.resolve()
153
+ .then(async () => {
154
+ const relayPeers: Peer[] = await this.peerStore.all({
155
+ filters: [(peer) => {
156
+ return peer.tags.has(RELAY_TAG)
157
+ }]
158
+ })
159
+
160
+ this.log('removing tag from %d old relays', relayPeers.length)
161
+
162
+ // remove old relay tag and redial
163
+ await Promise.all(
164
+ relayPeers.map(async peer => {
165
+ await this.peerStore.merge(peer.id, {
166
+ tags: {
167
+ [RELAY_TAG]: undefined,
168
+ [KEEP_ALIVE_TAG]: undefined
169
+ }
170
+ })
171
+ })
172
+ )
173
+
174
+ if (this.reservations.size < this.maxDiscoveredRelays) {
175
+ this.log('not enough relays %d/%d', this.reservations.size, this.maxDiscoveredRelays)
176
+ this.safeDispatchEvent('relay:not-enough-relays', {})
177
+ }
178
+ })
179
+ .catch(err => {
180
+ this.log.error(err)
181
+ })
141
182
  }
142
183
 
143
184
  stop (): void {
@@ -157,26 +198,26 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
157
198
  */
158
199
  async addRelay (peerId: PeerId, type: RelayType): Promise<void> {
159
200
  if (this.peerId.equals(peerId)) {
160
- this.log('not trying to use self as relay')
201
+ this.log.trace('not trying to use self as relay')
161
202
  return
162
203
  }
163
204
 
164
205
  if (this.reserveQueue.size > this.maxReservationQueueLength) {
165
- this.log('not adding potential relay peer %p as the queue is full', peerId)
206
+ this.log.trace('not adding potential relay peer %p as the queue is full', peerId)
166
207
  return
167
208
  }
168
209
 
169
210
  if (this.reserveQueue.has(peerId)) {
170
- this.log('potential relay peer %p is already in the reservation queue', peerId)
211
+ this.log.trace('potential relay peer %p is already in the reservation queue', peerId)
171
212
  return
172
213
  }
173
214
 
174
215
  if (this.relayFilter.has(peerId.toMultihash().bytes)) {
175
- this.log('potential relay peer %p has failed previously, not trying again', peerId)
216
+ this.log.trace('potential relay peer %p has failed previously, not trying again', peerId)
176
217
  return
177
218
  }
178
219
 
179
- this.log('try to reserve relay slot with %p', peerId)
220
+ this.log.trace('try to reserve relay slot with %p', peerId)
180
221
 
181
222
  await this.reserveQueue.add(async () => {
182
223
  const start = Date.now()
@@ -186,13 +227,24 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
186
227
  const existingReservation = this.reservations.get(peerId)
187
228
 
188
229
  if (existingReservation != null) {
189
- if (getExpirationMilliseconds(existingReservation.reservation.expire) > REFRESH_WINDOW) {
190
- this.log('already have reservation on relay peer %p and it expires in more than 10 minutes', peerId)
230
+ const connections = this.connectionManager.getConnections(peerId)
231
+ let connected = false
232
+
233
+ if (connections.length === 0) {
234
+ this.log('already have relay reservation with %p but we are no longer connected', peerId)
235
+ }
236
+
237
+ if (connections.map(conn => conn.id).includes(existingReservation.connection)) {
238
+ this.log('already have relay reservation with %p and the original connection is still open', peerId)
239
+ connected = true
240
+ }
241
+
242
+ if (connected && getExpirationMilliseconds(existingReservation.reservation.expire) > REFRESH_WINDOW) {
243
+ this.log('already have relay reservation with %p but we are still connected and it does not expire soon', peerId)
191
244
  return
192
245
  }
193
246
 
194
- clearTimeout(existingReservation.timeout)
195
- this.reservations.delete(peerId)
247
+ await this.#removeReservation(peerId, existingReservation)
196
248
  }
197
249
 
198
250
  if (type === 'discovered' && [...this.reservations.values()].reduce((acc, curr) => {
@@ -202,7 +254,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
202
254
 
203
255
  return acc
204
256
  }, 0) >= this.maxDiscoveredRelays) {
205
- this.log('already have enough discovered relays')
257
+ this.log.trace('already have enough discovered relays')
206
258
  return
207
259
  }
208
260
 
@@ -222,25 +274,41 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
222
274
  signal
223
275
  })
224
276
 
225
- this.log('created reservation on relay peer %p', peerId)
226
-
227
277
  const expiration = getExpirationMilliseconds(reservation.expire)
228
278
 
279
+ this.log('created reservation on relay peer %p, expiry date is %s', peerId, new Date(Date.now() + expiration).toString())
280
+
229
281
  // sets a lower bound on the timeout, and also don't let it go over
230
282
  // 2^31 - 1 (setTimeout will only accept signed 32 bit integers)
231
283
  const timeoutDuration = Math.min(Math.max(expiration - REFRESH_TIMEOUT, REFRESH_TIMEOUT_MIN), Math.pow(2, 31) - 1)
232
284
 
233
285
  const timeout = setTimeout(() => {
234
- this.addRelay(peerId, type).catch(err => {
235
- this.log.error('could not refresh reservation to relay %p', peerId, err)
236
- })
286
+ this.log('refresh reservation to relay %p', peerId)
287
+
288
+ this.addRelay(peerId, type)
289
+ .catch(async err => {
290
+ this.log.error('could not refresh reservation to relay %p - %e', peerId, err)
291
+
292
+ const reservation = this.reservations.get(peerId)
293
+
294
+ if (reservation == null) {
295
+ this.log.error('did not have reservation after refreshing reservation failed %p', peerId)
296
+ return
297
+ }
298
+
299
+ await this.#removeReservation(peerId, reservation)
300
+ })
301
+ .catch(err => {
302
+ this.log.error('could not remove expired reservation to relay %p - %e', peerId, err)
303
+ })
237
304
  }, timeoutDuration)
238
305
 
239
306
  // we've managed to create a reservation successfully
240
307
  this.reservations.set(peerId, {
241
308
  timeout,
242
309
  reservation,
243
- type
310
+ type,
311
+ connection: connection.id
244
312
  })
245
313
 
246
314
  // ensure we don't close the connection to the relay
@@ -250,7 +318,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
250
318
  value: 1,
251
319
  ttl: expiration
252
320
  },
253
- [KEEP_ALIVE]: {
321
+ [KEEP_ALIVE_TAG]: {
254
322
  value: 1,
255
323
  ttl: expiration
256
324
  }
@@ -258,7 +326,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
258
326
  })
259
327
 
260
328
  // listen on multiaddr that only the circuit transport is listening for
261
- await this.transportManager.listen([multiaddr(`/p2p/${peerId.toString()}/p2p-circuit`)])
329
+ await this.transportManager.listen([multiaddr(`/p2p/${peerId.toString()}/p2p-circuit/p2p/${this.peerId.toString()}`)])
262
330
 
263
331
  this.safeDispatchEvent('relay:created-reservation', {
264
332
  detail: peerId
@@ -266,18 +334,19 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
266
334
  } catch (err) {
267
335
  this.log.error('could not reserve slot on %p after %dms', peerId, Date.now() - start, err)
268
336
 
337
+ // don't try this peer again
338
+ this.relayFilter.add(peerId.toMultihash().bytes)
339
+
269
340
  // cancel the renewal timeout if it's been set
270
341
  const reservation = this.reservations.get(peerId)
271
342
 
343
+ // if listening failed, remove the reservation
272
344
  if (reservation != null) {
273
- clearTimeout(reservation.timeout)
345
+ this.#removeReservation(peerId, reservation)
346
+ .catch(err => {
347
+ this.log.error('could not remove reservation on %p after reserving slot failed - %e', peerId, err)
348
+ })
274
349
  }
275
-
276
- // if listening failed, remove the reservation
277
- this.reservations.delete(peerId)
278
-
279
- // don't try this peer again
280
- this.relayFilter.add(peerId.toMultihash().bytes)
281
350
  }
282
351
  }, {
283
352
  peerId
@@ -296,6 +365,14 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
296
365
  return this.reservations.size
297
366
  }
298
367
 
368
+ async cancelReservations (): Promise<void> {
369
+ await Promise.all(
370
+ [...this.reservations.entries()].map(async ([peerId, reservation]) => {
371
+ await this.#removeReservation(peerId, reservation)
372
+ })
373
+ )
374
+ }
375
+
299
376
  async #createReservation (connection: Connection, options: AbortOptions): Promise<Reservation> {
300
377
  options.signal?.throwIfAborted()
301
378
 
@@ -318,24 +395,31 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
318
395
  }
319
396
  }
320
397
 
321
- if (response.status === Status.OK && (response.reservation != null)) {
398
+ if (response.status === Status.OK && response.reservation != null) {
322
399
  // check that the returned relay has the relay address - this can be
323
400
  // omitted when requesting a reservation from a go-libp2p relay we
324
401
  // already have a reservation on
325
- let hasRelayAddress = false
326
- const relayAddressBytes = connection.remoteAddr.bytes
402
+ const addresses = new Set<string>()
403
+ addresses.add(connection.remoteAddr.toString())
327
404
 
328
405
  for (const buf of response.reservation.addrs) {
329
- if (uint8ArrayEquals(relayAddressBytes, buf)) {
330
- hasRelayAddress = true
331
- break
406
+ let ma = multiaddr(buf)
407
+
408
+ if (ma.getPeerId() == null) {
409
+ ma = ma.encapsulate(`/p2p/${connection.remotePeer}`)
332
410
  }
333
- }
334
411
 
335
- if (!hasRelayAddress) {
336
- response.reservation.addrs.push(relayAddressBytes)
412
+ // TODO: workaround for https://github.com/libp2p/go-libp2p/issues/3003
413
+ ma = multiaddr(ma.toString().replace(
414
+ `/p2p/${connection.remotePeer}/p2p/${connection.remotePeer}`,
415
+ `/p2p/${connection.remotePeer}`
416
+ ))
417
+
418
+ addresses.add(ma.toString())
337
419
  }
338
420
 
421
+ response.reservation.addrs = [...addresses].map(str => multiaddr(str).bytes)
422
+
339
423
  return response.reservation
340
424
  }
341
425
 
@@ -348,18 +432,24 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
348
432
  /**
349
433
  * Remove listen relay
350
434
  */
351
- #removeRelay (peerId: PeerId): void {
352
- const existingReservation = this.reservations.get(peerId)
353
-
354
- if (existingReservation == null) {
435
+ async #removeReservation (peerId: PeerId, reservation: RelayEntry): Promise<void> {
436
+ if (!this.reservations.has(peerId)) {
437
+ this.log('not removing relay reservation with %p from local store as we do not have a reservation with this peer', peerId)
355
438
  return
356
439
  }
357
440
 
358
- this.log('connection to relay %p closed, removing reservation from local store', peerId)
359
-
360
- clearTimeout(existingReservation.timeout)
441
+ this.log('removing relay reservation with %p from local store', peerId)
442
+ clearTimeout(reservation.timeout)
361
443
  this.reservations.delete(peerId)
362
444
 
445
+ // untag the relay
446
+ await this.peerStore.merge(peerId, {
447
+ tags: {
448
+ [RELAY_TAG]: undefined,
449
+ [KEEP_ALIVE_TAG]: undefined
450
+ }
451
+ })
452
+
363
453
  this.safeDispatchEvent('relay:removed', { detail: peerId })
364
454
 
365
455
  if (this.reservations.size < this.maxDiscoveredRelays) {
@@ -2,14 +2,14 @@ import { DialError, InvalidMessageError, serviceCapabilities, serviceDependencie
2
2
  import { peerFilter } from '@libp2p/peer-collections'
3
3
  import { peerIdFromMultihash, peerIdFromString } from '@libp2p/peer-id'
4
4
  import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn'
5
- import * as mafmt from '@multiformats/mafmt'
6
5
  import { multiaddr } from '@multiformats/multiaddr'
6
+ import { Circuit } from '@multiformats/multiaddr-matcher'
7
7
  import { pbStream } from 'it-protobuf-stream'
8
8
  import * as Digest from 'multiformats/hashes/digest'
9
9
  import { CustomProgressEvent } from 'progress-events'
10
10
  import { CIRCUIT_PROTO_CODE, DEFAULT_DISCOVERY_FILTER_ERROR_RATE, DEFAULT_DISCOVERY_FILTER_SIZE, MAX_CONNECTIONS, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js'
11
11
  import { StopMessage, HopMessage, Status } from '../pb/index.js'
12
- import { LimitTracker } from '../utils.js'
12
+ import { CircuitListen, LimitTracker } from '../utils.js'
13
13
  import { RelayDiscovery } from './discovery.js'
14
14
  import { createListener } from './listener.js'
15
15
  import { ReservationStore } from './reservation-store.js'
@@ -184,9 +184,9 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
184
184
  const destinationId = destinationAddr.getPeerId()
185
185
 
186
186
  if (relayId == null || destinationId == null) {
187
- const errMsg = `Circuit relay dial to ${ma.toString()} failed as address did not have peer ids`
188
- this.log.error(errMsg)
189
- throw new DialError(errMsg)
187
+ const errMsg = `ircuit relay dial to ${ma.toString()} failed as address did not have both relay and destination PeerIDs`
188
+ this.log.error(`c${errMsg}`)
189
+ throw new DialError(`C${errMsg}`)
190
190
  }
191
191
 
192
192
  const relayPeer = peerIdFromString(relayId)
@@ -281,7 +281,7 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
281
281
  onProgress
282
282
  })
283
283
  } catch (err: any) {
284
- this.log.error(`Circuit relay dial to destination ${destinationPeer.toString()} via relay ${connection.remotePeer.toString()} failed`, err)
284
+ this.log.error(`circuit relay dial to destination ${destinationPeer.toString()} via relay ${connection.remotePeer.toString()} failed`, err)
285
285
  disconnectOnFailure && await connection.close()
286
286
  throw err
287
287
  }
@@ -305,7 +305,7 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
305
305
  multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
306
306
 
307
307
  return multiaddrs.filter((ma) => {
308
- return mafmt.Circuit.matches(ma)
308
+ return CircuitListen.exactMatch(ma)
309
309
  })
310
310
  }
311
311
 
@@ -313,7 +313,11 @@ export class CircuitRelayTransport implements Transport<CircuitRelayDialEvents>
313
313
  * Filter check for all Multiaddrs that this transport can dial
314
314
  */
315
315
  dialFilter (multiaddrs: Multiaddr[]): Multiaddr[] {
316
- return this.listenFilter(multiaddrs)
316
+ multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
317
+
318
+ return multiaddrs.filter((ma) => {
319
+ return Circuit.exactMatch(ma)
320
+ })
317
321
  }
318
322
 
319
323
  /**
package/src/utils.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import { P2P } from '@multiformats/multiaddr-matcher'
2
+ import { fmt, peerId, literal, optional, and } from '@multiformats/multiaddr-matcher/utils'
1
3
  import { anySignal } from 'any-signal'
2
4
  import { CID } from 'multiformats/cid'
3
5
  import { sha256 } from 'multiformats/hashes/sha2'
4
6
  import { DurationLimitError, TransferLimitError } from './errors.js'
7
+ import type { RelayReservation } from './index.js'
5
8
  import type { Limit } from './pb/index.js'
6
9
  import type { ConnectionLimits, LoggerOptions, Stream } from '@libp2p/interface'
7
10
  import type { Source } from 'it-stream-types'
@@ -34,16 +37,18 @@ async function * countStreamBytes (source: Source<Uint8Array | Uint8ArrayList>,
34
37
  }
35
38
  }
36
39
 
37
- export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: AbortSignal, limit: Limit | undefined, options: LoggerOptions): void {
40
+ export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: AbortSignal, reservation: RelayReservation, options: LoggerOptions): void {
38
41
  function abortStreams (err: Error): void {
39
42
  src.abort(err)
40
43
  dst.abort(err)
41
44
  }
42
45
 
43
- const signals = [abortSignal]
46
+ // combine shutdown signal and reservation expiry signal
47
+ const signals = [abortSignal, reservation.signal]
44
48
 
45
- if (limit?.duration != null) {
46
- signals.push(AbortSignal.timeout(limit.duration))
49
+ if (reservation.limit?.duration != null) {
50
+ options.log('limiting relayed connection duration to %dms', reservation.limit.duration)
51
+ signals.push(AbortSignal.timeout(reservation.limit.duration))
47
52
  }
48
53
 
49
54
  const signal = anySignal(signals)
@@ -53,15 +58,16 @@ export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: Abort
53
58
 
54
59
  let dataLimit: { remaining: bigint } | undefined
55
60
 
56
- if (limit?.data != null) {
61
+ if (reservation.limit?.data != null) {
57
62
  dataLimit = {
58
- remaining: limit.data
63
+ remaining: reservation.limit.data
59
64
  }
60
65
  }
61
66
 
62
67
  queueMicrotask(() => {
63
68
  const onAbort = (): void => {
64
- dst.abort(new DurationLimitError(`duration limit of ${limit?.duration} ms exceeded`))
69
+ options.log('relayed connection reached time limit')
70
+ dst.abort(new DurationLimitError(`duration limit of ${reservation.limit?.duration} ms exceeded`))
65
71
  }
66
72
 
67
73
  signal.addEventListener('abort', onAbort, { once: true })
@@ -83,7 +89,8 @@ export function createLimitedRelay (src: Stream, dst: Stream, abortSignal: Abort
83
89
 
84
90
  queueMicrotask(() => {
85
91
  const onAbort = (): void => {
86
- src.abort(new DurationLimitError(`duration limit of ${limit?.duration} ms exceeded`))
92
+ options.log('relayed connection reached time limit')
93
+ src.abort(new DurationLimitError(`duration limit of ${reservation.limit?.duration} ms exceeded`))
87
94
  }
88
95
 
89
96
  signal.addEventListener('abort', onAbort, { once: true })
@@ -185,3 +192,9 @@ export class LimitTracker {
185
192
  return output
186
193
  }
187
194
  }
195
+
196
+ /**
197
+ * A custom matcher that makes the `/p2p/peer-id` part of circuit relay
198
+ * addresses optional
199
+ */
200
+ export const CircuitListen = fmt(and(P2P.matchers[0], literal('p2p-circuit'), optional(peerId())))
@@ -1,23 +0,0 @@
1
- {
2
- "codec": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.Limit.codec.html",
3
- "decode": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.Limit.decode.html",
4
- "encode": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.Limit.encode.html",
5
- "CircuitRelayServerComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServerComponents.html",
6
- "CircuitRelayServerInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServerInit.html",
7
- "CircuitRelayService": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayService.html",
8
- ".:CircuitRelayService": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayService.html",
9
- "CircuitRelayServiceEvents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServiceEvents.html",
10
- ".:CircuitRelayServiceEvents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayServiceEvents.html",
11
- "CircuitRelayTransportComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayTransportComponents.html",
12
- "CircuitRelayTransportInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.CircuitRelayTransportInit.html",
13
- "Limit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.Limit-1.html",
14
- "RelayDiscoveryComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayDiscoveryComponents.html",
15
- "RelayReservation": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayReservation.html",
16
- ".:RelayReservation": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayReservation.html",
17
- "RelayStoreInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.RelayStoreInit.html",
18
- "ReservationStoreInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_circuit_relay_v2.ReservationStoreInit.html",
19
- "RELAY_V2_HOP_CODEC": "https://libp2p.github.io/js-libp2p/variables/_libp2p_circuit_relay_v2.RELAY_V2_HOP_CODEC.html",
20
- "RELAY_V2_STOP_CODEC": "https://libp2p.github.io/js-libp2p/variables/_libp2p_circuit_relay_v2.RELAY_V2_STOP_CODEC.html",
21
- "circuitRelayServer": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.circuitRelayServer.html",
22
- "circuitRelayTransport": "https://libp2p.github.io/js-libp2p/functions/_libp2p_circuit_relay_v2.circuitRelayTransport.html"
23
- }