@libp2p/circuit-relay-v2 2.1.4 → 2.1.5-3bc9769b8
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 +4 -4
- package/dist/src/constants.d.ts +0 -5
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +0 -5
- package/dist/src/constants.js.map +1 -1
- package/dist/src/errors.d.ts +22 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +22 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +16 -1
- 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 +19 -10
- 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.d.ts +1 -0
- package/dist/src/transport/discovery.d.ts.map +1 -1
- package/dist/src/transport/discovery.js +38 -8
- package/dist/src/transport/discovery.js.map +1 -1
- package/dist/src/transport/index.d.ts +0 -6
- package/dist/src/transport/index.d.ts.map +1 -1
- package/dist/src/transport/index.js.map +1 -1
- package/dist/src/transport/listener.d.ts +3 -0
- package/dist/src/transport/listener.d.ts.map +1 -1
- package/dist/src/transport/listener.js +57 -27
- package/dist/src/transport/listener.js.map +1 -1
- package/dist/src/transport/reservation-store.d.ts +37 -14
- package/dist/src/transport/reservation-store.d.ts.map +1 -1
- package/dist/src/transport/reservation-store.js +144 -74
- package/dist/src/transport/reservation-store.js.map +1 -1
- package/dist/src/transport/transport.d.ts +2 -13
- package/dist/src/transport/transport.d.ts.map +1 -1
- package/dist/src/transport/transport.js +30 -54
- package/dist/src/transport/transport.js.map +1 -1
- package/dist/src/utils.d.ts +10 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +22 -8
- package/dist/src/utils.js.map +1 -1
- package/package.json +14 -12
- package/src/constants.ts +0 -7
- package/src/errors.ts +25 -0
- package/src/index.ts +19 -1
- package/src/pb/index.proto +20 -1
- package/src/pb/index.ts +99 -3
- package/src/server/index.ts +21 -11
- package/src/server/reservation-store.ts +38 -42
- package/src/server/reservation-voucher.ts +2 -2
- package/src/transport/discovery.ts +47 -9
- package/src/transport/index.ts +0 -7
- package/src/transport/listener.ts +75 -35
- package/src/transport/reservation-store.ts +209 -95
- package/src/transport/transport.ts +34 -76
- package/src/utils.ts +29 -8
- package/dist/typedoc-urls.json +0 -23
@@ -1,15 +1,18 @@
|
|
1
|
-
import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
1
|
+
import { ListenError, TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
2
2
|
import { PeerMap } from '@libp2p/peer-collections'
|
3
|
-
import {
|
3
|
+
import { createScalableCuckooFilter } from '@libp2p/utils/filters'
|
4
4
|
import { PeerQueue } from '@libp2p/utils/peer-queue'
|
5
5
|
import { multiaddr } from '@multiformats/multiaddr'
|
6
|
+
import { Circuit } from '@multiformats/multiaddr-matcher'
|
6
7
|
import { pbStream } from 'it-protobuf-stream'
|
7
|
-
import {
|
8
|
+
import { nanoid } from 'nanoid'
|
9
|
+
import { DEFAULT_MAX_RESERVATION_QUEUE_LENGTH, DEFAULT_RESERVATION_COMPLETION_TIMEOUT, DEFAULT_RESERVATION_CONCURRENCY, KEEP_ALIVE_TAG, RELAY_V2_HOP_CODEC } from '../constants.js'
|
10
|
+
import { DoubleRelayError, HadEnoughRelaysError, RelayQueueFullError } from '../errors.js'
|
8
11
|
import { HopMessage, Status } from '../pb/index.js'
|
9
12
|
import { getExpirationMilliseconds } from '../utils.js'
|
10
13
|
import type { Reservation } from '../pb/index.js'
|
11
|
-
import type { TypedEventTarget, Libp2pEvents,
|
12
|
-
import type { ConnectionManager
|
14
|
+
import type { AbortOptions, TypedEventTarget, Libp2pEvents, ComponentLogger, Logger, PeerId, PeerStore, Startable, Metrics, Peer, Connection } from '@libp2p/interface'
|
15
|
+
import type { ConnectionManager } from '@libp2p/interface-internal'
|
13
16
|
import type { Filter } from '@libp2p/utils/filters'
|
14
17
|
|
15
18
|
// allow refreshing a relay reservation if it will expire in the next 10 minutes
|
@@ -24,7 +27,6 @@ const REFRESH_TIMEOUT_MIN = 30 * 1000
|
|
24
27
|
export interface ReservationStoreComponents {
|
25
28
|
peerId: PeerId
|
26
29
|
connectionManager: ConnectionManager
|
27
|
-
transportManager: TransportManager
|
28
30
|
peerStore: PeerStore
|
29
31
|
events: TypedEventTarget<Libp2pEvents>
|
30
32
|
logger: ComponentLogger
|
@@ -44,11 +46,6 @@ export interface ReservationStoreInit {
|
|
44
46
|
*/
|
45
47
|
reservationConcurrency?: number
|
46
48
|
|
47
|
-
/**
|
48
|
-
* How many discovered relays to allow in the reservation store
|
49
|
-
*/
|
50
|
-
discoverRelays?: number
|
51
|
-
|
52
49
|
/**
|
53
50
|
* Limit the number of potential relays we will dial
|
54
51
|
*
|
@@ -66,37 +63,60 @@ export interface ReservationStoreInit {
|
|
66
63
|
|
67
64
|
export type RelayType = 'discovered' | 'configured'
|
68
65
|
|
69
|
-
interface
|
66
|
+
export interface DiscoveredRelayEntry {
|
70
67
|
timeout: ReturnType<typeof setTimeout>
|
71
|
-
type:
|
68
|
+
type: 'discovered'
|
72
69
|
reservation: Reservation
|
73
70
|
|
74
71
|
/**
|
75
72
|
* Stores the id of the connection we have to the relay
|
76
73
|
*/
|
77
74
|
connection: string
|
75
|
+
|
76
|
+
/**
|
77
|
+
* Stores the identifier returned when the reservation was requested
|
78
|
+
*/
|
79
|
+
id: string
|
80
|
+
}
|
81
|
+
|
82
|
+
export interface ConfiguredRelayEntry {
|
83
|
+
timeout: ReturnType<typeof setTimeout>
|
84
|
+
type: 'configured'
|
85
|
+
reservation: Reservation
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Stores the id of the connection we have to the relay
|
89
|
+
*/
|
90
|
+
connection: string
|
91
|
+
}
|
92
|
+
|
93
|
+
export type RelayEntry = DiscoveredRelayEntry | ConfiguredRelayEntry
|
94
|
+
|
95
|
+
export interface RelayReservation {
|
96
|
+
relay: PeerId
|
97
|
+
details: RelayEntry
|
78
98
|
}
|
79
99
|
|
80
100
|
export interface ReservationStoreEvents {
|
81
101
|
'relay:not-enough-relays': CustomEvent
|
82
|
-
'relay:
|
83
|
-
'relay:
|
102
|
+
'relay:found-enough-relays': CustomEvent
|
103
|
+
'relay:removed': CustomEvent<RelayReservation>
|
104
|
+
'relay:created-reservation': CustomEvent<RelayReservation>
|
84
105
|
}
|
85
106
|
|
86
107
|
export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents> implements Startable {
|
87
108
|
private readonly peerId: PeerId
|
88
109
|
private readonly connectionManager: ConnectionManager
|
89
|
-
private readonly transportManager: TransportManager
|
90
110
|
private readonly peerStore: PeerStore
|
91
111
|
private readonly events: TypedEventTarget<Libp2pEvents>
|
92
|
-
private readonly reserveQueue: PeerQueue
|
112
|
+
private readonly reserveQueue: PeerQueue<RelayReservation>
|
93
113
|
private readonly reservations: PeerMap<RelayEntry>
|
94
|
-
private readonly
|
114
|
+
private readonly pendingReservations: string[]
|
95
115
|
private readonly maxReservationQueueLength: number
|
96
116
|
private readonly reservationCompletionTimeout: number
|
97
117
|
private started: boolean
|
98
118
|
private readonly log: Logger
|
99
|
-
private
|
119
|
+
private relayFilter: Filter
|
100
120
|
|
101
121
|
constructor (components: ReservationStoreComponents, init?: ReservationStoreInit) {
|
102
122
|
super()
|
@@ -104,15 +124,14 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
104
124
|
this.log = components.logger.forComponent('libp2p:circuit-relay:transport:reservation-store')
|
105
125
|
this.peerId = components.peerId
|
106
126
|
this.connectionManager = components.connectionManager
|
107
|
-
this.transportManager = components.transportManager
|
108
127
|
this.peerStore = components.peerStore
|
109
128
|
this.events = components.events
|
110
129
|
this.reservations = new PeerMap()
|
111
|
-
this.
|
130
|
+
this.pendingReservations = []
|
112
131
|
this.maxReservationQueueLength = init?.maxReservationQueueLength ?? DEFAULT_MAX_RESERVATION_QUEUE_LENGTH
|
113
132
|
this.reservationCompletionTimeout = init?.reservationCompletionTimeout ?? DEFAULT_RESERVATION_COMPLETION_TIMEOUT
|
114
133
|
this.started = false
|
115
|
-
this.relayFilter =
|
134
|
+
this.relayFilter = createScalableCuckooFilter(100)
|
116
135
|
|
117
136
|
// ensure we don't listen on multiple relays simultaneously
|
118
137
|
this.reserveQueue = new PeerQueue({
|
@@ -132,7 +151,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
132
151
|
return
|
133
152
|
}
|
134
153
|
|
135
|
-
this.#removeReservation(evt.detail.remotePeer
|
154
|
+
this.#removeReservation(evt.detail.remotePeer)
|
136
155
|
.catch(err => {
|
137
156
|
this.log('could not remove relay %p - %e', evt.detail, err)
|
138
157
|
})
|
@@ -153,7 +172,7 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
153
172
|
.then(async () => {
|
154
173
|
const relayPeers: Peer[] = await this.peerStore.all({
|
155
174
|
filters: [(peer) => {
|
156
|
-
return peer.tags.has(
|
175
|
+
return peer.tags.has(KEEP_ALIVE_TAG)
|
157
176
|
}]
|
158
177
|
})
|
159
178
|
|
@@ -164,17 +183,18 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
164
183
|
relayPeers.map(async peer => {
|
165
184
|
await this.peerStore.merge(peer.id, {
|
166
185
|
tags: {
|
167
|
-
[RELAY_TAG]: undefined,
|
168
186
|
[KEEP_ALIVE_TAG]: undefined
|
169
187
|
}
|
170
188
|
})
|
171
189
|
})
|
172
190
|
)
|
173
191
|
|
174
|
-
|
175
|
-
|
176
|
-
this.
|
177
|
-
|
192
|
+
this.log('redialing %d old relays', relayPeers.length)
|
193
|
+
await Promise.all(
|
194
|
+
relayPeers.map(async peer => this.addRelay(peer.id, 'discovered'))
|
195
|
+
)
|
196
|
+
|
197
|
+
this.#checkReservationCount()
|
178
198
|
})
|
179
199
|
.catch(err => {
|
180
200
|
this.log.error(err)
|
@@ -190,36 +210,46 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
190
210
|
this.started = false
|
191
211
|
}
|
192
212
|
|
213
|
+
reserveRelay (): string {
|
214
|
+
const id = nanoid()
|
215
|
+
|
216
|
+
this.pendingReservations.push(id)
|
217
|
+
|
218
|
+
this.#checkReservationCount()
|
219
|
+
|
220
|
+
return id
|
221
|
+
}
|
222
|
+
|
193
223
|
/**
|
194
224
|
* If the number of current relays is beneath the configured `maxReservations`
|
195
225
|
* value, and the passed peer id is not our own, and we have a non-relayed
|
196
226
|
* connection to the remote, and the remote peer speaks the hop protocol, try
|
197
227
|
* to reserve a slot on the remote peer
|
198
228
|
*/
|
199
|
-
async addRelay (peerId: PeerId, type: RelayType): Promise<
|
229
|
+
async addRelay (peerId: PeerId, type: RelayType): Promise<RelayReservation> {
|
200
230
|
if (this.peerId.equals(peerId)) {
|
201
231
|
this.log.trace('not trying to use self as relay')
|
202
|
-
|
232
|
+
throw new ListenError('Cannot use self as relay')
|
203
233
|
}
|
204
234
|
|
205
235
|
if (this.reserveQueue.size > this.maxReservationQueueLength) {
|
206
|
-
|
207
|
-
return
|
236
|
+
throw new RelayQueueFullError('The reservation queue is full')
|
208
237
|
}
|
209
238
|
|
210
|
-
|
239
|
+
const existingJob = this.reserveQueue.find(peerId)
|
240
|
+
|
241
|
+
if (existingJob != null) {
|
211
242
|
this.log.trace('potential relay peer %p is already in the reservation queue', peerId)
|
212
|
-
return
|
243
|
+
return existingJob.join()
|
213
244
|
}
|
214
245
|
|
215
246
|
if (this.relayFilter.has(peerId.toMultihash().bytes)) {
|
216
|
-
|
217
|
-
return
|
247
|
+
throw new ListenError('The relay was previously invalid')
|
218
248
|
}
|
219
249
|
|
220
250
|
this.log.trace('try to reserve relay slot with %p', peerId)
|
221
251
|
|
222
|
-
|
252
|
+
return this.reserveQueue.add(async () => {
|
223
253
|
const start = Date.now()
|
224
254
|
|
225
255
|
try {
|
@@ -227,24 +257,31 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
227
257
|
const existingReservation = this.reservations.get(peerId)
|
228
258
|
|
229
259
|
if (existingReservation != null) {
|
230
|
-
|
231
|
-
|
232
|
-
|
260
|
+
const connections = this.connectionManager.getConnections(peerId)
|
261
|
+
let connected = false
|
262
|
+
|
263
|
+
if (connections.length === 0) {
|
264
|
+
this.log('already have relay reservation with %p but we are no longer connected', peerId)
|
233
265
|
}
|
234
266
|
|
235
|
-
|
236
|
-
|
237
|
-
|
267
|
+
if (connections.map(conn => conn.id).includes(existingReservation.connection)) {
|
268
|
+
this.log('already have relay reservation with %p and the original connection is still open', peerId)
|
269
|
+
connected = true
|
270
|
+
}
|
238
271
|
|
239
|
-
|
240
|
-
|
241
|
-
|
272
|
+
if (connected && getExpirationMilliseconds(existingReservation.reservation.expire) > REFRESH_WINDOW) {
|
273
|
+
this.log('already have relay reservation with %p but we are still connected and it does not expire soon', peerId)
|
274
|
+
return {
|
275
|
+
relay: peerId,
|
276
|
+
details: existingReservation
|
277
|
+
} satisfies RelayReservation
|
242
278
|
}
|
243
279
|
|
244
|
-
|
245
|
-
}
|
246
|
-
|
247
|
-
|
280
|
+
await this.#removeReservation(peerId)
|
281
|
+
}
|
282
|
+
|
283
|
+
if (type === 'discovered' && this.pendingReservations.length === 0) {
|
284
|
+
throw new HadEnoughRelaysError('Not making reservation on discovered relay because we do not need any more relays')
|
248
285
|
}
|
249
286
|
|
250
287
|
const signal = AbortSignal.timeout(this.reservationCompletionTimeout)
|
@@ -254,44 +291,67 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
254
291
|
signal
|
255
292
|
})
|
256
293
|
|
257
|
-
if (connection.remoteAddr
|
258
|
-
|
259
|
-
return
|
294
|
+
if (Circuit.matches(connection.remoteAddr)) {
|
295
|
+
throw new DoubleRelayError('not creating reservation over relayed connection')
|
260
296
|
}
|
261
297
|
|
262
298
|
const reservation = await this.#createReservation(connection, {
|
263
299
|
signal
|
264
300
|
})
|
265
301
|
|
266
|
-
this.log('created reservation on relay peer %p', peerId)
|
267
|
-
|
268
302
|
const expiration = getExpirationMilliseconds(reservation.expire)
|
269
303
|
|
304
|
+
this.log('created reservation on relay peer %p, expiry date is %s', peerId, new Date(Date.now() + expiration).toString())
|
305
|
+
|
270
306
|
// sets a lower bound on the timeout, and also don't let it go over
|
271
307
|
// 2^31 - 1 (setTimeout will only accept signed 32 bit integers)
|
272
308
|
const timeoutDuration = Math.min(Math.max(expiration - REFRESH_TIMEOUT, REFRESH_TIMEOUT_MIN), Math.pow(2, 31) - 1)
|
273
309
|
|
274
310
|
const timeout = setTimeout(() => {
|
275
|
-
this.
|
276
|
-
|
277
|
-
|
311
|
+
this.log('refresh reservation to relay %p', peerId)
|
312
|
+
|
313
|
+
this.addRelay(peerId, type)
|
314
|
+
.catch(async err => {
|
315
|
+
this.log.error('could not refresh reservation to relay %p - %e', peerId, err)
|
316
|
+
await this.#removeReservation(peerId)
|
317
|
+
})
|
318
|
+
.catch(err => {
|
319
|
+
this.log.error('could not remove expired reservation to relay %p - %e', peerId, err)
|
320
|
+
})
|
278
321
|
}, timeoutDuration)
|
279
322
|
|
323
|
+
let res: RelayEntry
|
324
|
+
|
325
|
+
// assign a reservation id if one was requested
|
326
|
+
if (type === 'discovered') {
|
327
|
+
const id = this.pendingReservations.pop()
|
328
|
+
|
329
|
+
if (id == null) {
|
330
|
+
throw new HadEnoughRelaysError('Made reservation on relay but did not need any more discovered relays')
|
331
|
+
}
|
332
|
+
|
333
|
+
res = {
|
334
|
+
timeout,
|
335
|
+
reservation,
|
336
|
+
type,
|
337
|
+
connection: connection.id,
|
338
|
+
id
|
339
|
+
}
|
340
|
+
} else {
|
341
|
+
res = {
|
342
|
+
timeout,
|
343
|
+
reservation,
|
344
|
+
type,
|
345
|
+
connection: connection.id
|
346
|
+
}
|
347
|
+
}
|
348
|
+
|
280
349
|
// we've managed to create a reservation successfully
|
281
|
-
this.reservations.set(peerId,
|
282
|
-
timeout,
|
283
|
-
reservation,
|
284
|
-
type,
|
285
|
-
connection: connection.id
|
286
|
-
})
|
350
|
+
this.reservations.set(peerId, res)
|
287
351
|
|
288
352
|
// ensure we don't close the connection to the relay
|
289
353
|
await this.peerStore.merge(peerId, {
|
290
354
|
tags: {
|
291
|
-
[RELAY_TAG]: {
|
292
|
-
value: 1,
|
293
|
-
ttl: expiration
|
294
|
-
},
|
295
355
|
[KEEP_ALIVE_TAG]: {
|
296
356
|
value: 1,
|
297
357
|
ttl: expiration
|
@@ -299,27 +359,37 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
299
359
|
}
|
300
360
|
})
|
301
361
|
|
302
|
-
//
|
303
|
-
|
362
|
+
// check to see if we have discovered enough relays
|
363
|
+
this.#checkReservationCount()
|
364
|
+
|
365
|
+
const result: RelayReservation = {
|
366
|
+
relay: peerId,
|
367
|
+
details: res
|
368
|
+
}
|
304
369
|
|
305
370
|
this.safeDispatchEvent('relay:created-reservation', {
|
306
|
-
detail:
|
371
|
+
detail: result
|
307
372
|
})
|
308
|
-
} catch (err) {
|
309
|
-
this.log.error('could not reserve slot on %p after %dms', peerId, Date.now() - start, err)
|
310
373
|
|
311
|
-
|
312
|
-
|
374
|
+
return result
|
375
|
+
} catch (err: any) {
|
376
|
+
if (!(type === 'discovered' && err.name === 'HadEnoughRelaysError')) {
|
377
|
+
this.log.error('could not reserve slot on %p after %dms - %e', peerId, Date.now() - start, err)
|
378
|
+
}
|
313
379
|
|
314
|
-
if
|
315
|
-
|
380
|
+
// don't try this peer again if dialing failed or they do not support
|
381
|
+
// the hop protocol
|
382
|
+
if (err.name === 'DialError' || err.name === 'UnsupportedProtocolError') {
|
383
|
+
this.relayFilter.add(peerId.toMultihash().bytes)
|
316
384
|
}
|
317
385
|
|
318
386
|
// if listening failed, remove the reservation
|
319
|
-
this
|
387
|
+
this.#removeReservation(peerId)
|
388
|
+
.catch(err => {
|
389
|
+
this.log.error('could not remove reservation on %p after reserving slot failed - %e', peerId, err)
|
390
|
+
})
|
320
391
|
|
321
|
-
|
322
|
-
this.relayFilter.add(peerId.toMultihash().bytes)
|
392
|
+
throw err
|
323
393
|
}
|
324
394
|
}, {
|
325
395
|
peerId
|
@@ -334,16 +404,26 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
334
404
|
return this.reservations.get(peerId)?.reservation
|
335
405
|
}
|
336
406
|
|
337
|
-
reservationCount (): number {
|
338
|
-
|
407
|
+
reservationCount (type?: RelayType): number {
|
408
|
+
if (type == null) {
|
409
|
+
return this.reservations.size
|
410
|
+
}
|
411
|
+
|
412
|
+
return [...this.reservations.values()].reduce((acc, curr) => {
|
413
|
+
if (curr.type === type) {
|
414
|
+
acc++
|
415
|
+
}
|
416
|
+
|
417
|
+
return acc
|
418
|
+
}, 0)
|
339
419
|
}
|
340
420
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
)
|
421
|
+
cancelReservations (): void {
|
422
|
+
[...this.reservations.values()].forEach(reservation => {
|
423
|
+
clearTimeout(reservation.timeout)
|
424
|
+
})
|
425
|
+
|
426
|
+
this.reservations.clear()
|
347
427
|
}
|
348
428
|
|
349
429
|
async #createReservation (connection: Connection, options: AbortOptions): Promise<Reservation> {
|
@@ -353,11 +433,14 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
353
433
|
const stream = await connection.newStream(RELAY_V2_HOP_CODEC, options)
|
354
434
|
const pbstr = pbStream(stream)
|
355
435
|
const hopstr = pbstr.pb(HopMessage)
|
436
|
+
|
437
|
+
this.log.trace('send RESERVE to %p', connection.remotePeer)
|
356
438
|
await hopstr.write({ type: HopMessage.Type.RESERVE }, options)
|
357
439
|
|
358
440
|
let response: HopMessage
|
359
441
|
|
360
442
|
try {
|
443
|
+
this.log.trace('read response from %p', connection.remotePeer)
|
361
444
|
response = await hopstr.read(options)
|
362
445
|
} catch (err: any) {
|
363
446
|
stream.abort(err)
|
@@ -368,6 +451,8 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
368
451
|
}
|
369
452
|
}
|
370
453
|
|
454
|
+
this.log.trace('read response from %p', response)
|
455
|
+
|
371
456
|
if (response.status === Status.OK && response.reservation != null) {
|
372
457
|
// check that the returned relay has the relay address - this can be
|
373
458
|
// omitted when requesting a reservation from a go-libp2p relay we
|
@@ -405,24 +490,53 @@ export class ReservationStore extends TypedEventEmitter<ReservationStoreEvents>
|
|
405
490
|
/**
|
406
491
|
* Remove listen relay
|
407
492
|
*/
|
408
|
-
async #removeReservation (peerId: PeerId
|
493
|
+
async #removeReservation (peerId: PeerId): Promise<void> {
|
494
|
+
const reservation = this.reservations.get(peerId)
|
495
|
+
|
496
|
+
if (reservation == null) {
|
497
|
+
return
|
498
|
+
}
|
499
|
+
|
409
500
|
this.log('removing relay reservation with %p from local store', peerId)
|
410
501
|
clearTimeout(reservation.timeout)
|
411
502
|
this.reservations.delete(peerId)
|
412
503
|
|
504
|
+
// discover a new relay for this discovery request
|
505
|
+
if (reservation.type === 'discovered') {
|
506
|
+
this.pendingReservations.push(
|
507
|
+
reservation.id
|
508
|
+
)
|
509
|
+
}
|
510
|
+
|
413
511
|
// untag the relay
|
414
512
|
await this.peerStore.merge(peerId, {
|
415
513
|
tags: {
|
416
|
-
[RELAY_TAG]: undefined,
|
417
514
|
[KEEP_ALIVE_TAG]: undefined
|
418
515
|
}
|
419
516
|
})
|
420
517
|
|
421
|
-
this.safeDispatchEvent('relay:removed', {
|
518
|
+
this.safeDispatchEvent('relay:removed', {
|
519
|
+
detail: {
|
520
|
+
relay: peerId,
|
521
|
+
details: reservation
|
522
|
+
}
|
523
|
+
})
|
524
|
+
|
525
|
+
// maybe trigger discovery of new relays
|
526
|
+
this.#checkReservationCount()
|
527
|
+
}
|
528
|
+
|
529
|
+
#checkReservationCount (): void {
|
530
|
+
if (this.pendingReservations.length === 0) {
|
531
|
+
this.log.trace('have discovered enough relays')
|
532
|
+
this.reserveQueue.clear()
|
533
|
+
this.safeDispatchEvent('relay:found-enough-relays')
|
422
534
|
|
423
|
-
|
424
|
-
this.log('not enough relays %d/%d', this.reservations.size, this.maxDiscoveredRelays)
|
425
|
-
this.safeDispatchEvent('relay:not-enough-relays', {})
|
535
|
+
return
|
426
536
|
}
|
537
|
+
|
538
|
+
this.relayFilter = createScalableCuckooFilter(100)
|
539
|
+
this.log('not discovered enough relays %d/%d', this.reservations.size, this.pendingReservations.length)
|
540
|
+
this.safeDispatchEvent('relay:not-enough-relays')
|
427
541
|
}
|
428
542
|
}
|