@libp2p/circuit-relay-v2 2.1.4 → 2.1.5-3bc9769b8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
}
|