@libp2p/circuit-relay-v2 1.0.24-7aec7bd45 → 1.0.24-bc6556f96
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.min.js +5 -5
- package/dist/src/constants.d.ts +13 -12
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +13 -12
- package/dist/src/constants.js.map +1 -1
- package/dist/src/pb/index.d.ts +7 -7
- package/dist/src/pb/index.d.ts.map +1 -1
- package/dist/src/pb/index.js +94 -52
- package/dist/src/pb/index.js.map +1 -1
- package/dist/src/server/index.d.ts +1 -7
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +10 -19
- package/dist/src/server/index.js.map +1 -1
- package/dist/src/transport/discovery.d.ts +15 -10
- package/dist/src/transport/discovery.d.ts.map +1 -1
- package/dist/src/transport/discovery.js +103 -51
- package/dist/src/transport/discovery.js.map +1 -1
- package/dist/src/transport/index.d.ts +27 -18
- package/dist/src/transport/index.d.ts.map +1 -1
- package/dist/src/transport/index.js +0 -3
- package/dist/src/transport/index.js.map +1 -1
- package/dist/src/transport/reservation-store.d.ts +7 -3
- package/dist/src/transport/reservation-store.d.ts.map +1 -1
- package/dist/src/transport/reservation-store.js +37 -13
- package/dist/src/transport/reservation-store.js.map +1 -1
- package/dist/src/transport/transport.d.ts +0 -1
- package/dist/src/transport/transport.d.ts.map +1 -1
- package/dist/src/transport/transport.js +20 -19
- package/dist/src/transport/transport.js.map +1 -1
- package/package.json +12 -13
- package/src/constants.ts +16 -15
- package/src/pb/index.ts +96 -53
- package/src/server/index.ts +11 -29
- package/src/transport/discovery.ts +121 -56
- package/src/transport/index.ts +28 -18
- package/src/transport/reservation-store.ts +45 -13
- package/src/transport/transport.ts +21 -21
- package/dist/src/server/advert-service.d.ts +0 -44
- package/dist/src/server/advert-service.d.ts.map +0 -1
- package/dist/src/server/advert-service.js +0 -72
- package/dist/src/server/advert-service.js.map +0 -1
- package/src/server/advert-service.ts +0 -107
package/src/pb/index.ts
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
/* eslint-disable @typescript-eslint/no-unnecessary-boolean-literal-compare */
|
5
5
|
/* eslint-disable @typescript-eslint/no-empty-interface */
|
6
6
|
|
7
|
-
import {
|
8
|
-
import
|
7
|
+
import { type Codec, CodeError, decodeMessage, type DecodeOptions, encodeMessage, enumeration, message } from 'protons-runtime'
|
8
|
+
import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc'
|
9
9
|
import type { Uint8ArrayList } from 'uint8arraylist'
|
10
10
|
|
11
11
|
export interface HopMessage {
|
@@ -72,7 +72,7 @@ export namespace HopMessage {
|
|
72
72
|
if (opts.lengthDelimited !== false) {
|
73
73
|
w.ldelim()
|
74
74
|
}
|
75
|
-
}, (reader, length) => {
|
75
|
+
}, (reader, length, opts = {}) => {
|
76
76
|
const obj: any = {}
|
77
77
|
|
78
78
|
const end = length == null ? reader.len : reader.pos + length
|
@@ -81,24 +81,36 @@ export namespace HopMessage {
|
|
81
81
|
const tag = reader.uint32()
|
82
82
|
|
83
83
|
switch (tag >>> 3) {
|
84
|
-
case 1:
|
84
|
+
case 1: {
|
85
85
|
obj.type = HopMessage.Type.codec().decode(reader)
|
86
86
|
break
|
87
|
-
|
88
|
-
|
87
|
+
}
|
88
|
+
case 2: {
|
89
|
+
obj.peer = Peer.codec().decode(reader, reader.uint32(), {
|
90
|
+
limits: opts.limits?.peer
|
91
|
+
})
|
89
92
|
break
|
90
|
-
|
91
|
-
|
93
|
+
}
|
94
|
+
case 3: {
|
95
|
+
obj.reservation = Reservation.codec().decode(reader, reader.uint32(), {
|
96
|
+
limits: opts.limits?.reservation
|
97
|
+
})
|
92
98
|
break
|
93
|
-
|
94
|
-
|
99
|
+
}
|
100
|
+
case 4: {
|
101
|
+
obj.limit = Limit.codec().decode(reader, reader.uint32(), {
|
102
|
+
limits: opts.limits?.limit
|
103
|
+
})
|
95
104
|
break
|
96
|
-
|
105
|
+
}
|
106
|
+
case 5: {
|
97
107
|
obj.status = Status.codec().decode(reader)
|
98
108
|
break
|
99
|
-
|
109
|
+
}
|
110
|
+
default: {
|
100
111
|
reader.skipType(tag & 7)
|
101
112
|
break
|
113
|
+
}
|
102
114
|
}
|
103
115
|
}
|
104
116
|
|
@@ -113,8 +125,8 @@ export namespace HopMessage {
|
|
113
125
|
return encodeMessage(obj, HopMessage.codec())
|
114
126
|
}
|
115
127
|
|
116
|
-
export const decode = (buf: Uint8Array | Uint8ArrayList): HopMessage => {
|
117
|
-
return decodeMessage(buf, HopMessage.codec())
|
128
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<HopMessage>): HopMessage => {
|
129
|
+
return decodeMessage(buf, HopMessage.codec(), opts)
|
118
130
|
}
|
119
131
|
}
|
120
132
|
|
@@ -174,7 +186,7 @@ export namespace StopMessage {
|
|
174
186
|
if (opts.lengthDelimited !== false) {
|
175
187
|
w.ldelim()
|
176
188
|
}
|
177
|
-
}, (reader, length) => {
|
189
|
+
}, (reader, length, opts = {}) => {
|
178
190
|
const obj: any = {}
|
179
191
|
|
180
192
|
const end = length == null ? reader.len : reader.pos + length
|
@@ -183,21 +195,30 @@ export namespace StopMessage {
|
|
183
195
|
const tag = reader.uint32()
|
184
196
|
|
185
197
|
switch (tag >>> 3) {
|
186
|
-
case 1:
|
198
|
+
case 1: {
|
187
199
|
obj.type = StopMessage.Type.codec().decode(reader)
|
188
200
|
break
|
189
|
-
|
190
|
-
|
201
|
+
}
|
202
|
+
case 2: {
|
203
|
+
obj.peer = Peer.codec().decode(reader, reader.uint32(), {
|
204
|
+
limits: opts.limits?.peer
|
205
|
+
})
|
191
206
|
break
|
192
|
-
|
193
|
-
|
207
|
+
}
|
208
|
+
case 3: {
|
209
|
+
obj.limit = Limit.codec().decode(reader, reader.uint32(), {
|
210
|
+
limits: opts.limits?.limit
|
211
|
+
})
|
194
212
|
break
|
195
|
-
|
213
|
+
}
|
214
|
+
case 4: {
|
196
215
|
obj.status = Status.codec().decode(reader)
|
197
216
|
break
|
198
|
-
|
217
|
+
}
|
218
|
+
default: {
|
199
219
|
reader.skipType(tag & 7)
|
200
220
|
break
|
221
|
+
}
|
201
222
|
}
|
202
223
|
}
|
203
224
|
|
@@ -212,8 +233,8 @@ export namespace StopMessage {
|
|
212
233
|
return encodeMessage(obj, StopMessage.codec())
|
213
234
|
}
|
214
235
|
|
215
|
-
export const decode = (buf: Uint8Array | Uint8ArrayList): StopMessage => {
|
216
|
-
return decodeMessage(buf, StopMessage.codec())
|
236
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<StopMessage>): StopMessage => {
|
237
|
+
return decodeMessage(buf, StopMessage.codec(), opts)
|
217
238
|
}
|
218
239
|
}
|
219
240
|
|
@@ -247,9 +268,9 @@ export namespace Peer {
|
|
247
268
|
if (opts.lengthDelimited !== false) {
|
248
269
|
w.ldelim()
|
249
270
|
}
|
250
|
-
}, (reader, length) => {
|
271
|
+
}, (reader, length, opts = {}) => {
|
251
272
|
const obj: any = {
|
252
|
-
id:
|
273
|
+
id: uint8ArrayAlloc(0),
|
253
274
|
addrs: []
|
254
275
|
}
|
255
276
|
|
@@ -259,15 +280,22 @@ export namespace Peer {
|
|
259
280
|
const tag = reader.uint32()
|
260
281
|
|
261
282
|
switch (tag >>> 3) {
|
262
|
-
case 1:
|
283
|
+
case 1: {
|
263
284
|
obj.id = reader.bytes()
|
264
285
|
break
|
265
|
-
|
286
|
+
}
|
287
|
+
case 2: {
|
288
|
+
if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) {
|
289
|
+
throw new CodeError('decode error - map field "addrs" had too many elements', 'ERR_MAX_LENGTH')
|
290
|
+
}
|
291
|
+
|
266
292
|
obj.addrs.push(reader.bytes())
|
267
293
|
break
|
268
|
-
|
294
|
+
}
|
295
|
+
default: {
|
269
296
|
reader.skipType(tag & 7)
|
270
297
|
break
|
298
|
+
}
|
271
299
|
}
|
272
300
|
}
|
273
301
|
|
@@ -282,8 +310,8 @@ export namespace Peer {
|
|
282
310
|
return encodeMessage(obj, Peer.codec())
|
283
311
|
}
|
284
312
|
|
285
|
-
export const decode = (buf: Uint8Array | Uint8ArrayList): Peer => {
|
286
|
-
return decodeMessage(buf, Peer.codec())
|
313
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<Peer>): Peer => {
|
314
|
+
return decodeMessage(buf, Peer.codec(), opts)
|
287
315
|
}
|
288
316
|
}
|
289
317
|
|
@@ -323,7 +351,7 @@ export namespace Reservation {
|
|
323
351
|
if (opts.lengthDelimited !== false) {
|
324
352
|
w.ldelim()
|
325
353
|
}
|
326
|
-
}, (reader, length) => {
|
354
|
+
}, (reader, length, opts = {}) => {
|
327
355
|
const obj: any = {
|
328
356
|
expire: 0n,
|
329
357
|
addrs: []
|
@@ -335,18 +363,26 @@ export namespace Reservation {
|
|
335
363
|
const tag = reader.uint32()
|
336
364
|
|
337
365
|
switch (tag >>> 3) {
|
338
|
-
case 1:
|
366
|
+
case 1: {
|
339
367
|
obj.expire = reader.uint64()
|
340
368
|
break
|
341
|
-
|
369
|
+
}
|
370
|
+
case 2: {
|
371
|
+
if (opts.limits?.addrs != null && obj.addrs.length === opts.limits.addrs) {
|
372
|
+
throw new CodeError('decode error - map field "addrs" had too many elements', 'ERR_MAX_LENGTH')
|
373
|
+
}
|
374
|
+
|
342
375
|
obj.addrs.push(reader.bytes())
|
343
376
|
break
|
344
|
-
|
377
|
+
}
|
378
|
+
case 3: {
|
345
379
|
obj.voucher = reader.bytes()
|
346
380
|
break
|
347
|
-
|
381
|
+
}
|
382
|
+
default: {
|
348
383
|
reader.skipType(tag & 7)
|
349
384
|
break
|
385
|
+
}
|
350
386
|
}
|
351
387
|
}
|
352
388
|
|
@@ -361,8 +397,8 @@ export namespace Reservation {
|
|
361
397
|
return encodeMessage(obj, Reservation.codec())
|
362
398
|
}
|
363
399
|
|
364
|
-
export const decode = (buf: Uint8Array | Uint8ArrayList): Reservation => {
|
365
|
-
return decodeMessage(buf, Reservation.codec())
|
400
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<Reservation>): Reservation => {
|
401
|
+
return decodeMessage(buf, Reservation.codec(), opts)
|
366
402
|
}
|
367
403
|
}
|
368
404
|
|
@@ -394,7 +430,7 @@ export namespace Limit {
|
|
394
430
|
if (opts.lengthDelimited !== false) {
|
395
431
|
w.ldelim()
|
396
432
|
}
|
397
|
-
}, (reader, length) => {
|
433
|
+
}, (reader, length, opts = {}) => {
|
398
434
|
const obj: any = {}
|
399
435
|
|
400
436
|
const end = length == null ? reader.len : reader.pos + length
|
@@ -403,15 +439,18 @@ export namespace Limit {
|
|
403
439
|
const tag = reader.uint32()
|
404
440
|
|
405
441
|
switch (tag >>> 3) {
|
406
|
-
case 1:
|
442
|
+
case 1: {
|
407
443
|
obj.duration = reader.uint32()
|
408
444
|
break
|
409
|
-
|
445
|
+
}
|
446
|
+
case 2: {
|
410
447
|
obj.data = reader.uint64()
|
411
448
|
break
|
412
|
-
|
449
|
+
}
|
450
|
+
default: {
|
413
451
|
reader.skipType(tag & 7)
|
414
452
|
break
|
453
|
+
}
|
415
454
|
}
|
416
455
|
}
|
417
456
|
|
@@ -426,8 +465,8 @@ export namespace Limit {
|
|
426
465
|
return encodeMessage(obj, Limit.codec())
|
427
466
|
}
|
428
467
|
|
429
|
-
export const decode = (buf: Uint8Array | Uint8ArrayList): Limit => {
|
430
|
-
return decodeMessage(buf, Limit.codec())
|
468
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<Limit>): Limit => {
|
469
|
+
return decodeMessage(buf, Limit.codec(), opts)
|
431
470
|
}
|
432
471
|
}
|
433
472
|
|
@@ -494,10 +533,10 @@ export namespace ReservationVoucher {
|
|
494
533
|
if (opts.lengthDelimited !== false) {
|
495
534
|
w.ldelim()
|
496
535
|
}
|
497
|
-
}, (reader, length) => {
|
536
|
+
}, (reader, length, opts = {}) => {
|
498
537
|
const obj: any = {
|
499
|
-
relay:
|
500
|
-
peer:
|
538
|
+
relay: uint8ArrayAlloc(0),
|
539
|
+
peer: uint8ArrayAlloc(0),
|
501
540
|
expiration: 0n
|
502
541
|
}
|
503
542
|
|
@@ -507,18 +546,22 @@ export namespace ReservationVoucher {
|
|
507
546
|
const tag = reader.uint32()
|
508
547
|
|
509
548
|
switch (tag >>> 3) {
|
510
|
-
case 1:
|
549
|
+
case 1: {
|
511
550
|
obj.relay = reader.bytes()
|
512
551
|
break
|
513
|
-
|
552
|
+
}
|
553
|
+
case 2: {
|
514
554
|
obj.peer = reader.bytes()
|
515
555
|
break
|
516
|
-
|
556
|
+
}
|
557
|
+
case 3: {
|
517
558
|
obj.expiration = reader.uint64()
|
518
559
|
break
|
519
|
-
|
560
|
+
}
|
561
|
+
default: {
|
520
562
|
reader.skipType(tag & 7)
|
521
563
|
break
|
564
|
+
}
|
522
565
|
}
|
523
566
|
}
|
524
567
|
|
@@ -533,7 +576,7 @@ export namespace ReservationVoucher {
|
|
533
576
|
return encodeMessage(obj, ReservationVoucher.codec())
|
534
577
|
}
|
535
578
|
|
536
|
-
export const decode = (buf: Uint8Array | Uint8ArrayList): ReservationVoucher => {
|
537
|
-
return decodeMessage(buf, ReservationVoucher.codec())
|
579
|
+
export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions<ReservationVoucher>): ReservationVoucher => {
|
580
|
+
return decodeMessage(buf, ReservationVoucher.codec(), opts)
|
538
581
|
}
|
539
582
|
}
|
package/src/server/index.ts
CHANGED
@@ -14,7 +14,6 @@ import {
|
|
14
14
|
} from '../constants.js'
|
15
15
|
import { HopMessage, type Reservation, Status, StopMessage } from '../pb/index.js'
|
16
16
|
import { createLimitedRelay } from '../utils.js'
|
17
|
-
import { AdvertService, type AdvertServiceComponents, type AdvertServiceInit } from './advert-service.js'
|
18
17
|
import { ReservationStore, type ReservationStoreInit } from './reservation-store.js'
|
19
18
|
import { ReservationVoucherRecord } from './reservation-voucher.js'
|
20
19
|
import type { CircuitRelayService, RelayReservation } from '../index.js'
|
@@ -31,12 +30,6 @@ export interface CircuitRelayServerInit {
|
|
31
30
|
*/
|
32
31
|
hopTimeout?: number
|
33
32
|
|
34
|
-
/**
|
35
|
-
* If true, advertise this service via libp2p content routing to allow
|
36
|
-
* peers to locate us on the network (default: false)
|
37
|
-
*/
|
38
|
-
advertise?: boolean | AdvertServiceInit
|
39
|
-
|
40
33
|
/**
|
41
34
|
* Configuration of reservations
|
42
35
|
*/
|
@@ -70,7 +63,7 @@ export interface StopOptions {
|
|
70
63
|
request: StopMessage
|
71
64
|
}
|
72
65
|
|
73
|
-
export interface CircuitRelayServerComponents
|
66
|
+
export interface CircuitRelayServerComponents {
|
74
67
|
registrar: Registrar
|
75
68
|
peerStore: PeerStore
|
76
69
|
addressManager: AddressManager
|
@@ -98,7 +91,6 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
98
91
|
private readonly connectionManager: ConnectionManager
|
99
92
|
private readonly connectionGater: ConnectionGater
|
100
93
|
private readonly reservationStore: ReservationStore
|
101
|
-
private readonly advertService: AdvertService | undefined
|
102
94
|
private started: boolean
|
103
95
|
private readonly hopTimeout: number
|
104
96
|
private readonly shutdownController: AbortController
|
@@ -122,24 +114,13 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
122
114
|
this.connectionGater = components.connectionGater
|
123
115
|
this.started = false
|
124
116
|
this.hopTimeout = init?.hopTimeout ?? DEFAULT_HOP_TIMEOUT
|
125
|
-
this.shutdownController = new AbortController()
|
126
117
|
this.maxInboundHopStreams = init.maxInboundHopStreams
|
127
118
|
this.maxOutboundHopStreams = init.maxOutboundHopStreams
|
128
119
|
this.maxOutboundStopStreams = init.maxOutboundStopStreams ?? defaults.maxOutboundStopStreams
|
120
|
+
this.reservationStore = new ReservationStore(init.reservations)
|
129
121
|
|
122
|
+
this.shutdownController = new AbortController()
|
130
123
|
setMaxListeners(Infinity, this.shutdownController.signal)
|
131
|
-
|
132
|
-
if (init.advertise != null && init.advertise !== false) {
|
133
|
-
this.advertService = new AdvertService(components, init.advertise === true ? undefined : init.advertise)
|
134
|
-
this.advertService.addEventListener('advert:success', () => {
|
135
|
-
this.safeDispatchEvent('relay:advert:success', {})
|
136
|
-
})
|
137
|
-
this.advertService.addEventListener('advert:error', (evt) => {
|
138
|
-
this.safeDispatchEvent('relay:advert:error', { detail: evt.detail })
|
139
|
-
})
|
140
|
-
}
|
141
|
-
|
142
|
-
this.reservationStore = new ReservationStore(init.reservations)
|
143
124
|
}
|
144
125
|
|
145
126
|
isStarted (): boolean {
|
@@ -154,9 +135,6 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
154
135
|
return
|
155
136
|
}
|
156
137
|
|
157
|
-
// Advertise service if HOP enabled and advertising enabled
|
158
|
-
this.advertService?.start()
|
159
|
-
|
160
138
|
await this.registrar.handle(RELAY_V2_HOP_CODEC, (data) => {
|
161
139
|
void this.onHop(data).catch(err => {
|
162
140
|
this.log.error(err)
|
@@ -176,7 +154,6 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
176
154
|
* Stop Relay service
|
177
155
|
*/
|
178
156
|
async stop (): Promise<void> {
|
179
|
-
this.advertService?.stop()
|
180
157
|
this.reservationStore.stop()
|
181
158
|
this.shutdownController.abort()
|
182
159
|
await this.registrar.unhandle(RELAY_V2_HOP_CODEC)
|
@@ -359,6 +336,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
359
336
|
return
|
360
337
|
}
|
361
338
|
|
339
|
+
const limit = this.reservationStore.get(dstPeer)?.limit
|
362
340
|
const destinationConnection = connections[0]
|
363
341
|
|
364
342
|
const destinationStream = await this.stopHop({
|
@@ -368,7 +346,8 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
368
346
|
peer: {
|
369
347
|
id: connection.remotePeer.toBytes(),
|
370
348
|
addrs: []
|
371
|
-
}
|
349
|
+
},
|
350
|
+
limit
|
372
351
|
}
|
373
352
|
})
|
374
353
|
|
@@ -378,11 +357,14 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
378
357
|
return
|
379
358
|
}
|
380
359
|
|
381
|
-
await hopstr.write({
|
360
|
+
await hopstr.write({
|
361
|
+
type: HopMessage.Type.STATUS,
|
362
|
+
status: Status.OK,
|
363
|
+
limit
|
364
|
+
})
|
382
365
|
const sourceStream = stream.unwrap()
|
383
366
|
|
384
367
|
this.log('connection from %p to %p established - merging streams', connection.remotePeer, dstPeer)
|
385
|
-
const limit = this.reservationStore.get(dstPeer)?.limit
|
386
368
|
// Short circuit the two streams to create the relayed connection
|
387
369
|
createLimitedRelay(sourceStream, destinationStream, this.shutdownController.signal, limit, {
|
388
370
|
log: this.log
|
@@ -1,24 +1,28 @@
|
|
1
|
-
import { TypedEventEmitter } from '@libp2p/interface'
|
1
|
+
import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
2
|
+
import { PeerQueue } from '@libp2p/utils/peer-queue'
|
3
|
+
import { anySignal } from 'any-signal'
|
4
|
+
import { raceSignal } from 'race-signal'
|
2
5
|
import {
|
3
|
-
RELAY_RENDEZVOUS_NS,
|
4
6
|
RELAY_V2_HOP_CODEC
|
5
7
|
} from '../constants.js'
|
6
|
-
import {
|
7
|
-
import type {
|
8
|
-
import type { ConnectionManager, Registrar, TransportManager } from '@libp2p/interface-internal'
|
8
|
+
import type { ComponentLogger, Logger, PeerId, PeerStore, Startable, TopologyFilter } from '@libp2p/interface'
|
9
|
+
import type { ConnectionManager, RandomWalk, Registrar, TransportManager } from '@libp2p/interface-internal'
|
9
10
|
|
10
11
|
export interface RelayDiscoveryEvents {
|
11
12
|
'relay:discover': CustomEvent<PeerId>
|
12
13
|
}
|
13
14
|
|
14
15
|
export interface RelayDiscoveryComponents {
|
15
|
-
peerId: PeerId
|
16
16
|
peerStore: PeerStore
|
17
17
|
connectionManager: ConnectionManager
|
18
18
|
transportManager: TransportManager
|
19
|
-
contentRouting: ContentRouting
|
20
19
|
registrar: Registrar
|
21
20
|
logger: ComponentLogger
|
21
|
+
randomWalk: RandomWalk
|
22
|
+
}
|
23
|
+
|
24
|
+
export interface RelayDiscoveryInit {
|
25
|
+
filter?: TopologyFilter
|
22
26
|
}
|
23
27
|
|
24
28
|
/**
|
@@ -26,23 +30,30 @@ export interface RelayDiscoveryComponents {
|
|
26
30
|
* peers that support the circuit v2 HOP protocol.
|
27
31
|
*/
|
28
32
|
export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> implements Startable {
|
29
|
-
private readonly peerId: PeerId
|
30
33
|
private readonly peerStore: PeerStore
|
31
|
-
private readonly contentRouting: ContentRouting
|
32
34
|
private readonly registrar: Registrar
|
35
|
+
private readonly connectionManager: ConnectionManager
|
36
|
+
private readonly randomWalk: RandomWalk
|
33
37
|
private started: boolean
|
38
|
+
private running: boolean
|
34
39
|
private topologyId?: string
|
35
40
|
private readonly log: Logger
|
41
|
+
private discoveryController: AbortController
|
42
|
+
private readonly filter?: TopologyFilter
|
36
43
|
|
37
|
-
constructor (components: RelayDiscoveryComponents) {
|
44
|
+
constructor (components: RelayDiscoveryComponents, init: RelayDiscoveryInit = {}) {
|
38
45
|
super()
|
39
46
|
|
40
47
|
this.log = components.logger.forComponent('libp2p:circuit-relay:discover-relays')
|
41
48
|
this.started = false
|
42
|
-
this.
|
49
|
+
this.running = false
|
43
50
|
this.peerStore = components.peerStore
|
44
|
-
this.contentRouting = components.contentRouting
|
45
51
|
this.registrar = components.registrar
|
52
|
+
this.connectionManager = components.connectionManager
|
53
|
+
this.randomWalk = components.randomWalk
|
54
|
+
this.filter = init.filter
|
55
|
+
this.discoveryController = new AbortController()
|
56
|
+
setMaxListeners(Infinity, this.discoveryController.signal)
|
46
57
|
}
|
47
58
|
|
48
59
|
isStarted (): boolean {
|
@@ -53,8 +64,9 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
53
64
|
// register a topology listener for when new peers are encountered
|
54
65
|
// that support the hop protocol
|
55
66
|
this.topologyId = await this.registrar.register(RELAY_V2_HOP_CODEC, {
|
56
|
-
|
67
|
+
filter: this.filter,
|
57
68
|
onConnect: (peerId) => {
|
69
|
+
this.log('discovered relay %p', peerId)
|
58
70
|
this.safeDispatchEvent('relay:discover', { detail: peerId })
|
59
71
|
}
|
60
72
|
})
|
@@ -62,18 +74,12 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
62
74
|
this.started = true
|
63
75
|
}
|
64
76
|
|
65
|
-
afterStart (): void {
|
66
|
-
void this.discover()
|
67
|
-
.catch(err => {
|
68
|
-
this.log.error('error discovering relays', err)
|
69
|
-
})
|
70
|
-
}
|
71
|
-
|
72
77
|
stop (): void {
|
73
78
|
if (this.topologyId != null) {
|
74
79
|
this.registrar.unregister(this.topologyId)
|
75
80
|
}
|
76
81
|
|
82
|
+
this.discoveryController?.abort()
|
77
83
|
this.started = false
|
78
84
|
}
|
79
85
|
|
@@ -81,54 +87,113 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
81
87
|
* Try to listen on available hop relay connections.
|
82
88
|
* The following order will happen while we do not have enough relays:
|
83
89
|
*
|
84
|
-
* 1. Check the metadata store for known relays, try to listen on the ones we are already connected
|
90
|
+
* 1. Check the metadata store for known relays, try to listen on the ones we are already connected to
|
85
91
|
* 2. Dial and try to listen on the peers we know that support hop but are not connected
|
86
92
|
* 3. Search the network
|
87
93
|
*/
|
88
|
-
|
89
|
-
this.
|
90
|
-
|
91
|
-
filters: [
|
92
|
-
// filter by a list of peers supporting RELAY_V2_HOP and ones we are not listening on
|
93
|
-
(peer) => {
|
94
|
-
return peer.protocols.includes(RELAY_V2_HOP_CODEC)
|
95
|
-
}
|
96
|
-
],
|
97
|
-
orders: [
|
98
|
-
() => Math.random() < 0.5 ? 1 : -1
|
99
|
-
]
|
100
|
-
}))
|
101
|
-
|
102
|
-
for (const peer of peers) {
|
103
|
-
this.log('found relay peer %p in content peer store', peer.id)
|
104
|
-
this.safeDispatchEvent('relay:discover', { detail: peer.id })
|
94
|
+
startDiscovery (): void {
|
95
|
+
if (this.running) {
|
96
|
+
return
|
105
97
|
}
|
106
98
|
|
107
|
-
this.log('
|
99
|
+
this.log('start discovery')
|
100
|
+
this.running = true
|
101
|
+
this.discoveryController = new AbortController()
|
102
|
+
setMaxListeners(Infinity, this.discoveryController.signal)
|
103
|
+
|
104
|
+
Promise.resolve()
|
105
|
+
.then(async () => {
|
106
|
+
this.log('searching peer store for relays')
|
107
|
+
|
108
|
+
const peers = (await this.peerStore.all({
|
109
|
+
filters: [
|
110
|
+
// filter by a list of peers supporting RELAY_V2_HOP and ones we are not listening on
|
111
|
+
(peer) => {
|
112
|
+
return peer.protocols.includes(RELAY_V2_HOP_CODEC)
|
113
|
+
}
|
114
|
+
],
|
115
|
+
orders: [
|
116
|
+
() => Math.random() < 0.5 ? 1 : -1
|
117
|
+
]
|
118
|
+
}))
|
119
|
+
|
120
|
+
for (const peer of peers) {
|
121
|
+
this.log.trace('found relay peer %p in peer store', peer.id)
|
122
|
+
this.safeDispatchEvent('relay:discover', { detail: peer.id })
|
123
|
+
}
|
124
|
+
|
125
|
+
this.log('found %d relay peers in peer store', peers.length)
|
126
|
+
|
127
|
+
// perform random walk and dial peers - after identify has run, the network
|
128
|
+
// topology will be notified of new relays
|
129
|
+
const queue = new PeerQueue({
|
130
|
+
concurrency: 5
|
131
|
+
})
|
132
|
+
|
133
|
+
this.log('start random walk')
|
134
|
+
for await (const peer of this.randomWalk.walk({ signal: this.discoveryController.signal })) {
|
135
|
+
this.log.trace('found random peer %p', peer.id)
|
136
|
+
|
137
|
+
if (queue.has(peer.id)) {
|
138
|
+
this.log.trace('random peer %p was already in queue', peer.id)
|
139
|
+
|
140
|
+
// skip peers already in the queue
|
141
|
+
continue
|
142
|
+
}
|
108
143
|
|
109
|
-
|
110
|
-
|
111
|
-
const cid = await namespaceToCid(RELAY_RENDEZVOUS_NS)
|
144
|
+
if (this.connectionManager.getConnections(peer.id)?.length > 0) {
|
145
|
+
this.log.trace('random peer %p was already connected', peer.id)
|
112
146
|
|
113
|
-
|
147
|
+
// skip peers we are already connected to
|
148
|
+
continue
|
149
|
+
}
|
114
150
|
|
115
|
-
|
116
|
-
|
117
|
-
const peerId = provider.id
|
151
|
+
if (!(await this.connectionManager.isDialable(peer.multiaddrs))) {
|
152
|
+
this.log.trace('random peer %p was not dialable', peer.id, peer.multiaddrs.map(ma => ma.toString()))
|
118
153
|
|
119
|
-
|
120
|
-
|
121
|
-
|
154
|
+
// skip peers we can't dial
|
155
|
+
continue
|
156
|
+
}
|
157
|
+
|
158
|
+
this.log.trace('wait for space in queue for %p', peer.id)
|
159
|
+
|
160
|
+
// pause the random walk until there is space in the queue
|
161
|
+
await raceSignal(queue.onSizeLessThan(10), this.discoveryController.signal)
|
162
|
+
|
163
|
+
this.log('adding random peer %p to dial queue (length: %d)', peer.id, queue.size)
|
164
|
+
|
165
|
+
// dial the peer - this will cause identify to run and our topology to
|
166
|
+
// be notified and we'll attempt to create reservations
|
167
|
+
queue.add(async () => {
|
168
|
+
const signal = anySignal([this.discoveryController.signal, AbortSignal.timeout(5000)])
|
169
|
+
setMaxListeners(Infinity, signal)
|
170
|
+
|
171
|
+
try {
|
172
|
+
await this.connectionManager.openConnection(peer.id, { signal })
|
173
|
+
} finally {
|
174
|
+
signal.clear()
|
175
|
+
}
|
176
|
+
}, {
|
177
|
+
peerId: peer.id,
|
178
|
+
signal: this.discoveryController.signal
|
122
179
|
})
|
180
|
+
.catch(err => {
|
181
|
+
this.log.error('error opening connection to random peer %p', peer.id, err)
|
182
|
+
})
|
183
|
+
}
|
123
184
|
|
124
|
-
|
125
|
-
|
185
|
+
await queue.onIdle()
|
186
|
+
})
|
187
|
+
.catch(err => {
|
188
|
+
if (!this.discoveryController.signal.aborted) {
|
189
|
+
this.log.error('failed when finding relays on the network', err)
|
126
190
|
}
|
127
|
-
}
|
191
|
+
})
|
192
|
+
}
|
128
193
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
194
|
+
stopDiscovery (): void {
|
195
|
+
this.log('stop discovery')
|
196
|
+
this.running = false
|
197
|
+
this.discoveryController?.abort()
|
133
198
|
}
|
134
199
|
}
|