libp2p 0.42.2-593deefe → 0.42.2-5e63ee2d
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 +30 -30
- package/dist/src/address-manager/index.d.ts +1 -10
- package/dist/src/address-manager/index.d.ts.map +1 -1
- package/dist/src/address-manager/index.js +46 -29
- package/dist/src/address-manager/index.js.map +1 -1
- package/dist/src/autonat/constants.d.ts +4 -0
- package/dist/src/autonat/constants.d.ts.map +1 -0
- package/dist/src/autonat/constants.js +4 -0
- package/dist/src/autonat/constants.js.map +1 -0
- package/dist/src/autonat/index.d.ts +64 -0
- package/dist/src/autonat/index.d.ts.map +1 -0
- package/dist/src/autonat/index.js +417 -0
- package/dist/src/autonat/index.js.map +1 -0
- package/dist/src/autonat/pb/index.d.ts +57 -0
- package/dist/src/autonat/pb/index.d.ts.map +1 -0
- package/dist/src/autonat/pb/index.js +250 -0
- package/dist/src/autonat/pb/index.js.map +1 -0
- package/dist/src/circuit/constants.d.ts +29 -3
- package/dist/src/circuit/constants.d.ts.map +1 -1
- package/dist/src/circuit/constants.js +32 -5
- package/dist/src/circuit/constants.js.map +1 -1
- package/dist/src/circuit/index.d.ts +16 -61
- package/dist/src/circuit/index.d.ts.map +1 -1
- package/dist/src/circuit/index.js +2 -1
- package/dist/src/circuit/index.js.map +1 -1
- package/dist/src/circuit/server/advert-service.d.ts +43 -0
- package/dist/src/circuit/server/advert-service.d.ts.map +1 -0
- package/dist/src/circuit/server/advert-service.js +69 -0
- package/dist/src/circuit/server/advert-service.js.map +1 -0
- package/dist/src/circuit/server/index.d.ts +60 -0
- package/dist/src/circuit/server/index.d.ts.map +1 -0
- package/dist/src/circuit/server/index.js +287 -0
- package/dist/src/circuit/server/index.js.map +1 -0
- package/dist/src/circuit/{reservation-store.d.ts → server/reservation-store.d.ts} +17 -10
- package/dist/src/circuit/server/reservation-store.d.ts.map +1 -0
- package/dist/src/circuit/server/reservation-store.js +57 -0
- package/dist/src/circuit/server/reservation-store.js.map +1 -0
- package/dist/src/circuit/server/reservation-voucher.d.ts.map +1 -0
- package/dist/src/circuit/{reservation-voucher.js → server/reservation-voucher.js} +1 -1
- package/dist/src/circuit/server/reservation-voucher.js.map +1 -0
- package/dist/src/circuit/transport/discovery.d.ts +45 -0
- package/dist/src/circuit/transport/discovery.d.ts.map +1 -0
- package/dist/src/circuit/transport/discovery.js +82 -0
- package/dist/src/circuit/transport/discovery.js.map +1 -0
- package/dist/src/circuit/transport/index.d.ts +33 -0
- package/dist/src/circuit/transport/index.d.ts.map +1 -0
- package/dist/src/circuit/transport/index.js +225 -0
- package/dist/src/circuit/transport/index.js.map +1 -0
- package/dist/src/circuit/transport/listener.d.ts +9 -0
- package/dist/src/circuit/transport/listener.d.ts.map +1 -0
- package/dist/src/circuit/transport/listener.js +76 -0
- package/dist/src/circuit/transport/listener.js.map +1 -0
- package/dist/src/circuit/transport/reservation-store.d.ts +60 -0
- package/dist/src/circuit/transport/reservation-store.d.ts.map +1 -0
- package/dist/src/circuit/transport/reservation-store.js +165 -0
- package/dist/src/circuit/transport/reservation-store.js.map +1 -0
- package/dist/src/circuit/utils.d.ts +4 -2
- package/dist/src/circuit/utils.d.ts.map +1 -1
- package/dist/src/circuit/utils.js +75 -102
- package/dist/src/circuit/utils.js.map +1 -1
- package/dist/src/components.d.ts +2 -1
- package/dist/src/components.d.ts.map +1 -1
- package/dist/src/components.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +17 -20
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection/index.d.ts +2 -2
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js +1 -1
- package/dist/src/connection/index.js.map +1 -1
- package/dist/src/connection-manager/auto-dialler.d.ts +0 -4
- package/dist/src/connection-manager/auto-dialler.d.ts.map +1 -1
- package/dist/src/connection-manager/auto-dialler.js +0 -9
- package/dist/src/connection-manager/auto-dialler.js.map +1 -1
- package/dist/src/connection-manager/dialer/dial-request.js +1 -1
- package/dist/src/connection-manager/dialer/dial-request.js.map +1 -1
- package/dist/src/connection-manager/dialer/index.d.ts +2 -1
- package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
- package/dist/src/connection-manager/dialer/index.js +3 -3
- package/dist/src/connection-manager/dialer/index.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +0 -4
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +1 -1
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/latency-monitor.d.ts.map +1 -1
- package/dist/src/connection-manager/latency-monitor.js +1 -1
- package/dist/src/connection-manager/latency-monitor.js.map +1 -1
- package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +1 -1
- package/dist/src/content-routing/index.d.ts +6 -4
- package/dist/src/content-routing/index.d.ts.map +1 -1
- package/dist/src/content-routing/index.js +1 -1
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/content-routing/utils.d.ts +3 -3
- package/dist/src/content-routing/utils.d.ts.map +1 -1
- package/dist/src/dht/dht-content-routing.d.ts +2 -1
- package/dist/src/dht/dht-content-routing.d.ts.map +1 -1
- package/dist/src/dht/dht-content-routing.js.map +1 -1
- package/dist/src/dht/dht-peer-routing.d.ts +3 -2
- package/dist/src/dht/dht-peer-routing.d.ts.map +1 -1
- package/dist/src/dht/dht-peer-routing.js.map +1 -1
- package/dist/src/dht/dummy-dht.d.ts +1 -1
- package/dist/src/dht/dummy-dht.d.ts.map +1 -1
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/identify/index.d.ts +3 -1
- package/dist/src/identify/index.d.ts.map +1 -1
- package/dist/src/identify/index.js +12 -7
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/index.d.ts +13 -7
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/insecure/index.d.ts.map +1 -1
- package/dist/src/insecure/index.js.map +1 -1
- package/dist/src/libp2p.d.ts +6 -4
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +19 -28
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/nat-manager.d.ts.map +1 -1
- package/dist/src/nat-manager.js +3 -1
- package/dist/src/nat-manager.js.map +1 -1
- package/dist/src/peer-record-updater.d.ts.map +1 -1
- package/dist/src/peer-routing.d.ts.map +1 -1
- package/dist/src/ping/index.d.ts.map +1 -1
- package/dist/src/pnet/crypto.d.ts +1 -1
- package/dist/src/pnet/crypto.d.ts.map +1 -1
- package/dist/src/pnet/crypto.js +1 -1
- package/dist/src/pnet/crypto.js.map +1 -1
- package/dist/src/pnet/key-generator.d.ts.map +1 -1
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/transport-manager.d.ts.map +1 -1
- package/dist/src/transport-manager.js +1 -1
- package/dist/src/transport-manager.js.map +1 -1
- package/dist/src/upgrader.d.ts +2 -1
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +19 -14
- package/dist/src/upgrader.js.map +1 -1
- package/package.json +23 -18
- package/src/address-manager/index.ts +62 -35
- package/src/autonat/constants.ts +4 -0
- package/src/autonat/index.ts +567 -0
- package/src/autonat/pb/index.proto +35 -0
- package/src/autonat/pb/index.ts +320 -0
- package/src/circuit/constants.ts +40 -5
- package/src/circuit/index.ts +17 -67
- package/src/circuit/server/advert-service.ts +108 -0
- package/src/circuit/server/index.ts +421 -0
- package/src/circuit/server/reservation-store.ts +111 -0
- package/src/circuit/{reservation-voucher.ts → server/reservation-voucher.ts} +3 -3
- package/src/circuit/transport/discovery.ts +127 -0
- package/src/circuit/transport/index.ts +325 -0
- package/src/circuit/transport/listener.ts +99 -0
- package/src/circuit/transport/reservation-store.ts +249 -0
- package/src/circuit/utils.ts +78 -115
- package/src/components.ts +9 -8
- package/src/config.ts +17 -20
- package/src/connection/index.ts +7 -7
- package/src/connection-manager/auto-dialler.ts +4 -20
- package/src/connection-manager/dialer/dial-request.ts +1 -1
- package/src/connection-manager/dialer/index.ts +10 -9
- package/src/connection-manager/index.ts +14 -19
- package/src/connection-manager/latency-monitor.ts +9 -9
- package/src/connection-manager/visibility-change-emitter.ts +4 -4
- package/src/content-routing/index.ts +10 -8
- package/src/content-routing/utils.ts +3 -3
- package/src/dht/dht-content-routing.ts +3 -2
- package/src/dht/dht-peer-routing.ts +3 -2
- package/src/dht/dummy-dht.ts +1 -1
- package/src/fetch/index.ts +7 -7
- package/src/identify/index.ts +22 -17
- package/src/index.ts +14 -7
- package/src/insecure/index.ts +2 -1
- package/src/libp2p.ts +33 -41
- package/src/nat-manager.ts +9 -7
- package/src/peer-record-updater.ts +4 -4
- package/src/peer-routing.ts +4 -4
- package/src/ping/index.ts +4 -4
- package/src/pnet/crypto.ts +3 -3
- package/src/pnet/key-generator.ts +1 -1
- package/src/registrar.ts +8 -8
- package/src/transport-manager.ts +10 -10
- package/src/upgrader.ts +20 -19
- package/src/version.ts +1 -1
- package/dist/src/circuit/client.d.ts +0 -81
- package/dist/src/circuit/client.d.ts.map +0 -1
- package/dist/src/circuit/client.js +0 -285
- package/dist/src/circuit/client.js.map +0 -1
- package/dist/src/circuit/hop.d.ts +0 -23
- package/dist/src/circuit/hop.d.ts.map +0 -1
- package/dist/src/circuit/hop.js +0 -167
- package/dist/src/circuit/hop.js.map +0 -1
- package/dist/src/circuit/interfaces.d.ts +0 -27
- package/dist/src/circuit/interfaces.d.ts.map +0 -1
- package/dist/src/circuit/interfaces.js +0 -2
- package/dist/src/circuit/interfaces.js.map +0 -1
- package/dist/src/circuit/listener.d.ts +0 -9
- package/dist/src/circuit/listener.d.ts.map +0 -1
- package/dist/src/circuit/listener.js +0 -62
- package/dist/src/circuit/listener.js.map +0 -1
- package/dist/src/circuit/multicodec.d.ts +0 -3
- package/dist/src/circuit/multicodec.d.ts.map +0 -1
- package/dist/src/circuit/multicodec.js +0 -3
- package/dist/src/circuit/multicodec.js.map +0 -1
- package/dist/src/circuit/relay.d.ts +0 -34
- package/dist/src/circuit/relay.d.ts.map +0 -1
- package/dist/src/circuit/relay.js +0 -61
- package/dist/src/circuit/relay.js.map +0 -1
- package/dist/src/circuit/reservation-store.d.ts.map +0 -1
- package/dist/src/circuit/reservation-store.js +0 -59
- package/dist/src/circuit/reservation-store.js.map +0 -1
- package/dist/src/circuit/reservation-voucher.d.ts.map +0 -1
- package/dist/src/circuit/reservation-voucher.js.map +0 -1
- package/dist/src/circuit/stop.d.ts +0 -19
- package/dist/src/circuit/stop.d.ts.map +0 -1
- package/dist/src/circuit/stop.js +0 -67
- package/dist/src/circuit/stop.js.map +0 -1
- package/dist/src/circuit/transport.d.ts +0 -66
- package/dist/src/circuit/transport.d.ts.map +0 -1
- package/dist/src/circuit/transport.js +0 -238
- package/dist/src/circuit/transport.js.map +0 -1
- package/src/circuit/client.ts +0 -381
- package/src/circuit/hop.ts +0 -210
- package/src/circuit/interfaces.ts +0 -28
- package/src/circuit/listener.ts +0 -83
- package/src/circuit/multicodec.ts +0 -3
- package/src/circuit/relay.ts +0 -87
- package/src/circuit/reservation-store.ts +0 -106
- package/src/circuit/stop.ts +0 -92
- package/src/circuit/transport.ts +0 -313
- /package/dist/src/circuit/{reservation-voucher.d.ts → server/reservation-voucher.d.ts} +0 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { StopMessage, HopMessage, Status } from '../pb/index.js'
|
|
2
|
+
import { logger } from '@libp2p/logger'
|
|
3
|
+
import createError from 'err-code'
|
|
4
|
+
import * as mafmt from '@multiformats/mafmt'
|
|
5
|
+
import { multiaddr } from '@multiformats/multiaddr'
|
|
6
|
+
import { codes } from '../../errors.js'
|
|
7
|
+
import { streamToMaConnection } from '@libp2p/utils/stream-to-ma-conn'
|
|
8
|
+
import { createListener } from './listener.js'
|
|
9
|
+
import { symbol, Upgrader } from '@libp2p/interface-transport'
|
|
10
|
+
import { peerIdFromBytes, peerIdFromString } from '@libp2p/peer-id'
|
|
11
|
+
import type { AbortOptions } from '@libp2p/interfaces'
|
|
12
|
+
import type { IncomingStreamData, Registrar } from '@libp2p/interface-registrar'
|
|
13
|
+
import type { Listener, Transport, CreateListenerOptions } from '@libp2p/interface-transport'
|
|
14
|
+
import type { Connection, Stream } from '@libp2p/interface-connection'
|
|
15
|
+
import type { ConnectionGater } from '@libp2p/interface-connection-gater'
|
|
16
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
17
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
18
|
+
import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
19
|
+
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
20
|
+
import type { AddressManager } from '@libp2p/interface-address-manager'
|
|
21
|
+
import { pbStream } from 'it-pb-stream'
|
|
22
|
+
import type { ContentRouting } from '@libp2p/interface-content-routing'
|
|
23
|
+
import { CIRCUIT_PROTO_CODE, RELAY_V2_HOP_CODEC, RELAY_V2_STOP_CODEC } from '../constants.js'
|
|
24
|
+
import { RelayStoreInit, ReservationStore } from './reservation-store.js'
|
|
25
|
+
import { RelayDiscovery, RelayDiscoveryComponents } from './discovery.js'
|
|
26
|
+
|
|
27
|
+
const log = logger('libp2p:circuit-relay:transport')
|
|
28
|
+
|
|
29
|
+
const isValidStop = (request: StopMessage): request is Required<StopMessage> => {
|
|
30
|
+
if (request.peer == null) {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
request.peer.addrs.forEach(multiaddr)
|
|
36
|
+
} catch {
|
|
37
|
+
return false
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface CircuitRelayTransportComponents extends RelayDiscoveryComponents {
|
|
44
|
+
peerId: PeerId
|
|
45
|
+
peerStore: PeerStore
|
|
46
|
+
registrar: Registrar
|
|
47
|
+
connectionManager: ConnectionManager
|
|
48
|
+
upgrader: Upgrader
|
|
49
|
+
addressManager: AddressManager
|
|
50
|
+
contentRouting: ContentRouting
|
|
51
|
+
connectionGater: ConnectionGater
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface ConnectOptions {
|
|
55
|
+
stream: Stream
|
|
56
|
+
connection: Connection
|
|
57
|
+
destinationPeer: PeerId
|
|
58
|
+
destinationAddr: Multiaddr
|
|
59
|
+
relayAddr: Multiaddr
|
|
60
|
+
ma: Multiaddr
|
|
61
|
+
disconnectOnFailure: boolean
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* RelayConfig configures the circuit v2 relay transport.
|
|
66
|
+
*/
|
|
67
|
+
export interface CircuitRelayTransportInit extends RelayStoreInit {
|
|
68
|
+
/**
|
|
69
|
+
* The number of peers running diable relays to search for and
|
|
70
|
+
* connect to. (default: 0)
|
|
71
|
+
*/
|
|
72
|
+
discoverRelays?: number
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
class CircuitRelayTransport implements Transport {
|
|
76
|
+
private readonly discovery?: RelayDiscovery
|
|
77
|
+
private readonly registrar: Registrar
|
|
78
|
+
private readonly peerStore: PeerStore
|
|
79
|
+
private readonly connectionManager: ConnectionManager
|
|
80
|
+
private readonly peerId: PeerId
|
|
81
|
+
private readonly upgrader: Upgrader
|
|
82
|
+
private readonly addressManager: AddressManager
|
|
83
|
+
private readonly connectionGater: ConnectionGater
|
|
84
|
+
private readonly reservationStore: ReservationStore
|
|
85
|
+
private started: boolean
|
|
86
|
+
|
|
87
|
+
constructor (components: CircuitRelayTransportComponents, init: CircuitRelayTransportInit) {
|
|
88
|
+
this.registrar = components.registrar
|
|
89
|
+
this.peerStore = components.peerStore
|
|
90
|
+
this.connectionManager = components.connectionManager
|
|
91
|
+
this.peerId = components.peerId
|
|
92
|
+
this.upgrader = components.upgrader
|
|
93
|
+
this.addressManager = components.addressManager
|
|
94
|
+
this.connectionGater = components.connectionGater
|
|
95
|
+
|
|
96
|
+
if (init.discoverRelays != null && init.discoverRelays > 0) {
|
|
97
|
+
this.discovery = new RelayDiscovery(components)
|
|
98
|
+
this.discovery.addEventListener('relay:discover', (evt) => {
|
|
99
|
+
this.reservationStore.addRelay(evt.detail, 'discovered')
|
|
100
|
+
.catch(err => {
|
|
101
|
+
log.error('could not add discovered relay %p', evt.detail, err)
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
this.reservationStore = new ReservationStore(components, init)
|
|
107
|
+
this.reservationStore.addEventListener('relay:not-enough-relays', () => {
|
|
108
|
+
this.discovery?.discover()
|
|
109
|
+
.catch(err => {
|
|
110
|
+
log.error('could not discover relays', err)
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
this.started = false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
isStarted (): boolean {
|
|
118
|
+
return this.started
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async start (): Promise<void> {
|
|
122
|
+
await this.reservationStore.start()
|
|
123
|
+
await this.discovery?.start()
|
|
124
|
+
|
|
125
|
+
await this.registrar.handle(RELAY_V2_STOP_CODEC, (data) => {
|
|
126
|
+
void this.onStop(data).catch(err => {
|
|
127
|
+
log.error(err)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
this.started = true
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async stop (): Promise<void> {
|
|
135
|
+
this.discovery?.stop()
|
|
136
|
+
await this.reservationStore.stop()
|
|
137
|
+
await this.registrar.unhandle(RELAY_V2_STOP_CODEC)
|
|
138
|
+
|
|
139
|
+
this.started = false
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
get [symbol] (): true {
|
|
143
|
+
return true
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get [Symbol.toStringTag] (): 'libp2p/circuit-relay-v2' {
|
|
147
|
+
return 'libp2p/circuit-relay-v2'
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Dial a peer over a relay
|
|
152
|
+
*/
|
|
153
|
+
async dial (ma: Multiaddr, options: AbortOptions = {}): Promise<Connection> {
|
|
154
|
+
if (ma.protoCodes().filter(code => code === CIRCUIT_PROTO_CODE).length !== 1) {
|
|
155
|
+
const errMsg = 'Invalid circuit relay address'
|
|
156
|
+
log.error(errMsg, ma)
|
|
157
|
+
throw createError(new Error(errMsg), codes.ERR_RELAYED_DIAL)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Check the multiaddr to see if it contains a relay and a destination peer
|
|
161
|
+
const addrs = ma.toString().split('/p2p-circuit')
|
|
162
|
+
const relayAddr = multiaddr(addrs[0])
|
|
163
|
+
const destinationAddr = multiaddr(addrs[addrs.length - 1])
|
|
164
|
+
const relayId = relayAddr.getPeerId()
|
|
165
|
+
const destinationId = destinationAddr.getPeerId()
|
|
166
|
+
|
|
167
|
+
if (relayId == null || destinationId == null) {
|
|
168
|
+
const errMsg = 'Circuit relay dial failed as addresses did not have peer id'
|
|
169
|
+
log.error(errMsg)
|
|
170
|
+
throw createError(new Error(errMsg), codes.ERR_RELAYED_DIAL)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const relayPeer = peerIdFromString(relayId)
|
|
174
|
+
const destinationPeer = peerIdFromString(destinationId)
|
|
175
|
+
|
|
176
|
+
let disconnectOnFailure = false
|
|
177
|
+
const relayConnections = this.connectionManager.getConnections(relayPeer)
|
|
178
|
+
let relayConnection = relayConnections[0]
|
|
179
|
+
|
|
180
|
+
if (relayConnection == null) {
|
|
181
|
+
await this.peerStore.addressBook.add(relayPeer, [relayAddr])
|
|
182
|
+
relayConnection = await this.connectionManager.openConnection(relayPeer, options)
|
|
183
|
+
disconnectOnFailure = true
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const stream = await relayConnection.newStream([RELAY_V2_HOP_CODEC])
|
|
188
|
+
|
|
189
|
+
return await this.connectV2({
|
|
190
|
+
stream,
|
|
191
|
+
connection: relayConnection,
|
|
192
|
+
destinationPeer,
|
|
193
|
+
destinationAddr,
|
|
194
|
+
relayAddr,
|
|
195
|
+
ma,
|
|
196
|
+
disconnectOnFailure
|
|
197
|
+
})
|
|
198
|
+
} catch (err: any) {
|
|
199
|
+
log.error('Circuit relay dial failed', err)
|
|
200
|
+
disconnectOnFailure && await relayConnection.close()
|
|
201
|
+
throw err
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async connectV2 (
|
|
206
|
+
{
|
|
207
|
+
stream, connection, destinationPeer,
|
|
208
|
+
destinationAddr, relayAddr, ma,
|
|
209
|
+
disconnectOnFailure
|
|
210
|
+
}: ConnectOptions
|
|
211
|
+
): Promise<Connection> {
|
|
212
|
+
try {
|
|
213
|
+
const pbstr = pbStream(stream)
|
|
214
|
+
const hopstr = pbstr.pb(HopMessage)
|
|
215
|
+
hopstr.write({
|
|
216
|
+
type: HopMessage.Type.CONNECT,
|
|
217
|
+
peer: {
|
|
218
|
+
id: destinationPeer.toBytes(),
|
|
219
|
+
addrs: [multiaddr(destinationAddr).bytes]
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
const status = await hopstr.read()
|
|
224
|
+
|
|
225
|
+
if (status.status !== Status.OK) {
|
|
226
|
+
throw createError(new Error(`failed to connect via relay with status ${status?.status?.toString() ?? 'undefined'}`), codes.ERR_HOP_REQUEST_FAILED)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// TODO: do something with limit and transient connection
|
|
230
|
+
|
|
231
|
+
const maConn = streamToMaConnection({
|
|
232
|
+
stream: pbstr.unwrap(),
|
|
233
|
+
remoteAddr: ma,
|
|
234
|
+
localAddr: relayAddr.encapsulate(`/p2p-circuit/p2p/${this.peerId.toString()}`)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
log('new outbound connection %s', maConn.remoteAddr)
|
|
238
|
+
return await this.upgrader.upgradeOutbound(maConn)
|
|
239
|
+
} catch (err) {
|
|
240
|
+
log.error('Circuit relay dial failed', err)
|
|
241
|
+
disconnectOnFailure && await connection.close()
|
|
242
|
+
throw err
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Create a listener
|
|
248
|
+
*/
|
|
249
|
+
createListener (options: CreateListenerOptions): Listener {
|
|
250
|
+
return createListener({
|
|
251
|
+
connectionManager: this.connectionManager,
|
|
252
|
+
relayStore: this.reservationStore
|
|
253
|
+
})
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Filter check for all Multiaddrs that this transport can dial on
|
|
258
|
+
*
|
|
259
|
+
* @param {Multiaddr[]} multiaddrs
|
|
260
|
+
* @returns {Multiaddr[]}
|
|
261
|
+
*/
|
|
262
|
+
filter (multiaddrs: Multiaddr[]): Multiaddr[] {
|
|
263
|
+
multiaddrs = Array.isArray(multiaddrs) ? multiaddrs : [multiaddrs]
|
|
264
|
+
|
|
265
|
+
return multiaddrs.filter((ma) => {
|
|
266
|
+
return mafmt.Circuit.matches(ma)
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* An incoming STOP request means a remote peer wants to dial us via a relay
|
|
272
|
+
*/
|
|
273
|
+
async onStop ({ connection, stream }: IncomingStreamData): Promise<void> {
|
|
274
|
+
const pbstr = pbStream(stream)
|
|
275
|
+
const request = await pbstr.readPB(StopMessage)
|
|
276
|
+
log('received circuit v2 stop protocol request from %s', connection.remotePeer)
|
|
277
|
+
|
|
278
|
+
if (request?.type === undefined) {
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const stopstr = pbstr.pb(StopMessage)
|
|
283
|
+
log('new circuit relay v2 stop stream from %s', connection.remotePeer)
|
|
284
|
+
|
|
285
|
+
// Validate the STOP request has the required input
|
|
286
|
+
if (request.type !== StopMessage.Type.CONNECT) {
|
|
287
|
+
log.error('invalid stop connect request via peer %s', connection.remotePeer)
|
|
288
|
+
stopstr.write({ type: StopMessage.Type.STATUS, status: Status.UNEXPECTED_MESSAGE })
|
|
289
|
+
return
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (!isValidStop(request)) {
|
|
293
|
+
log.error('invalid stop connect request via peer %s', connection.remotePeer)
|
|
294
|
+
stopstr.write({ type: StopMessage.Type.STATUS, status: Status.MALFORMED_MESSAGE })
|
|
295
|
+
return
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const remotePeerId = peerIdFromBytes(request.peer.id)
|
|
299
|
+
|
|
300
|
+
if ((await this.connectionGater.denyInboundRelayedConnection?.(connection.remotePeer, remotePeerId)) === true) {
|
|
301
|
+
stopstr.write({ type: StopMessage.Type.STATUS, status: Status.PERMISSION_DENIED })
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
stopstr.write({ type: StopMessage.Type.STATUS, status: Status.OK })
|
|
306
|
+
|
|
307
|
+
const remoteAddr = connection.remoteAddr.encapsulate(`/p2p-circuit/p2p/${remotePeerId.toString()}`)
|
|
308
|
+
const localAddr = this.addressManager.getAddresses()[0]
|
|
309
|
+
const maConn = streamToMaConnection({
|
|
310
|
+
stream: pbstr.unwrap(),
|
|
311
|
+
remoteAddr,
|
|
312
|
+
localAddr
|
|
313
|
+
})
|
|
314
|
+
|
|
315
|
+
log('new inbound connection %s', maConn.remoteAddr)
|
|
316
|
+
await this.upgrader.upgradeInbound(maConn)
|
|
317
|
+
log('%s connection %s upgraded', 'inbound', maConn.remoteAddr)
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function circuitRelayTransport (init: CircuitRelayTransportInit = {}): (components: CircuitRelayTransportComponents) => Transport {
|
|
322
|
+
return (components) => {
|
|
323
|
+
return new CircuitRelayTransport(components, init)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
|
|
2
|
+
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
3
|
+
import type { Listener, ListenerEvents } from '@libp2p/interface-transport'
|
|
4
|
+
import type { Multiaddr } from '@multiformats/multiaddr'
|
|
5
|
+
import { multiaddr } from '@multiformats/multiaddr'
|
|
6
|
+
import type { ReservationStore } from './reservation-store'
|
|
7
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
8
|
+
import { PeerMap } from '@libp2p/peer-collections'
|
|
9
|
+
import { logger } from '@libp2p/logger'
|
|
10
|
+
|
|
11
|
+
const log = logger('libp2p:circuit-relay:transport:listener')
|
|
12
|
+
|
|
13
|
+
export interface CircuitRelayTransportListenerComponents {
|
|
14
|
+
connectionManager: ConnectionManager
|
|
15
|
+
relayStore: ReservationStore
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class CircuitRelayTransportListener extends EventEmitter<ListenerEvents> implements Listener {
|
|
19
|
+
private readonly connectionManager: ConnectionManager
|
|
20
|
+
private readonly relayStore: ReservationStore
|
|
21
|
+
private readonly listeningAddrs: PeerMap<Multiaddr>
|
|
22
|
+
|
|
23
|
+
constructor (components: CircuitRelayTransportListenerComponents) {
|
|
24
|
+
super()
|
|
25
|
+
|
|
26
|
+
this.connectionManager = components.connectionManager
|
|
27
|
+
this.relayStore = components.relayStore
|
|
28
|
+
this.listeningAddrs = new PeerMap()
|
|
29
|
+
|
|
30
|
+
// remove listening addrs when a relay is removed
|
|
31
|
+
this.relayStore.addEventListener('relay:removed', (evt) => {
|
|
32
|
+
this.#removeRelayPeer(evt.detail)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// remove listening addrs when a peer disconnects
|
|
36
|
+
this.connectionManager.addEventListener('peer:disconnect', (evt) => {
|
|
37
|
+
this.#removeRelayPeer(evt.detail.remotePeer)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async listen (addr: Multiaddr): Promise<void> {
|
|
42
|
+
log('listen on %s', addr)
|
|
43
|
+
|
|
44
|
+
const addrString = addr.toString().split('/p2p-circuit').find(a => a !== '')
|
|
45
|
+
const ma = multiaddr(addrString)
|
|
46
|
+
const relayConn = await this.connectionManager.openConnection(ma)
|
|
47
|
+
|
|
48
|
+
if (!this.relayStore.hasReservation(relayConn.remotePeer)) {
|
|
49
|
+
// addRelay calls transportManager.listen which calls this listen method
|
|
50
|
+
await this.relayStore.addRelay(relayConn.remotePeer, 'configured')
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (this.listeningAddrs.has(relayConn.remotePeer)) {
|
|
55
|
+
log('already listening on relay %p', relayConn.remotePeer)
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.listeningAddrs.set(relayConn.remotePeer, addr)
|
|
60
|
+
this.dispatchEvent(new CustomEvent('listening'))
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get fixed up multiaddrs
|
|
65
|
+
*
|
|
66
|
+
* NOTE: This method will grab the peers multiaddrs and expand them such that:
|
|
67
|
+
*
|
|
68
|
+
* a) If it's an existing /p2p-circuit address for a specific relay i.e.
|
|
69
|
+
* `/ip4/0.0.0.0/tcp/0/ipfs/QmRelay/p2p-circuit` this method will expand the
|
|
70
|
+
* address to `/ip4/0.0.0.0/tcp/0/ipfs/QmRelay/p2p-circuit/ipfs/QmPeer` where
|
|
71
|
+
* `QmPeer` is this peers id
|
|
72
|
+
* b) If it's not a /p2p-circuit address, it will encapsulate the address as a /p2p-circuit
|
|
73
|
+
* addr, such when dialing over a relay with this address, it will create the circuit using
|
|
74
|
+
* the encapsulated transport address. This is useful when for example, a peer should only
|
|
75
|
+
* be dialed over TCP rather than any other transport
|
|
76
|
+
*/
|
|
77
|
+
getAddrs (): Multiaddr[] {
|
|
78
|
+
return [...this.listeningAddrs.values()]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async close (): Promise<void> {
|
|
82
|
+
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#removeRelayPeer (peerId: PeerId): void {
|
|
86
|
+
const had = this.listeningAddrs.has(peerId)
|
|
87
|
+
|
|
88
|
+
this.listeningAddrs.delete(peerId)
|
|
89
|
+
|
|
90
|
+
if (had) {
|
|
91
|
+
// Announce listen addresses change
|
|
92
|
+
this.dispatchEvent(new CustomEvent('close'))
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function createListener (options: CircuitRelayTransportListenerComponents): Listener {
|
|
98
|
+
return new CircuitRelayTransportListener(options)
|
|
99
|
+
}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
2
|
+
import { PeerMap } from '@libp2p/peer-collections'
|
|
3
|
+
import PQueue from 'p-queue'
|
|
4
|
+
import { DEFAULT_RESERVATION_CONCURRENCY, RELAY_TAG, RELAY_V2_HOP_CODEC } from '../constants.js'
|
|
5
|
+
import { logger } from '@libp2p/logger'
|
|
6
|
+
import { pbStream } from 'it-pb-stream'
|
|
7
|
+
import type { ConnectionManager } from '@libp2p/interface-connection-manager'
|
|
8
|
+
import type { Connection } from '@libp2p/interface-connection'
|
|
9
|
+
import type { Reservation } from '../pb/index.js'
|
|
10
|
+
import { HopMessage, Status } from '../pb/index.js'
|
|
11
|
+
import { getExpiration } from '../utils.js'
|
|
12
|
+
import type { TransportManager } from '@libp2p/interface-transport'
|
|
13
|
+
import type { Startable } from '@libp2p/interfaces/dist/src/startable.js'
|
|
14
|
+
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
|
|
15
|
+
import type { PeerStore } from '@libp2p/interface-peer-store'
|
|
16
|
+
import { multiaddr } from '@multiformats/multiaddr'
|
|
17
|
+
|
|
18
|
+
const log = logger('libp2p:circuit-relay:transport:reservation-store')
|
|
19
|
+
|
|
20
|
+
// allow refreshing a relay reservation if it will expire in the next 10 minutes
|
|
21
|
+
const REFRESH_WINDOW = (60 * 1000) * 10
|
|
22
|
+
|
|
23
|
+
// try to refresh relay reservations 5 minutes before expiry
|
|
24
|
+
const REFRESH_TIMEOUT = (60 * 1000) * 5
|
|
25
|
+
|
|
26
|
+
export interface RelayStoreComponents {
|
|
27
|
+
peerId: PeerId
|
|
28
|
+
connectionManager: ConnectionManager
|
|
29
|
+
transportManager: TransportManager
|
|
30
|
+
peerStore: PeerStore
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface RelayStoreInit {
|
|
34
|
+
/**
|
|
35
|
+
* Multiple relays may be discovered simultaneously - to prevent listening
|
|
36
|
+
* on too many relays, this value controls how many to attempt to reserve a
|
|
37
|
+
* slot on at once. If set to more than one, we may end up listening on
|
|
38
|
+
* more relays than the `maxReservations` value, but on networks with poor
|
|
39
|
+
* connectivity the user may wish to attempt to reserve on multiple relays
|
|
40
|
+
* simultaneously. (default: 1)
|
|
41
|
+
*/
|
|
42
|
+
reservationConcurrency?: number
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* How many discovered relays to allow in the reservation store
|
|
46
|
+
*/
|
|
47
|
+
discoverRelays?: number
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type RelayType = 'discovered' | 'configured'
|
|
51
|
+
|
|
52
|
+
interface RelayEntry {
|
|
53
|
+
timeout: ReturnType<typeof setTimeout>
|
|
54
|
+
type: RelayType
|
|
55
|
+
reservation: Reservation
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ReservationStoreEvents {
|
|
59
|
+
'relay:not-enough-relays': CustomEvent
|
|
60
|
+
'relay:removed': CustomEvent<PeerId>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export class ReservationStore extends EventEmitter<ReservationStoreEvents> implements Startable {
|
|
64
|
+
private readonly peerId: PeerId
|
|
65
|
+
private readonly connectionManager: ConnectionManager
|
|
66
|
+
private readonly transportManager: TransportManager
|
|
67
|
+
private readonly peerStore: PeerStore
|
|
68
|
+
private readonly reserveQueue: PQueue
|
|
69
|
+
private readonly reservations: PeerMap<RelayEntry>
|
|
70
|
+
private readonly maxDiscoveredRelays: number
|
|
71
|
+
private started: boolean
|
|
72
|
+
|
|
73
|
+
constructor (components: RelayStoreComponents, init?: RelayStoreInit) {
|
|
74
|
+
super()
|
|
75
|
+
|
|
76
|
+
this.peerId = components.peerId
|
|
77
|
+
this.connectionManager = components.connectionManager
|
|
78
|
+
this.transportManager = components.transportManager
|
|
79
|
+
this.peerStore = components.peerStore
|
|
80
|
+
this.reservations = new PeerMap()
|
|
81
|
+
this.maxDiscoveredRelays = init?.discoverRelays ?? 0
|
|
82
|
+
this.started = false
|
|
83
|
+
|
|
84
|
+
// ensure we don't listen on multiple relays simultaneously
|
|
85
|
+
this.reserveQueue = new PQueue({
|
|
86
|
+
concurrency: init?.reservationConcurrency ?? DEFAULT_RESERVATION_CONCURRENCY
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// When a peer disconnects, if we had a reservation on that peer
|
|
90
|
+
// remove the reservation and multiaddr and maybe trigger search
|
|
91
|
+
// for new relays
|
|
92
|
+
this.connectionManager.addEventListener('peer:disconnect', (evt) => {
|
|
93
|
+
this.removeRelay(evt.detail.remotePeer)
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
isStarted (): boolean {
|
|
98
|
+
return this.started
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async start (): Promise<void> {
|
|
102
|
+
this.started = true
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async stop (): Promise<void> {
|
|
106
|
+
this.reservations.forEach(({ timeout }) => {
|
|
107
|
+
clearTimeout(timeout)
|
|
108
|
+
})
|
|
109
|
+
this.reservations.clear()
|
|
110
|
+
|
|
111
|
+
this.started = true
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* If the number of current relays is beneath the configured `maxReservations`
|
|
116
|
+
* value, and the passed peer id is not our own, and we have a non-relayed connection
|
|
117
|
+
* to the remote, and the remote peer speaks the hop protocol, try to reserve a slot
|
|
118
|
+
* on the remote peer
|
|
119
|
+
*/
|
|
120
|
+
async addRelay (peerId: PeerId, type: RelayType): Promise<void> {
|
|
121
|
+
log('add relay', this.reserveQueue.size)
|
|
122
|
+
|
|
123
|
+
await this.reserveQueue.add(async () => {
|
|
124
|
+
try {
|
|
125
|
+
if (this.peerId.equals(peerId)) {
|
|
126
|
+
log('not trying to use self as relay')
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// allow refresh of an existing reservation if it is about to expire
|
|
131
|
+
const existingReservation = this.reservations.get(peerId)
|
|
132
|
+
|
|
133
|
+
if (existingReservation != null) {
|
|
134
|
+
if (getExpiration(existingReservation.reservation.expire) > REFRESH_WINDOW) {
|
|
135
|
+
log('already have reservation on relay peer %p and it expires in more than 10 minutes', peerId)
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
clearTimeout(existingReservation.timeout)
|
|
140
|
+
this.reservations.delete(peerId)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (type === 'discovered' && [...this.reservations.values()].reduce((acc, curr) => {
|
|
144
|
+
if (curr.type === 'discovered') {
|
|
145
|
+
acc++
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return acc
|
|
149
|
+
}, 0) >= this.maxDiscoveredRelays) {
|
|
150
|
+
log('already have enough discovered relays')
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const connection = await this.connectionManager.openConnection(peerId)
|
|
155
|
+
|
|
156
|
+
if (connection.remoteAddr.protoNames().includes('p2p-circuit')) {
|
|
157
|
+
log('not creating reservation over relayed connection')
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const reservation = await this.#createReservation(connection)
|
|
162
|
+
|
|
163
|
+
log('created reservation on relay peer %p', peerId)
|
|
164
|
+
|
|
165
|
+
const expiration = getExpiration(reservation.expire)
|
|
166
|
+
|
|
167
|
+
const timeout = setTimeout(() => {
|
|
168
|
+
this.addRelay(peerId, type).catch(err => {
|
|
169
|
+
log.error('could not refresh reservation to relay %p', peerId, err)
|
|
170
|
+
})
|
|
171
|
+
}, Math.max(expiration - REFRESH_TIMEOUT, 0))
|
|
172
|
+
|
|
173
|
+
this.reservations.set(peerId, {
|
|
174
|
+
timeout,
|
|
175
|
+
reservation,
|
|
176
|
+
type
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// ensure we don't close the connection to the relay
|
|
180
|
+
await this.peerStore.tagPeer(peerId, RELAY_TAG, {
|
|
181
|
+
value: 1,
|
|
182
|
+
ttl: expiration
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
await this.transportManager.listen(
|
|
186
|
+
reservation.addrs.map(ma => {
|
|
187
|
+
return multiaddr(ma).encapsulate('/p2p-circuit')
|
|
188
|
+
})
|
|
189
|
+
)
|
|
190
|
+
} catch (err) {
|
|
191
|
+
log.error('could not reserve slot on %p', peerId, err)
|
|
192
|
+
}
|
|
193
|
+
})
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
hasReservation (peerId: PeerId): boolean {
|
|
197
|
+
return this.reservations.has(peerId)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async #createReservation (connection: Connection): Promise<Reservation> {
|
|
201
|
+
log('requesting reservation from %s', connection.remotePeer)
|
|
202
|
+
const stream = await connection.newStream(RELAY_V2_HOP_CODEC)
|
|
203
|
+
const pbstr = pbStream(stream)
|
|
204
|
+
const hopstr = pbstr.pb(HopMessage)
|
|
205
|
+
hopstr.write({ type: HopMessage.Type.RESERVE })
|
|
206
|
+
|
|
207
|
+
let response: HopMessage
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
response = await hopstr.read()
|
|
211
|
+
} catch (err: any) {
|
|
212
|
+
log.error('error parsing reserve message response from %s because', connection.remotePeer, err.message)
|
|
213
|
+
throw err
|
|
214
|
+
} finally {
|
|
215
|
+
stream.close()
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (response.status === Status.OK && (response.reservation != null)) {
|
|
219
|
+
return response.reservation
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const errMsg = `reservation failed with status ${response.status ?? 'undefined'}`
|
|
223
|
+
log.error(errMsg)
|
|
224
|
+
|
|
225
|
+
throw new Error(errMsg)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Remove listen relay
|
|
230
|
+
*/
|
|
231
|
+
removeRelay (peerId: PeerId): void {
|
|
232
|
+
const existingReservation = this.reservations.get(peerId)
|
|
233
|
+
|
|
234
|
+
if (existingReservation == null) {
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
log('removing relay %p', peerId)
|
|
239
|
+
|
|
240
|
+
clearTimeout(existingReservation.timeout)
|
|
241
|
+
this.reservations.delete(peerId)
|
|
242
|
+
|
|
243
|
+
this.safeDispatchEvent('relay:removed', { detail: peerId })
|
|
244
|
+
|
|
245
|
+
if (this.reservations.size < this.maxDiscoveredRelays) {
|
|
246
|
+
this.dispatchEvent(new CustomEvent('relay:not-enough-relays'))
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|