@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
package/src/server/index.ts
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import { publicKeyToProtobuf } from '@libp2p/crypto/keys'
|
1
2
|
import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
2
3
|
import { peerIdFromMultihash } from '@libp2p/peer-id'
|
3
4
|
import { RecordEnvelope } from '@libp2p/peer-record'
|
@@ -156,8 +157,6 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
156
157
|
runOnLimitedConnection: true
|
157
158
|
})
|
158
159
|
|
159
|
-
this.reservationStore.start()
|
160
|
-
|
161
160
|
this.started = true
|
162
161
|
}
|
163
162
|
|
@@ -165,7 +164,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
165
164
|
* Stop Relay service
|
166
165
|
*/
|
167
166
|
async stop (): Promise<void> {
|
168
|
-
this.reservationStore.
|
167
|
+
this.reservationStore.clear()
|
169
168
|
this.shutdownController.abort()
|
170
169
|
await this.registrar.unhandle(RELAY_V2_HOP_CODEC)
|
171
170
|
|
@@ -290,16 +289,25 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
290
289
|
addrs.push(relayAddr.bytes)
|
291
290
|
}
|
292
291
|
|
293
|
-
const
|
292
|
+
const envelope = await RecordEnvelope.seal(new ReservationVoucherRecord({
|
294
293
|
peer: remotePeer,
|
295
294
|
relay: this.peerId,
|
296
|
-
expiration:
|
295
|
+
expiration: expire
|
297
296
|
}), this.privateKey)
|
298
297
|
|
299
298
|
return {
|
300
299
|
addrs,
|
301
300
|
expire,
|
302
|
-
voucher:
|
301
|
+
voucher: {
|
302
|
+
publicKey: publicKeyToProtobuf(envelope.publicKey),
|
303
|
+
payloadType: envelope.payloadType,
|
304
|
+
payload: {
|
305
|
+
peer: remotePeer.toMultihash().bytes,
|
306
|
+
relay: this.peerId.toMultihash().bytes,
|
307
|
+
expiration: expire
|
308
|
+
},
|
309
|
+
signature: envelope.signature
|
310
|
+
}
|
303
311
|
}
|
304
312
|
}
|
305
313
|
|
@@ -330,7 +338,9 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
330
338
|
return
|
331
339
|
}
|
332
340
|
|
333
|
-
|
341
|
+
const reservation = this.reservationStore.get(dstPeer)
|
342
|
+
|
343
|
+
if (reservation == null) {
|
334
344
|
this.log.error('hop connect denied for destination peer %p not having a reservation for %p with status %s', dstPeer, connection.remotePeer, Status.NO_RESERVATION)
|
335
345
|
await hopstr.write({ type: HopMessage.Type.STATUS, status: Status.NO_RESERVATION }, options)
|
336
346
|
return
|
@@ -350,7 +360,6 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
350
360
|
return
|
351
361
|
}
|
352
362
|
|
353
|
-
const limit = this.reservationStore.get(dstPeer)?.limit
|
354
363
|
const destinationConnection = connections[0]
|
355
364
|
|
356
365
|
const destinationStream = await this.stopHop({
|
@@ -361,7 +370,7 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
361
370
|
id: connection.remotePeer.toMultihash().bytes,
|
362
371
|
addrs: []
|
363
372
|
},
|
364
|
-
limit
|
373
|
+
limit: reservation?.limit
|
365
374
|
}
|
366
375
|
}, options)
|
367
376
|
|
@@ -374,13 +383,14 @@ class CircuitRelayServer extends TypedEventEmitter<RelayServerEvents> implements
|
|
374
383
|
await hopstr.write({
|
375
384
|
type: HopMessage.Type.STATUS,
|
376
385
|
status: Status.OK,
|
377
|
-
limit
|
386
|
+
limit: reservation?.limit
|
378
387
|
}, options)
|
379
388
|
const sourceStream = stream.unwrap()
|
380
389
|
|
381
390
|
this.log('connection from %p to %p established - merging streams', connection.remotePeer, dstPeer)
|
391
|
+
|
382
392
|
// Short circuit the two streams to create the relayed connection
|
383
|
-
createLimitedRelay(sourceStream, destinationStream, this.shutdownController.signal,
|
393
|
+
createLimitedRelay(sourceStream, destinationStream, this.shutdownController.signal, reservation, {
|
384
394
|
log: this.log
|
385
395
|
})
|
386
396
|
}
|
@@ -1,14 +1,16 @@
|
|
1
1
|
import { trackedPeerMap } from '@libp2p/peer-collections'
|
2
|
-
import {
|
2
|
+
import { retimeableSignal } from 'retimeable-signal'
|
3
|
+
import { DEFAULT_DATA_LIMIT, DEFAULT_DURATION_LIMIT, DEFAULT_MAX_RESERVATION_STORE_SIZE, DEFAULT_MAX_RESERVATION_TTL } from '../constants.js'
|
3
4
|
import { type Limit, Status } from '../pb/index.js'
|
4
5
|
import type { RelayReservation } from '../index.js'
|
5
|
-
import type { Metrics, PeerId
|
6
|
+
import type { ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
|
6
7
|
import type { PeerMap } from '@libp2p/peer-collections'
|
7
8
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
8
9
|
|
9
10
|
export type ReservationStatus = Status.OK | Status.PERMISSION_DENIED | Status.RESERVATION_REFUSED
|
10
11
|
|
11
12
|
export interface ReservationStoreComponents {
|
13
|
+
logger: ComponentLogger
|
12
14
|
metrics?: Metrics
|
13
15
|
}
|
14
16
|
|
@@ -52,20 +54,18 @@ export interface ReservationStoreInit {
|
|
52
54
|
defaultDataLimit?: bigint
|
53
55
|
}
|
54
56
|
|
55
|
-
export class ReservationStore
|
57
|
+
export class ReservationStore {
|
56
58
|
public readonly reservations: PeerMap<RelayReservation>
|
57
|
-
private _started = false
|
58
|
-
private interval: any
|
59
59
|
private readonly maxReservations: number
|
60
|
-
private readonly reservationClearInterval: number
|
61
60
|
private readonly applyDefaultLimit: boolean
|
62
61
|
private readonly reservationTtl: number
|
63
62
|
private readonly defaultDurationLimit: number
|
64
63
|
private readonly defaultDataLimit: bigint
|
64
|
+
private readonly log: Logger
|
65
65
|
|
66
66
|
constructor (components: ReservationStoreComponents, init: ReservationStoreInit = {}) {
|
67
|
+
this.log = components.logger.forComponent('libp2p:circuit-relay:server:reservation-store')
|
67
68
|
this.maxReservations = init.maxReservations ?? DEFAULT_MAX_RESERVATION_STORE_SIZE
|
68
|
-
this.reservationClearInterval = init.reservationClearInterval ?? DEFAULT_MAX_RESERVATION_CLEAR_INTERVAL
|
69
69
|
this.applyDefaultLimit = init.applyDefaultLimit !== false
|
70
70
|
this.reservationTtl = init.reservationTtl ?? DEFAULT_MAX_RESERVATION_TTL
|
71
71
|
this.defaultDurationLimit = init.defaultDurationLimit ?? DEFAULT_DURATION_LIMIT
|
@@ -77,59 +77,55 @@ export class ReservationStore implements Startable {
|
|
77
77
|
})
|
78
78
|
}
|
79
79
|
|
80
|
-
isStarted (): boolean {
|
81
|
-
return this._started
|
82
|
-
}
|
83
|
-
|
84
|
-
start (): void {
|
85
|
-
if (this._started) {
|
86
|
-
return
|
87
|
-
}
|
88
|
-
this._started = true
|
89
|
-
this.interval = setInterval(
|
90
|
-
() => {
|
91
|
-
const now = (new Date()).getTime()
|
92
|
-
this.reservations.forEach((r, k) => {
|
93
|
-
if (r.expire.getTime() < now) {
|
94
|
-
this.reservations.delete(k)
|
95
|
-
}
|
96
|
-
})
|
97
|
-
},
|
98
|
-
this.reservationClearInterval
|
99
|
-
)
|
100
|
-
}
|
101
|
-
|
102
|
-
stop (): void {
|
103
|
-
clearInterval(this.interval)
|
104
|
-
}
|
105
|
-
|
106
80
|
reserve (peer: PeerId, addr: Multiaddr, limit?: Limit): { status: ReservationStatus, expire?: number } {
|
107
|
-
|
81
|
+
let reservation = this.reservations.get(peer)
|
82
|
+
|
83
|
+
if (this.reservations.size >= this.maxReservations && reservation == null) {
|
108
84
|
return { status: Status.RESERVATION_REFUSED }
|
109
85
|
}
|
110
86
|
|
111
|
-
const
|
87
|
+
const expiry = new Date(Date.now() + this.reservationTtl)
|
112
88
|
let checkedLimit: Limit | undefined
|
113
89
|
|
114
90
|
if (this.applyDefaultLimit) {
|
115
|
-
checkedLimit = limit ?? {
|
91
|
+
checkedLimit = limit ?? {
|
92
|
+
data: this.defaultDataLimit,
|
93
|
+
duration: this.defaultDurationLimit
|
94
|
+
}
|
116
95
|
}
|
117
96
|
|
118
|
-
|
97
|
+
if (reservation != null) {
|
98
|
+
this.log('refreshing reservation for client %p', peer)
|
99
|
+
reservation.signal.reset(this.reservationTtl)
|
100
|
+
} else {
|
101
|
+
this.log('creating new reservation for client %p', peer)
|
102
|
+
reservation = {
|
103
|
+
addr,
|
104
|
+
expiry,
|
105
|
+
limit: checkedLimit,
|
106
|
+
signal: retimeableSignal(this.reservationTtl)
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
this.reservations.set(peer, reservation)
|
111
|
+
|
112
|
+
reservation.signal.addEventListener('abort', () => {
|
113
|
+
this.reservations.delete(peer)
|
114
|
+
})
|
119
115
|
|
120
116
|
// return expiry time in seconds
|
121
|
-
return { status: Status.OK, expire: Math.round(
|
117
|
+
return { status: Status.OK, expire: Math.round(expiry.getTime() / 1000) }
|
122
118
|
}
|
123
119
|
|
124
120
|
removeReservation (peer: PeerId): void {
|
125
121
|
this.reservations.delete(peer)
|
126
122
|
}
|
127
123
|
|
128
|
-
hasReservation (dst: PeerId): boolean {
|
129
|
-
return this.reservations.has(dst)
|
130
|
-
}
|
131
|
-
|
132
124
|
get (peer: PeerId): RelayReservation | undefined {
|
133
125
|
return this.reservations.get(peer)
|
134
126
|
}
|
127
|
+
|
128
|
+
clear (): void {
|
129
|
+
this.reservations.clear()
|
130
|
+
}
|
135
131
|
}
|
@@ -4,7 +4,7 @@ import type { PeerId, Record } from '@libp2p/interface'
|
|
4
4
|
export interface ReservationVoucherOptions {
|
5
5
|
relay: PeerId
|
6
6
|
peer: PeerId
|
7
|
-
expiration:
|
7
|
+
expiration: bigint
|
8
8
|
}
|
9
9
|
|
10
10
|
export class ReservationVoucherRecord implements Record {
|
@@ -13,7 +13,7 @@ export class ReservationVoucherRecord implements Record {
|
|
13
13
|
|
14
14
|
private readonly relay: PeerId
|
15
15
|
private readonly peer: PeerId
|
16
|
-
private readonly expiration:
|
16
|
+
private readonly expiration: bigint
|
17
17
|
|
18
18
|
constructor ({ relay, peer, expiration }: ReservationVoucherOptions) {
|
19
19
|
this.relay = relay
|
@@ -1,11 +1,11 @@
|
|
1
1
|
import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
2
2
|
import { PeerQueue } from '@libp2p/utils/peer-queue'
|
3
3
|
import { anySignal } from 'any-signal'
|
4
|
-
import {
|
4
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
5
5
|
import {
|
6
6
|
RELAY_V2_HOP_CODEC
|
7
7
|
} from '../constants.js'
|
8
|
-
import type { ComponentLogger, Logger, PeerId, PeerStore, Startable, TopologyFilter } from '@libp2p/interface'
|
8
|
+
import type { ComponentLogger, Logger, Peer, PeerId, PeerStore, Startable, TopologyFilter } from '@libp2p/interface'
|
9
9
|
import type { ConnectionManager, RandomWalk, Registrar, TransportManager } from '@libp2p/interface-internal'
|
10
10
|
|
11
11
|
export interface RelayDiscoveryEvents {
|
@@ -40,6 +40,7 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
40
40
|
private readonly log: Logger
|
41
41
|
private discoveryController: AbortController
|
42
42
|
private readonly filter?: TopologyFilter
|
43
|
+
private queue?: PeerQueue
|
43
44
|
|
44
45
|
constructor (components: RelayDiscoveryComponents, init: RelayDiscoveryInit = {}) {
|
45
46
|
super()
|
@@ -66,7 +67,7 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
66
67
|
this.topologyId = await this.registrar.register(RELAY_V2_HOP_CODEC, {
|
67
68
|
filter: this.filter,
|
68
69
|
onConnect: (peerId) => {
|
69
|
-
this.log.trace('discovered relay %p', peerId)
|
70
|
+
this.log.trace('discovered relay %p queue (length: %d, active %d)', peerId, this.queue?.size, this.queue?.running)
|
70
71
|
this.safeDispatchEvent('relay:discover', { detail: peerId })
|
71
72
|
}
|
72
73
|
})
|
@@ -113,7 +114,23 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
113
114
|
}
|
114
115
|
],
|
115
116
|
orders: [
|
116
|
-
|
117
|
+
// randomise
|
118
|
+
() => Math.random() < 0.5 ? 1 : -1,
|
119
|
+
// prefer peers we've connected to in the past
|
120
|
+
(a, b) => {
|
121
|
+
const lastDialA = getLastDial(a)
|
122
|
+
const lastDialB = getLastDial(b)
|
123
|
+
|
124
|
+
if (lastDialA > lastDialB) {
|
125
|
+
return -1
|
126
|
+
}
|
127
|
+
|
128
|
+
if (lastDialB > lastDialA) {
|
129
|
+
return 1
|
130
|
+
}
|
131
|
+
|
132
|
+
return 0
|
133
|
+
}
|
117
134
|
]
|
118
135
|
}))
|
119
136
|
|
@@ -126,11 +143,12 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
126
143
|
|
127
144
|
// perform random walk and dial peers - after identify has run, the network
|
128
145
|
// topology will be notified of new relays
|
129
|
-
const queue = new PeerQueue({
|
146
|
+
const queue = this.queue = new PeerQueue({
|
130
147
|
concurrency: 5
|
131
148
|
})
|
132
149
|
|
133
150
|
this.log('start random walk')
|
151
|
+
|
134
152
|
for await (const peer of this.randomWalk.walk({ signal: this.discoveryController.signal })) {
|
135
153
|
this.log.trace('found random peer %p', peer.id)
|
136
154
|
|
@@ -155,12 +173,16 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
155
173
|
continue
|
156
174
|
}
|
157
175
|
|
158
|
-
|
176
|
+
if (queue.queued > 10) {
|
177
|
+
this.log.trace('wait for space in queue for %p', peer.id)
|
159
178
|
|
160
|
-
|
161
|
-
|
179
|
+
// pause the random walk until there is space in the queue
|
180
|
+
await queue.onSizeLessThan(10, {
|
181
|
+
signal: this.discoveryController.signal
|
182
|
+
})
|
183
|
+
}
|
162
184
|
|
163
|
-
this.log('adding random peer %p to dial queue (length: %d)', peer.id, queue.size)
|
185
|
+
this.log('adding random peer %p to dial queue (length: %d, active %d)', peer.id, queue.size, queue.running)
|
164
186
|
|
165
187
|
// dial the peer - this will cause identify to run and our topology to
|
166
188
|
// be notified and we'll attempt to create reservations
|
@@ -182,6 +204,8 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
182
204
|
})
|
183
205
|
}
|
184
206
|
|
207
|
+
this.log('stop random walk')
|
208
|
+
|
185
209
|
await queue.onIdle()
|
186
210
|
})
|
187
211
|
.catch(err => {
|
@@ -197,3 +221,17 @@ export class RelayDiscovery extends TypedEventEmitter<RelayDiscoveryEvents> impl
|
|
197
221
|
this.discoveryController?.abort()
|
198
222
|
}
|
199
223
|
}
|
224
|
+
|
225
|
+
/**
|
226
|
+
* Returns the timestamp of the last time we connected to this peer, if we've
|
227
|
+
* not connected to them before return 0
|
228
|
+
*/
|
229
|
+
function getLastDial (peer: Peer): number {
|
230
|
+
const lastDial = peer.metadata.get('last-dial-success')
|
231
|
+
|
232
|
+
if (lastDial == null) {
|
233
|
+
return 0
|
234
|
+
}
|
235
|
+
|
236
|
+
return new Date(uint8ArrayToString(lastDial)).getTime()
|
237
|
+
}
|
package/src/transport/index.ts
CHANGED
@@ -17,13 +17,6 @@ export interface CircuitRelayTransportComponents extends RelayDiscoveryComponent
|
|
17
17
|
* RelayConfig configures the circuit v2 relay transport.
|
18
18
|
*/
|
19
19
|
export interface CircuitRelayTransportInit extends ReservationStoreInit {
|
20
|
-
/**
|
21
|
-
* The number of peers running diable relays to search for and connect to
|
22
|
-
*
|
23
|
-
* @default 0
|
24
|
-
*/
|
25
|
-
discoverRelays?: number
|
26
|
-
|
27
20
|
/**
|
28
21
|
* An optional filter used to prevent duplicate attempts to reserve relay
|
29
22
|
* slots on the same peer
|
@@ -1,8 +1,10 @@
|
|
1
|
-
import { ListenError, TypedEventEmitter } from '@libp2p/interface'
|
2
|
-
import { PeerMap } from '@libp2p/peer-collections'
|
1
|
+
import { ListenError, TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
3
2
|
import { multiaddr } from '@multiformats/multiaddr'
|
4
|
-
import
|
5
|
-
import
|
3
|
+
import { DEFAULT_RESERVATION_COMPLETION_TIMEOUT } from '../constants.js'
|
4
|
+
import { CircuitListen, CircuitSearch } from '../utils.js'
|
5
|
+
import type { RelayDiscovery } from './discovery.js'
|
6
|
+
import type { RelayReservation, ReservationStore } from './reservation-store.js'
|
7
|
+
import type { ComponentLogger, Logger, Listener, ListenerEvents, PeerId } from '@libp2p/interface'
|
6
8
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
7
9
|
import type { Multiaddr } from '@multiformats/multiaddr'
|
8
10
|
|
@@ -12,79 +14,117 @@ export interface CircuitRelayTransportListenerComponents {
|
|
12
14
|
logger: ComponentLogger
|
13
15
|
}
|
14
16
|
|
17
|
+
export interface CircuitRelayTransportListenerInit {
|
18
|
+
listenTimeout?: number
|
19
|
+
}
|
20
|
+
|
15
21
|
class CircuitRelayTransportListener extends TypedEventEmitter<ListenerEvents> implements Listener {
|
16
22
|
private readonly connectionManager: ConnectionManager
|
17
23
|
private readonly reservationStore: ReservationStore
|
18
|
-
private readonly
|
24
|
+
private readonly discovery?: RelayDiscovery
|
25
|
+
private listeningAddrs: Multiaddr[]
|
19
26
|
private readonly log: Logger
|
27
|
+
private readonly listenTimeout: number
|
28
|
+
private reservationId?: string
|
29
|
+
private relay?: PeerId
|
20
30
|
|
21
|
-
constructor (components: CircuitRelayTransportListenerComponents) {
|
31
|
+
constructor (components: CircuitRelayTransportListenerComponents, init: CircuitRelayTransportListenerInit = {}) {
|
22
32
|
super()
|
23
33
|
|
24
34
|
this.log = components.logger.forComponent('libp2p:circuit-relay:transport:listener')
|
25
35
|
this.connectionManager = components.connectionManager
|
26
36
|
this.reservationStore = components.relayStore
|
27
|
-
this.listeningAddrs =
|
37
|
+
this.listeningAddrs = []
|
38
|
+
this.listenTimeout = init.listenTimeout ?? DEFAULT_RESERVATION_COMPLETION_TIMEOUT
|
28
39
|
|
29
40
|
// remove listening addrs when a relay is removed
|
30
41
|
this.reservationStore.addEventListener('relay:removed', this._onRemoveRelayPeer)
|
42
|
+
this.reservationStore.addEventListener('relay:created-reservation', this._onAddRelayPeer)
|
31
43
|
}
|
32
44
|
|
33
|
-
_onRemoveRelayPeer = (evt: CustomEvent<
|
34
|
-
|
35
|
-
|
36
|
-
this.log('relay peer removed %p - had reservation', evt.detail, had)
|
45
|
+
_onRemoveRelayPeer = (evt: CustomEvent<RelayReservation>): void => {
|
46
|
+
this.log('relay removed %p our relay %p', evt.detail.relay, this.relay, this.relay?.equals(evt.detail.relay))
|
37
47
|
|
38
|
-
if (
|
48
|
+
if (this.relay?.equals(evt.detail.relay) !== true) {
|
39
49
|
return
|
40
50
|
}
|
41
51
|
|
42
|
-
this.
|
52
|
+
this.log('relay peer removed %p', evt.detail.relay)
|
53
|
+
|
54
|
+
this.listeningAddrs = []
|
43
55
|
|
44
56
|
// announce listen addresses change
|
45
57
|
this.safeDispatchEvent('listening')
|
46
58
|
}
|
47
59
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
const relayAddr = addr.decapsulate('/p2p-circuit')
|
53
|
-
const relayConn = await this.connectionManager.openConnection(relayAddr)
|
60
|
+
_onAddRelayPeer = (evt: CustomEvent<RelayReservation>): void => {
|
61
|
+
const {
|
62
|
+
relay, details
|
63
|
+
} = evt.detail
|
54
64
|
|
55
|
-
if (
|
56
|
-
this.log('making reservation on peer %p', relayConn.remotePeer)
|
57
|
-
// addRelay calls transportManager.listen which calls this listen method
|
58
|
-
await this.reservationStore.addRelay(relayConn.remotePeer, 'configured')
|
65
|
+
if (details.type === 'configured') {
|
59
66
|
return
|
60
67
|
}
|
61
68
|
|
62
|
-
|
63
|
-
|
64
|
-
if (reservation == null) {
|
65
|
-
throw new ListenError('Did not have reservation after making reservation')
|
66
|
-
}
|
67
|
-
|
68
|
-
if (this.listeningAddrs.has(relayConn.remotePeer)) {
|
69
|
-
this.log('already listening on relay %p', relayConn.remotePeer)
|
69
|
+
if (details.id !== this.reservationId) {
|
70
70
|
return
|
71
71
|
}
|
72
72
|
|
73
|
+
this.log('relay peer added %p', relay)
|
74
|
+
|
75
|
+
this.relay = relay
|
76
|
+
|
73
77
|
// add all addresses from the relay reservation
|
74
|
-
this.listeningAddrs.
|
78
|
+
this.listeningAddrs = details.reservation.addrs
|
75
79
|
.map(buf => multiaddr(buf).encapsulate('/p2p-circuit'))
|
76
|
-
)
|
77
80
|
|
81
|
+
// announce listen addresses change
|
78
82
|
this.safeDispatchEvent('listening')
|
79
83
|
}
|
80
84
|
|
85
|
+
async listen (addr: Multiaddr): Promise<void> {
|
86
|
+
this.log('listen on %a', addr)
|
87
|
+
|
88
|
+
if (CircuitSearch.exactMatch(addr)) {
|
89
|
+
// start relay discovery
|
90
|
+
this.reservationId = this.reservationStore.reserveRelay()
|
91
|
+
} else if (CircuitListen.exactMatch(addr)) {
|
92
|
+
const signal = AbortSignal.timeout(this.listenTimeout)
|
93
|
+
setMaxListeners(Infinity, signal)
|
94
|
+
|
95
|
+
// try to make a reservation on one particular relay
|
96
|
+
// remove the circuit part to get the peer id of the relay
|
97
|
+
const relayAddr = addr.decapsulate('/p2p-circuit')
|
98
|
+
const relayConn = await this.connectionManager.openConnection(relayAddr, {
|
99
|
+
signal
|
100
|
+
})
|
101
|
+
|
102
|
+
if (!this.reservationStore.hasReservation(relayConn.remotePeer)) {
|
103
|
+
this.log('making reservation on peer %p', relayConn.remotePeer)
|
104
|
+
const reservation = await this.reservationStore.addRelay(relayConn.remotePeer, 'configured')
|
105
|
+
this.log('made reservation on peer %p', relayConn.remotePeer)
|
106
|
+
|
107
|
+
this.relay = reservation.relay
|
108
|
+
|
109
|
+
// add all addresses from the relay reservation
|
110
|
+
this.listeningAddrs = reservation.details.reservation.addrs
|
111
|
+
.map(buf => multiaddr(buf).encapsulate('/p2p-circuit'))
|
112
|
+
|
113
|
+
// if that succeeded announce listen addresses change
|
114
|
+
this.safeDispatchEvent('listening')
|
115
|
+
}
|
116
|
+
} else {
|
117
|
+
throw new ListenError(`Could not listen on p2p-circuit address "${addr}"`)
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
81
121
|
getAddrs (): Multiaddr[] {
|
82
122
|
return [...this.listeningAddrs.values()].flat()
|
83
123
|
}
|
84
124
|
|
85
125
|
async close (): Promise<void> {
|
86
|
-
|
87
|
-
this.listeningAddrs
|
126
|
+
this.reservationStore.cancelReservations()
|
127
|
+
this.listeningAddrs = []
|
88
128
|
|
89
129
|
// remove listener
|
90
130
|
this.reservationStore.removeEventListener('relay:removed', this._onRemoveRelayPeer)
|