libp2p 2.1.3 → 2.1.4-58784abf7
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 +10 -10
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +1 -3
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection/index.d.ts.map +1 -1
- package/dist/src/connection/index.js +4 -6
- package/dist/src/connection/index.js.map +1 -1
- package/dist/src/connection-manager/address-sorter.d.ts +25 -0
- package/dist/src/connection-manager/address-sorter.d.ts.map +1 -0
- package/dist/src/connection-manager/address-sorter.js +112 -0
- package/dist/src/connection-manager/address-sorter.js.map +1 -0
- package/dist/src/connection-manager/connection-pruner.d.ts +4 -1
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
- package/dist/src/connection-manager/connection-pruner.js +13 -7
- package/dist/src/connection-manager/connection-pruner.js.map +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts +1 -1
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
- package/dist/src/connection-manager/dial-queue.js +4 -5
- package/dist/src/connection-manager/dial-queue.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +1 -1
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +79 -80
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +23 -21
- package/dist/src/upgrader.js.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/package.json +17 -17
- package/src/config.ts +1 -3
- package/src/connection/index.ts +5 -11
- package/src/connection-manager/address-sorter.ts +137 -0
- package/src/connection-manager/connection-pruner.ts +16 -8
- package/src/connection-manager/dial-queue.ts +5 -6
- package/src/connection-manager/index.ts +90 -83
- package/src/upgrader.ts +25 -16
- package/src/version.ts +1 -1
- package/dist/typedoc-urls.json +0 -19
package/src/connection/index.ts
CHANGED
|
@@ -161,13 +161,6 @@ export class ConnectionImpl implements Connection {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
try {
|
|
164
|
-
this.log.trace('closing all streams')
|
|
165
|
-
|
|
166
|
-
// close all streams gracefully - this can throw if we're not multiplexed
|
|
167
|
-
await Promise.all(
|
|
168
|
-
this.streams.map(async s => s.close(options))
|
|
169
|
-
)
|
|
170
|
-
|
|
171
164
|
this.log.trace('closing underlying transport')
|
|
172
165
|
|
|
173
166
|
// close raw connection
|
|
@@ -184,18 +177,19 @@ export class ConnectionImpl implements Connection {
|
|
|
184
177
|
}
|
|
185
178
|
|
|
186
179
|
abort (err: Error): void {
|
|
180
|
+
if (this.status === 'closed') {
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
187
184
|
this.log.error('aborting connection to %a due to error', this.remoteAddr, err)
|
|
188
185
|
|
|
189
186
|
this.status = 'closing'
|
|
190
|
-
this.streams.forEach(s => { s.abort(err) })
|
|
191
|
-
|
|
192
|
-
this.log.error('all streams aborted', this.streams.length)
|
|
193
187
|
|
|
194
188
|
// Abort raw connection
|
|
195
189
|
this._abort(err)
|
|
196
190
|
|
|
197
|
-
this.timeline.close = Date.now()
|
|
198
191
|
this.status = 'closed'
|
|
192
|
+
this.timeline.close = Date.now()
|
|
199
193
|
}
|
|
200
194
|
}
|
|
201
195
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
|
|
2
|
+
import { Circuit, WebSockets, WebSocketsSecure, WebRTC, WebRTCDirect, WebTransport, TCP } from '@multiformats/multiaddr-matcher'
|
|
3
|
+
import type { Address } from '@libp2p/interface'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sorts addresses by order of reliability, where they have presented the fewest
|
|
7
|
+
* problems:
|
|
8
|
+
*
|
|
9
|
+
* TCP -> WebSockets/Secure -> WebRTC -> WebRTCDirect -> WebTransport
|
|
10
|
+
*/
|
|
11
|
+
// eslint-disable-next-line complexity
|
|
12
|
+
export function reliableTransportsFirst (a: Address, b: Address): -1 | 0 | 1 {
|
|
13
|
+
const isATCP = TCP.exactMatch(a.multiaddr)
|
|
14
|
+
const isBTCP = TCP.exactMatch(b.multiaddr)
|
|
15
|
+
|
|
16
|
+
if (isATCP && !isBTCP) {
|
|
17
|
+
return -1
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (!isATCP && isBTCP) {
|
|
21
|
+
return 1
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const isAWebSocketSecure = WebSocketsSecure.exactMatch(a.multiaddr)
|
|
25
|
+
const isBWebSocketSecure = WebSocketsSecure.exactMatch(b.multiaddr)
|
|
26
|
+
|
|
27
|
+
if (isAWebSocketSecure && !isBWebSocketSecure) {
|
|
28
|
+
return -1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!isAWebSocketSecure && isBWebSocketSecure) {
|
|
32
|
+
return 1
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const isAWebSocket = WebSockets.exactMatch(a.multiaddr)
|
|
36
|
+
const isBWebSocket = WebSockets.exactMatch(b.multiaddr)
|
|
37
|
+
|
|
38
|
+
if (isAWebSocket && !isBWebSocket) {
|
|
39
|
+
return -1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!isAWebSocket && isBWebSocket) {
|
|
43
|
+
return 1
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const isAWebRTC = WebRTC.exactMatch(a.multiaddr)
|
|
47
|
+
const isBWebRTC = WebRTC.exactMatch(b.multiaddr)
|
|
48
|
+
|
|
49
|
+
if (isAWebRTC && !isBWebRTC) {
|
|
50
|
+
return -1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (!isAWebRTC && isBWebRTC) {
|
|
54
|
+
return 1
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const isAWebRTCDirect = WebRTCDirect.exactMatch(a.multiaddr)
|
|
58
|
+
const isBWebRTCDirect = WebRTCDirect.exactMatch(b.multiaddr)
|
|
59
|
+
|
|
60
|
+
if (isAWebRTCDirect && !isBWebRTCDirect) {
|
|
61
|
+
return -1
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!isAWebRTCDirect && isBWebRTCDirect) {
|
|
65
|
+
return 1
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const isAWebTransport = WebTransport.exactMatch(a.multiaddr)
|
|
69
|
+
const isBWebTransport = WebTransport.exactMatch(b.multiaddr)
|
|
70
|
+
|
|
71
|
+
if (isAWebTransport && !isBWebTransport) {
|
|
72
|
+
return -1
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!isAWebTransport && isBWebTransport) {
|
|
76
|
+
return 1
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ... everything else
|
|
80
|
+
return 0
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Compare function for array.sort() that moves public addresses to the start
|
|
85
|
+
* of the array.
|
|
86
|
+
*/
|
|
87
|
+
export function publicAddressesFirst (a: Address, b: Address): -1 | 0 | 1 {
|
|
88
|
+
const isAPrivate = isPrivate(a.multiaddr)
|
|
89
|
+
const isBPrivate = isPrivate(b.multiaddr)
|
|
90
|
+
|
|
91
|
+
if (isAPrivate && !isBPrivate) {
|
|
92
|
+
return 1
|
|
93
|
+
} else if (!isAPrivate && isBPrivate) {
|
|
94
|
+
return -1
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return 0
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Compare function for array.sort() that moves certified addresses to the start
|
|
102
|
+
* of the array.
|
|
103
|
+
*/
|
|
104
|
+
export function certifiedAddressesFirst (a: Address, b: Address): -1 | 0 | 1 {
|
|
105
|
+
if (a.isCertified && !b.isCertified) {
|
|
106
|
+
return -1
|
|
107
|
+
} else if (!a.isCertified && b.isCertified) {
|
|
108
|
+
return 1
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return 0
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Compare function for array.sort() that moves circuit relay addresses to the
|
|
116
|
+
* end of the array.
|
|
117
|
+
*/
|
|
118
|
+
export function circuitRelayAddressesLast (a: Address, b: Address): -1 | 0 | 1 {
|
|
119
|
+
const isACircuit = Circuit.exactMatch(a.multiaddr)
|
|
120
|
+
const isBCircuit = Circuit.exactMatch(b.multiaddr)
|
|
121
|
+
|
|
122
|
+
if (isACircuit && !isBCircuit) {
|
|
123
|
+
return 1
|
|
124
|
+
} else if (!isACircuit && isBCircuit) {
|
|
125
|
+
return -1
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return 0
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function defaultAddressSorter (addresses: Address[]): Address[] {
|
|
132
|
+
return addresses
|
|
133
|
+
.sort(reliableTransportsFirst)
|
|
134
|
+
.sort(certifiedAddressesFirst)
|
|
135
|
+
.sort(circuitRelayAddressesLast)
|
|
136
|
+
.sort(publicAddressesFirst)
|
|
137
|
+
}
|
|
@@ -40,21 +40,29 @@ export class ConnectionPruner {
|
|
|
40
40
|
this.peerStore = components.peerStore
|
|
41
41
|
this.events = components.events
|
|
42
42
|
this.log = components.logger.forComponent('libp2p:connection-manager:connection-pruner')
|
|
43
|
+
this.maybePruneConnections = this.maybePruneConnections.bind(this)
|
|
44
|
+
}
|
|
43
45
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
start (): void {
|
|
47
|
+
this.events.addEventListener('connection:open', this.maybePruneConnections)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
stop (): void {
|
|
51
|
+
this.events.removeEventListener('connection:open', this.maybePruneConnections)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
maybePruneConnections (): void {
|
|
55
|
+
this._maybePruneConnections()
|
|
56
|
+
.catch(err => {
|
|
57
|
+
this.log.error('error while pruning connections %e', err)
|
|
58
|
+
})
|
|
51
59
|
}
|
|
52
60
|
|
|
53
61
|
/**
|
|
54
62
|
* If we have more connections than our maximum, select some excess connections
|
|
55
63
|
* to prune based on peer value
|
|
56
64
|
*/
|
|
57
|
-
async
|
|
65
|
+
private async _maybePruneConnections (): Promise<void> {
|
|
58
66
|
const connections = this.connectionManager.getConnections()
|
|
59
67
|
const numConnections = connections.length
|
|
60
68
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* eslint-disable max-depth */
|
|
2
2
|
import { TimeoutError, DialError, setMaxListeners, AbortError } from '@libp2p/interface'
|
|
3
3
|
import { PeerMap } from '@libp2p/peer-collections'
|
|
4
|
-
import { defaultAddressSort } from '@libp2p/utils/address-sort'
|
|
5
4
|
import { PriorityQueue, type PriorityQueueJobOptions } from '@libp2p/utils/priority-queue'
|
|
6
5
|
import { type Multiaddr, type Resolver, resolvers, multiaddr } from '@multiformats/multiaddr'
|
|
7
6
|
import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
|
|
@@ -11,6 +10,7 @@ import { CustomProgressEvent } from 'progress-events'
|
|
|
11
10
|
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
|
|
12
11
|
import { DialDeniedError, NoValidAddressesError } from '../errors.js'
|
|
13
12
|
import { getPeerAddress } from '../get-peer.js'
|
|
13
|
+
import { defaultAddressSorter } from './address-sorter.js'
|
|
14
14
|
import {
|
|
15
15
|
DIAL_TIMEOUT,
|
|
16
16
|
MAX_PARALLEL_DIALS,
|
|
@@ -47,7 +47,6 @@ interface DialerInit {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const defaultOptions = {
|
|
50
|
-
addressSorter: defaultAddressSort,
|
|
51
50
|
maxParallelDials: MAX_PARALLEL_DIALS,
|
|
52
51
|
maxDialQueueLength: MAX_DIAL_QUEUE_LENGTH,
|
|
53
52
|
maxPeerAddrsToDial: MAX_PEER_ADDRS_TO_DIAL,
|
|
@@ -71,7 +70,7 @@ interface DialQueueComponents {
|
|
|
71
70
|
export class DialQueue {
|
|
72
71
|
public queue: PriorityQueue<Connection, DialQueueJobOptions>
|
|
73
72
|
private readonly components: DialQueueComponents
|
|
74
|
-
private readonly addressSorter
|
|
73
|
+
private readonly addressSorter?: AddressSorter
|
|
75
74
|
private readonly maxPeerAddrsToDial: number
|
|
76
75
|
private readonly maxDialQueueLength: number
|
|
77
76
|
private readonly dialTimeout: number
|
|
@@ -80,7 +79,7 @@ export class DialQueue {
|
|
|
80
79
|
private readonly log: Logger
|
|
81
80
|
|
|
82
81
|
constructor (components: DialQueueComponents, init: DialerInit = {}) {
|
|
83
|
-
this.addressSorter = init.addressSorter
|
|
82
|
+
this.addressSorter = init.addressSorter
|
|
84
83
|
this.maxPeerAddrsToDial = init.maxPeerAddrsToDial ?? defaultOptions.maxPeerAddrsToDial
|
|
85
84
|
this.maxDialQueueLength = init.maxDialQueueLength ?? defaultOptions.maxDialQueueLength
|
|
86
85
|
this.dialTimeout = init.dialTimeout ?? defaultOptions.dialTimeout
|
|
@@ -153,7 +152,7 @@ export class DialQueue {
|
|
|
153
152
|
})
|
|
154
153
|
})
|
|
155
154
|
|
|
156
|
-
if (existingConnection
|
|
155
|
+
if (existingConnection?.status === 'open') {
|
|
157
156
|
this.log('already connected to %a', existingConnection.remoteAddr)
|
|
158
157
|
options.onProgress?.(new CustomProgressEvent('dial-queue:already-connected'))
|
|
159
158
|
return existingConnection
|
|
@@ -467,7 +466,7 @@ export class DialQueue {
|
|
|
467
466
|
gatedAdrs.push(addr)
|
|
468
467
|
}
|
|
469
468
|
|
|
470
|
-
const sortedGatedAddrs = gatedAdrs.sort(this.addressSorter)
|
|
469
|
+
const sortedGatedAddrs = this.addressSorter == null ? defaultAddressSorter(gatedAdrs) : gatedAdrs.sort(this.addressSorter)
|
|
471
470
|
|
|
472
471
|
// make sure we actually have some addresses to dial
|
|
473
472
|
if (sortedGatedAddrs.length === 0) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { InvalidMultiaddrError, InvalidParametersError, InvalidPeerIdError, NotStartedError, start, stop } from '@libp2p/interface'
|
|
1
|
+
import { ConnectionClosedError, InvalidMultiaddrError, InvalidParametersError, InvalidPeerIdError, NotStartedError, start, stop } from '@libp2p/interface'
|
|
2
2
|
import { PeerMap } from '@libp2p/peer-collections'
|
|
3
|
-
import { defaultAddressSort } from '@libp2p/utils/address-sort'
|
|
4
3
|
import { RateLimiter } from '@libp2p/utils/rate-limiter'
|
|
5
4
|
import { type Multiaddr, type Resolver, multiaddr } from '@multiformats/multiaddr'
|
|
6
5
|
import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
|
|
@@ -181,6 +180,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
181
180
|
private readonly deny: Multiaddr[]
|
|
182
181
|
private readonly maxIncomingPendingConnections: number
|
|
183
182
|
private incomingPendingConnections: number
|
|
183
|
+
private outboundPendingConnections: number
|
|
184
184
|
private readonly maxConnections: number
|
|
185
185
|
|
|
186
186
|
public readonly dialQueue: DialQueue
|
|
@@ -214,8 +214,6 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
214
214
|
|
|
215
215
|
this.onConnect = this.onConnect.bind(this)
|
|
216
216
|
this.onDisconnect = this.onDisconnect.bind(this)
|
|
217
|
-
this.events.addEventListener('connection:open', this.onConnect)
|
|
218
|
-
this.events.addEventListener('connection:close', this.onDisconnect)
|
|
219
217
|
|
|
220
218
|
// allow/deny lists
|
|
221
219
|
this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
|
|
@@ -223,6 +221,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
223
221
|
|
|
224
222
|
this.incomingPendingConnections = 0
|
|
225
223
|
this.maxIncomingPendingConnections = init.maxIncomingPendingConnections ?? defaultOptions.maxIncomingPendingConnections
|
|
224
|
+
this.outboundPendingConnections = 0
|
|
226
225
|
|
|
227
226
|
// controls individual peers trying to dial us too quickly
|
|
228
227
|
this.inboundConnectionRateLimiter = new RateLimiter({
|
|
@@ -242,7 +241,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
242
241
|
})
|
|
243
242
|
|
|
244
243
|
this.dialQueue = new DialQueue(components, {
|
|
245
|
-
addressSorter: init.addressSorter
|
|
244
|
+
addressSorter: init.addressSorter,
|
|
246
245
|
maxParallelDials: init.maxParallelDials ?? MAX_PARALLEL_DIALS,
|
|
247
246
|
maxDialQueueLength: init.maxDialQueueLength ?? MAX_DIAL_QUEUE_LENGTH,
|
|
248
247
|
maxPeerAddrsToDial: init.maxPeerAddrsToDial ?? MAX_PEER_ADDRS_TO_DIAL,
|
|
@@ -268,10 +267,6 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
268
267
|
|
|
269
268
|
readonly [Symbol.toStringTag] = '@libp2p/connection-manager'
|
|
270
269
|
|
|
271
|
-
isStarted (): boolean {
|
|
272
|
-
return this.started
|
|
273
|
-
}
|
|
274
|
-
|
|
275
270
|
/**
|
|
276
271
|
* Starts the Connection Manager. If Metrics are not enabled on libp2p
|
|
277
272
|
* only event loop and connection limits will be monitored.
|
|
@@ -283,16 +278,13 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
283
278
|
const metric = {
|
|
284
279
|
inbound: 0,
|
|
285
280
|
'inbound pending': this.incomingPendingConnections,
|
|
286
|
-
outbound: 0
|
|
281
|
+
outbound: 0,
|
|
282
|
+
'outbound pending': this.outboundPendingConnections
|
|
287
283
|
}
|
|
288
284
|
|
|
289
285
|
for (const conns of this.connections.values()) {
|
|
290
286
|
for (const conn of conns) {
|
|
291
|
-
|
|
292
|
-
metric.inbound++
|
|
293
|
-
} else {
|
|
294
|
-
metric.outbound++
|
|
295
|
-
}
|
|
287
|
+
metric[conn.direction]++
|
|
296
288
|
}
|
|
297
289
|
}
|
|
298
290
|
|
|
@@ -356,9 +348,13 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
356
348
|
}
|
|
357
349
|
})
|
|
358
350
|
|
|
351
|
+
this.events.addEventListener('connection:open', this.onConnect)
|
|
352
|
+
this.events.addEventListener('connection:close', this.onDisconnect)
|
|
353
|
+
|
|
359
354
|
await start(
|
|
360
355
|
this.dialQueue,
|
|
361
|
-
this.reconnectQueue
|
|
356
|
+
this.reconnectQueue,
|
|
357
|
+
this.connectionPruner
|
|
362
358
|
)
|
|
363
359
|
|
|
364
360
|
this.started = true
|
|
@@ -369,9 +365,13 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
369
365
|
* Stops the Connection Manager
|
|
370
366
|
*/
|
|
371
367
|
async stop (): Promise<void> {
|
|
368
|
+
this.events.removeEventListener('connection:open', this.onConnect)
|
|
369
|
+
this.events.removeEventListener('connection:close', this.onDisconnect)
|
|
370
|
+
|
|
372
371
|
await stop(
|
|
373
372
|
this.reconnectQueue,
|
|
374
|
-
this.dialQueue
|
|
373
|
+
this.dialQueue,
|
|
374
|
+
this.connectionPruner
|
|
375
375
|
)
|
|
376
376
|
|
|
377
377
|
// Close all connections we're tracking
|
|
@@ -413,17 +413,19 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
413
413
|
return
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
if (storedConns != null) {
|
|
421
|
-
storedConns.push(connection)
|
|
422
|
-
} else {
|
|
423
|
-
isNewPeer = true
|
|
424
|
-
this.connections.set(peerId, [connection])
|
|
416
|
+
if (connection.status !== 'open') {
|
|
417
|
+
// this can happen when the remote closes the connection immediately after
|
|
418
|
+
// opening
|
|
419
|
+
return
|
|
425
420
|
}
|
|
426
421
|
|
|
422
|
+
const peerId = connection.remotePeer
|
|
423
|
+
const isNewPeer = !this.connections.has(peerId)
|
|
424
|
+
const storedConns = this.connections.get(peerId) ?? []
|
|
425
|
+
storedConns.push(connection)
|
|
426
|
+
|
|
427
|
+
this.connections.set(peerId, storedConns)
|
|
428
|
+
|
|
427
429
|
// only need to store RSA public keys, all other types are embedded in the peer id
|
|
428
430
|
if (peerId.publicKey != null && peerId.type === 'RSA') {
|
|
429
431
|
await this.peerStore.patch(peerId, {
|
|
@@ -441,20 +443,21 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
441
443
|
*/
|
|
442
444
|
onDisconnect (evt: CustomEvent<Connection>): void {
|
|
443
445
|
const { detail: connection } = evt
|
|
446
|
+
const peerId = connection.remotePeer
|
|
447
|
+
const peerConns = this.connections.get(peerId) ?? []
|
|
444
448
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
return
|
|
448
|
-
}
|
|
449
|
+
// remove closed connection
|
|
450
|
+
const filteredPeerConns = peerConns.filter(conn => conn.id !== connection.id)
|
|
449
451
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
+
// update peer connections
|
|
453
|
+
this.connections.set(peerId, filteredPeerConns)
|
|
452
454
|
|
|
453
|
-
if (
|
|
454
|
-
|
|
455
|
-
this.connections
|
|
456
|
-
} else if (storedConn != null) {
|
|
455
|
+
if (filteredPeerConns.length === 0) {
|
|
456
|
+
// trigger disconnect event if no connections remain
|
|
457
|
+
this.log('onDisconnect remove all connections for peer %p', peerId)
|
|
457
458
|
this.connections.delete(peerId)
|
|
459
|
+
|
|
460
|
+
// broadcast disconnect event
|
|
458
461
|
this.events.safeDispatchEvent('peer:disconnect', { detail: connection.remotePeer })
|
|
459
462
|
}
|
|
460
463
|
}
|
|
@@ -478,73 +481,77 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
|
|
|
478
481
|
}
|
|
479
482
|
|
|
480
483
|
async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise<Connection> {
|
|
481
|
-
if (!this.
|
|
484
|
+
if (!this.started) {
|
|
482
485
|
throw new NotStartedError('Not started')
|
|
483
486
|
}
|
|
484
487
|
|
|
485
|
-
|
|
488
|
+
this.outboundPendingConnections++
|
|
486
489
|
|
|
487
|
-
|
|
490
|
+
try {
|
|
491
|
+
options.signal?.throwIfAborted()
|
|
488
492
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
493
|
+
const { peerId } = getPeerAddress(peerIdOrMultiaddr)
|
|
494
|
+
|
|
495
|
+
if (this.peerId.equals(peerId)) {
|
|
496
|
+
throw new InvalidPeerIdError('Can not dial self')
|
|
497
|
+
}
|
|
492
498
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
499
|
+
if (peerId != null && options.force !== true) {
|
|
500
|
+
this.log('dial %p', peerId)
|
|
501
|
+
const existingConnection = this.getConnections(peerId)
|
|
502
|
+
.find(conn => conn.limits == null)
|
|
497
503
|
|
|
498
|
-
|
|
499
|
-
|
|
504
|
+
if (existingConnection != null) {
|
|
505
|
+
this.log('had an existing non-limited connection to %p', peerId)
|
|
500
506
|
|
|
501
|
-
|
|
502
|
-
|
|
507
|
+
options.onProgress?.(new CustomProgressEvent('dial-queue:already-connected'))
|
|
508
|
+
return existingConnection
|
|
509
|
+
}
|
|
503
510
|
}
|
|
504
|
-
}
|
|
505
511
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
512
|
+
const connection = await this.dialQueue.dial(peerIdOrMultiaddr, {
|
|
513
|
+
...options,
|
|
514
|
+
priority: options.priority ?? DEFAULT_DIAL_PRIORITY
|
|
515
|
+
})
|
|
510
516
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
throw err
|
|
515
|
-
}
|
|
517
|
+
if (connection.status !== 'open') {
|
|
518
|
+
throw new ConnectionClosedError('Remote closed connection during opening')
|
|
519
|
+
}
|
|
516
520
|
|
|
517
|
-
|
|
521
|
+
let peerConnections = this.connections.get(connection.remotePeer)
|
|
518
522
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
+
if (peerConnections == null) {
|
|
524
|
+
peerConnections = []
|
|
525
|
+
this.connections.set(connection.remotePeer, peerConnections)
|
|
526
|
+
}
|
|
523
527
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
+
// we get notified of connections via the Upgrader emitting "connection"
|
|
529
|
+
// events, double check we aren't already tracking this connection before
|
|
530
|
+
// storing it
|
|
531
|
+
let trackedConnection = false
|
|
528
532
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
+
for (const conn of peerConnections) {
|
|
534
|
+
if (conn.id === connection.id) {
|
|
535
|
+
trackedConnection = true
|
|
536
|
+
}
|
|
533
537
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
538
|
+
// make sure we don't already have a connection to this multiaddr
|
|
539
|
+
if (options.force !== true && conn.id !== connection.id && conn.remoteAddr.equals(connection.remoteAddr)) {
|
|
540
|
+
connection.abort(new InvalidMultiaddrError('Duplicate multiaddr connection'))
|
|
537
541
|
|
|
538
|
-
|
|
539
|
-
|
|
542
|
+
// return the existing connection
|
|
543
|
+
return conn
|
|
544
|
+
}
|
|
540
545
|
}
|
|
541
|
-
}
|
|
542
546
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
547
|
+
if (!trackedConnection) {
|
|
548
|
+
peerConnections.push(connection)
|
|
549
|
+
}
|
|
546
550
|
|
|
547
|
-
|
|
551
|
+
return connection
|
|
552
|
+
} finally {
|
|
553
|
+
this.outboundPendingConnections--
|
|
554
|
+
}
|
|
548
555
|
}
|
|
549
556
|
|
|
550
557
|
async closeConnections (peerId: PeerId, options: AbortOptions = {}): Promise<void> {
|
package/src/upgrader.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { InvalidMultiaddrError, TooManyInboundProtocolStreamsError, TooManyOutboundProtocolStreamsError, LimitedConnectionError, setMaxListeners } from '@libp2p/interface'
|
|
1
|
+
import { InvalidMultiaddrError, TooManyInboundProtocolStreamsError, TooManyOutboundProtocolStreamsError, LimitedConnectionError, setMaxListeners, InvalidPeerIdError } from '@libp2p/interface'
|
|
2
2
|
import * as mss from '@libp2p/multistream-select'
|
|
3
3
|
import { peerIdFromString } from '@libp2p/peer-id'
|
|
4
4
|
import { anySignal } from 'any-signal'
|
|
@@ -304,6 +304,14 @@ export class DefaultUpgrader implements Upgrader {
|
|
|
304
304
|
remotePeer = remotePeerId
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
+
// this can happen if we dial a multiaddr without a peer id, we only find
|
|
308
|
+
// out the identity of the remote after the connection is encrypted
|
|
309
|
+
if (remotePeer.equals(this.components.peerId)) {
|
|
310
|
+
const err = new InvalidPeerIdError('Can not dial self')
|
|
311
|
+
maConn.abort(err)
|
|
312
|
+
throw err
|
|
313
|
+
}
|
|
314
|
+
|
|
307
315
|
upgradedConn = encryptedConn
|
|
308
316
|
if (opts?.muxerFactory != null) {
|
|
309
317
|
muxerFactory = opts.muxerFactory
|
|
@@ -326,6 +334,8 @@ export class DefaultUpgrader implements Upgrader {
|
|
|
326
334
|
} catch (err: any) {
|
|
327
335
|
maConn.log.error('failed to upgrade inbound connection %s %a - %e', direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err)
|
|
328
336
|
throw err
|
|
337
|
+
} finally {
|
|
338
|
+
signal.clear()
|
|
329
339
|
}
|
|
330
340
|
|
|
331
341
|
await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn)
|
|
@@ -538,7 +548,7 @@ export class DefaultUpgrader implements Upgrader {
|
|
|
538
548
|
const _timeline = maConn.timeline
|
|
539
549
|
maConn.timeline = new Proxy(_timeline, {
|
|
540
550
|
set: (...args) => {
|
|
541
|
-
if (
|
|
551
|
+
if (args[1] === 'close' && args[2] != null && _timeline.close == null) {
|
|
542
552
|
// Wait for close to finish before notifying of the closure
|
|
543
553
|
(async () => {
|
|
544
554
|
try {
|
|
@@ -546,14 +556,14 @@ export class DefaultUpgrader implements Upgrader {
|
|
|
546
556
|
await connection.close()
|
|
547
557
|
}
|
|
548
558
|
} catch (err: any) {
|
|
549
|
-
connection.log.error('error closing connection after timeline close', err)
|
|
559
|
+
connection.log.error('error closing connection after timeline close %e', err)
|
|
550
560
|
} finally {
|
|
551
561
|
this.events.safeDispatchEvent('connection:close', {
|
|
552
562
|
detail: connection
|
|
553
563
|
})
|
|
554
564
|
}
|
|
555
565
|
})().catch(err => {
|
|
556
|
-
connection.log.error('error thrown while dispatching connection:close event', err)
|
|
566
|
+
connection.log.error('error thrown while dispatching connection:close event %e', err)
|
|
557
567
|
})
|
|
558
568
|
}
|
|
559
569
|
|
|
@@ -578,25 +588,21 @@ export class DefaultUpgrader implements Upgrader {
|
|
|
578
588
|
limits,
|
|
579
589
|
logger: this.components.logger,
|
|
580
590
|
newStream: newStream ?? errConnectionNotMultiplexed,
|
|
581
|
-
getStreams: () => {
|
|
591
|
+
getStreams: () => {
|
|
592
|
+
return muxer?.streams ?? []
|
|
593
|
+
},
|
|
582
594
|
close: async (options?: AbortOptions) => {
|
|
583
|
-
//
|
|
584
|
-
|
|
585
|
-
connection.log.trace('close muxer')
|
|
586
|
-
await muxer.close(options)
|
|
587
|
-
}
|
|
595
|
+
// ensure remaining streams are closed gracefully
|
|
596
|
+
await muxer?.close(options)
|
|
588
597
|
|
|
589
|
-
connection.log.trace('close maconn')
|
|
590
598
|
// close the underlying transport
|
|
591
599
|
await maConn.close(options)
|
|
592
|
-
connection.log.trace('closed maconn')
|
|
593
600
|
},
|
|
594
601
|
abort: (err) => {
|
|
595
602
|
maConn.abort(err)
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
603
|
+
|
|
604
|
+
// ensure remaining streams are aborted
|
|
605
|
+
muxer?.abort(err)
|
|
600
606
|
}
|
|
601
607
|
})
|
|
602
608
|
|
|
@@ -604,6 +610,9 @@ export class DefaultUpgrader implements Upgrader {
|
|
|
604
610
|
detail: connection
|
|
605
611
|
})
|
|
606
612
|
|
|
613
|
+
// @ts-expect-error nah
|
|
614
|
+
connection.__maConnTimeline = _timeline
|
|
615
|
+
|
|
607
616
|
return connection
|
|
608
617
|
}
|
|
609
618
|
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '2.1.
|
|
1
|
+
export const version = '2.1.4-58784abf7'
|
|
2
2
|
export const name = 'libp2p'
|