@libp2p/circuit-relay-v2 2.1.3 → 2.1.4-5d199f9b6
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.
- package/dist/index.min.js +2 -2
- package/dist/src/constants.d.ts +4 -6
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +5 -6
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +18 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/pb/index.d.ts +12 -1
- package/dist/src/pb/index.d.ts.map +1 -1
- package/dist/src/pb/index.js +78 -2
- package/dist/src/pb/index.js.map +1 -1
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +71 -60
- package/dist/src/server/index.js.map +1 -1
- package/dist/src/server/reservation-store.d.ts +5 -9
- package/dist/src/server/reservation-store.d.ts.map +1 -1
- package/dist/src/server/reservation-store.js +32 -33
- package/dist/src/server/reservation-store.js.map +1 -1
- package/dist/src/server/reservation-voucher.d.ts +1 -1
- package/dist/src/transport/discovery.js +1 -1
- package/dist/src/transport/discovery.js.map +1 -1
- package/dist/src/transport/index.d.ts +2 -2
- package/dist/src/transport/index.d.ts.map +1 -1
- package/dist/src/transport/listener.d.ts.map +1 -1
- package/dist/src/transport/listener.js +23 -22
- package/dist/src/transport/listener.js.map +1 -1
- package/dist/src/transport/reservation-store.d.ts +4 -3
- package/dist/src/transport/reservation-store.d.ts.map +1 -1
- package/dist/src/transport/reservation-store.js +111 -47
- package/dist/src/transport/reservation-store.js.map +1 -1
- package/dist/src/transport/transport.d.ts.map +1 -1
- package/dist/src/transport/transport.js +11 -8
- package/dist/src/transport/transport.js.map +1 -1
- package/dist/src/utils.d.ts +7 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +19 -8
- package/dist/src/utils.js.map +1 -1
- package/package.json +12 -12
- package/src/constants.ts +7 -7
- package/src/index.ts +21 -3
- package/src/pb/index.proto +20 -1
- package/src/pb/index.ts +99 -3
- package/src/server/index.ts +75 -64
- package/src/server/reservation-store.ts +38 -42
- package/src/server/reservation-voucher.ts +2 -2
- package/src/transport/discovery.ts +1 -1
- package/src/transport/index.ts +2 -2
- package/src/transport/listener.ts +28 -25
- package/src/transport/reservation-store.ts +147 -57
- package/src/transport/transport.ts +12 -8
- package/src/utils.ts +21 -8
- package/dist/typedoc-urls.json +0 -23
@@ -1,15 +1,14 @@
|
|
1
|
-
import {
|
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 {
|
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
|
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
|
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:
|
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
|
-
//
|
121
|
-
//
|
122
|
-
// for new relays
|
123
|
-
this.events.addEventListener('
|
124
|
-
this
|
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
|
-
|
138
|
-
|
139
|
-
|
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
|
-
|
190
|
-
|
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
|
-
|
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.
|
235
|
-
|
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
|
-
[
|
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
|
-
|
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 &&
|
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
|
-
|
326
|
-
|
402
|
+
const addresses = new Set<string>()
|
403
|
+
addresses.add(connection.remoteAddr.toString())
|
327
404
|
|
328
405
|
for (const buf of response.reservation.addrs) {
|
329
|
-
|
330
|
-
|
331
|
-
|
406
|
+
let ma = multiaddr(buf)
|
407
|
+
|
408
|
+
if (ma.getPeerId() == null) {
|
409
|
+
ma = ma.encapsulate(`/p2p/${connection.remotePeer}`)
|
332
410
|
}
|
333
|
-
}
|
334
411
|
|
335
|
-
|
336
|
-
|
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
|
-
#
|
352
|
-
|
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('
|
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 = `
|
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(`
|
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
|
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
|
-
|
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,
|
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
|
-
|
46
|
+
// combine shutdown signal and reservation expiry signal
|
47
|
+
const signals = [abortSignal, reservation.signal]
|
44
48
|
|
45
|
-
if (limit?.duration != null) {
|
46
|
-
|
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
|
-
|
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
|
-
|
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())))
|
package/dist/typedoc-urls.json
DELETED
@@ -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
|
-
}
|