libp2p 0.43.4 → 0.44.0
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/autonat/index.d.ts +1 -2
- package/dist/src/autonat/index.d.ts.map +1 -1
- package/dist/src/autonat/index.js +4 -6
- package/dist/src/autonat/index.js.map +1 -1
- package/dist/src/circuit-relay/transport/reservation-store.d.ts +1 -1
- package/dist/src/circuit-relay/transport/reservation-store.d.ts.map +1 -1
- package/dist/src/circuit-relay/utils.d.ts.map +1 -1
- package/dist/src/circuit-relay/utils.js +3 -1
- package/dist/src/circuit-relay/utils.js.map +1 -1
- package/dist/src/components.d.ts +1 -6
- package/dist/src/components.d.ts.map +1 -1
- package/dist/src/components.js +0 -10
- package/dist/src/components.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +0 -9
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/auto-dial.d.ts +36 -0
- package/dist/src/connection-manager/auto-dial.d.ts.map +1 -0
- package/dist/src/connection-manager/auto-dial.js +122 -0
- package/dist/src/connection-manager/auto-dial.js.map +1 -0
- package/dist/src/connection-manager/connection-pruner.d.ts +28 -0
- package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -0
- package/dist/src/connection-manager/connection-pruner.js +96 -0
- package/dist/src/connection-manager/connection-pruner.js.map +1 -0
- package/dist/src/connection-manager/constants.d.ts +49 -0
- package/dist/src/connection-manager/constants.d.ts.map +1 -0
- package/dist/src/connection-manager/constants.js +49 -0
- package/dist/src/connection-manager/constants.js.map +1 -0
- package/dist/src/connection-manager/dial-queue.d.ts +77 -0
- package/dist/src/connection-manager/dial-queue.d.ts.map +1 -0
- package/dist/src/connection-manager/dial-queue.js +366 -0
- package/dist/src/connection-manager/dial-queue.js.map +1 -0
- package/dist/src/connection-manager/index.d.ts +65 -69
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +116 -234
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/connection-manager/utils.d.ts +9 -0
- package/dist/src/connection-manager/utils.d.ts.map +1 -0
- package/dist/src/connection-manager/utils.js +66 -0
- package/dist/src/connection-manager/utils.js.map +1 -0
- package/dist/src/fetch/index.js +3 -3
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/identify/index.js +5 -5
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/insecure/index.d.ts.map +1 -1
- package/dist/src/insecure/index.js +3 -1
- package/dist/src/insecure/index.js.map +1 -1
- package/dist/src/libp2p.d.ts +10 -2
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +7 -13
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/upgrader.d.ts +1 -1
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +2 -1
- package/dist/src/upgrader.js.map +1 -1
- package/dist/typedoc-urls.json +1 -1
- package/package.json +18 -18
- package/src/autonat/index.ts +6 -9
- package/src/circuit-relay/transport/reservation-store.ts +1 -1
- package/src/circuit-relay/utils.ts +3 -1
- package/src/components.ts +1 -17
- package/src/config.ts +0 -9
- package/src/connection-manager/auto-dial.ts +171 -0
- package/src/connection-manager/connection-pruner.ts +137 -0
- package/src/connection-manager/constants.ts +60 -0
- package/src/connection-manager/dial-queue.ts +504 -0
- package/src/connection-manager/index.ts +190 -323
- package/src/connection-manager/utils.ts +76 -0
- package/src/fetch/index.ts +4 -4
- package/src/identify/index.ts +5 -5
- package/src/insecure/index.ts +5 -1
- package/src/libp2p.ts +17 -15
- package/src/upgrader.ts +3 -2
- package/src/version.ts +1 -1
- package/dist/src/connection-manager/auto-dialler.d.ts +0 -42
- package/dist/src/connection-manager/auto-dialler.d.ts.map +0 -1
- package/dist/src/connection-manager/auto-dialler.js +0 -105
- package/dist/src/connection-manager/auto-dialler.js.map +0 -1
- package/dist/src/connection-manager/dialer/dial-request.d.ts +0 -27
- package/dist/src/connection-manager/dialer/dial-request.d.ts.map +0 -1
- package/dist/src/connection-manager/dialer/dial-request.js +0 -114
- package/dist/src/connection-manager/dialer/dial-request.js.map +0 -1
- package/dist/src/connection-manager/dialer/index.d.ts +0 -121
- package/dist/src/connection-manager/dialer/index.d.ts.map +0 -1
- package/dist/src/connection-manager/dialer/index.js +0 -324
- package/dist/src/connection-manager/dialer/index.js.map +0 -1
- package/dist/src/connection-manager/latency-monitor.d.ts +0 -120
- package/dist/src/connection-manager/latency-monitor.d.ts.map +0 -1
- package/dist/src/connection-manager/latency-monitor.js +0 -220
- package/dist/src/connection-manager/latency-monitor.js.map +0 -1
- package/dist/src/connection-manager/visibility-change-emitter.d.ts +0 -66
- package/dist/src/connection-manager/visibility-change-emitter.d.ts.map +0 -1
- package/dist/src/connection-manager/visibility-change-emitter.js +0 -118
- package/dist/src/connection-manager/visibility-change-emitter.js.map +0 -1
- package/dist/src/constants.d.ts +0 -27
- package/dist/src/constants.d.ts.map +0 -1
- package/dist/src/constants.js +0 -31
- package/dist/src/constants.js.map +0 -1
- package/src/connection-manager/auto-dialler.ts +0 -158
- package/src/connection-manager/dialer/dial-request.ts +0 -144
- package/src/connection-manager/dialer/index.ts +0 -461
- package/src/connection-manager/latency-monitor.ts +0 -319
- package/src/connection-manager/visibility-change-emitter.ts +0 -135
- package/src/constants.ts +0 -36
|
@@ -1,69 +1,92 @@
|
|
|
1
1
|
import { logger } from '@libp2p/logger'
|
|
2
2
|
import { CodeError } from '@libp2p/interfaces/errors'
|
|
3
|
-
import mergeOptions from 'merge-options'
|
|
4
|
-
import { LatencyMonitor, SummaryObject } from './latency-monitor.js'
|
|
5
3
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
6
4
|
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
|
|
7
5
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
8
6
|
import { codes } from '../errors.js'
|
|
9
|
-
import {
|
|
7
|
+
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
10
8
|
import { setMaxListeners } from 'events'
|
|
11
9
|
import type { Connection, MultiaddrConnection } from '@libp2p/interface-connection'
|
|
12
|
-
import type { ConnectionManager, ConnectionManagerEvents
|
|
13
|
-
import * as STATUS from '@libp2p/interface-connection/status'
|
|
10
|
+
import type { ConnectionManager, ConnectionManagerEvents } from '@libp2p/interface-connection-manager'
|
|
14
11
|
import type { AddressSorter, PeerStore } from '@libp2p/interface-peer-store'
|
|
15
|
-
import {
|
|
16
|
-
import { PeerMap } from '@libp2p/peer-collections'
|
|
17
|
-
import { TimeoutController } from 'timeout-abort-controller'
|
|
12
|
+
import { Multiaddr, Resolver, multiaddr } from '@multiformats/multiaddr'
|
|
18
13
|
import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
|
|
19
14
|
import { RateLimiterMemory } from 'rate-limiter-flexible'
|
|
20
15
|
import type { Metrics } from '@libp2p/interface-metrics'
|
|
21
|
-
import type { Upgrader } from '@libp2p/interface-transport'
|
|
16
|
+
import type { TransportManager, Upgrader } from '@libp2p/interface-transport'
|
|
22
17
|
import { getPeerAddress } from '../get-peer.js'
|
|
18
|
+
import { AutoDial } from './auto-dial.js'
|
|
19
|
+
import { DialQueue } from './dial-queue.js'
|
|
20
|
+
import { ConnectionPruner } from './connection-pruner.js'
|
|
21
|
+
import type { ConnectionGater } from '@libp2p/interface-connection-gater'
|
|
22
|
+
import { PeerMap } from '@libp2p/peer-collections'
|
|
23
|
+
import { publicAddressesFirst } from '@libp2p/utils/address-sort'
|
|
24
|
+
import { AUTO_DIAL_CONCURRENCY, AUTO_DIAL_PRIORITY, DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_CONNECTIONS, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL, MIN_CONNECTIONS } from './constants.js'
|
|
25
|
+
import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
|
|
26
|
+
import type { PendingDial } from '../libp2p.js'
|
|
23
27
|
|
|
24
28
|
const log = logger('libp2p:connection-manager')
|
|
25
29
|
|
|
26
|
-
|
|
30
|
+
const DEFAULT_DIAL_PRIORITY = 50
|
|
31
|
+
|
|
32
|
+
export interface ConnectionManagerInit {
|
|
27
33
|
/**
|
|
28
|
-
* The maximum number of connections libp2p is willing to have before it starts
|
|
34
|
+
* The maximum number of connections libp2p is willing to have before it starts
|
|
35
|
+
* pruning connections to reduce resource usage. (default: 300)
|
|
29
36
|
*/
|
|
30
|
-
maxConnections
|
|
37
|
+
maxConnections?: number
|
|
31
38
|
|
|
32
39
|
/**
|
|
33
|
-
* The minimum number of connections below which libp2p
|
|
40
|
+
* The minimum number of connections below which libp2p will start to dial peers
|
|
41
|
+
* from the peer book. Setting this to 0 effectively disables this behaviour.
|
|
42
|
+
* (default: 50)
|
|
34
43
|
*/
|
|
35
|
-
minConnections
|
|
44
|
+
minConnections?: number
|
|
36
45
|
|
|
37
46
|
/**
|
|
38
|
-
*
|
|
47
|
+
* How long to wait between attempting to keep our number of concurrent connections
|
|
48
|
+
* above minConnections (default: 5000)
|
|
39
49
|
*/
|
|
40
|
-
|
|
50
|
+
autoDialInterval?: number
|
|
41
51
|
|
|
42
52
|
/**
|
|
43
|
-
*
|
|
53
|
+
* When dialling peers from the peer book to keep the number of open connections
|
|
54
|
+
* above `minConnections`, add dials for this many peers to the dial queue
|
|
55
|
+
* at once. (default: 25)
|
|
44
56
|
*/
|
|
45
|
-
|
|
57
|
+
autoDialConcurrency?: number
|
|
46
58
|
|
|
47
59
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
60
|
+
* To allow user dials to take priority over auto dials, use this value as the
|
|
61
|
+
* dial priority. (default: 0)
|
|
50
62
|
*/
|
|
51
|
-
|
|
63
|
+
autoDialPriority?: number
|
|
52
64
|
|
|
53
65
|
/**
|
|
54
|
-
* Sort the known addresses of a peer before trying to dial
|
|
66
|
+
* Sort the known addresses of a peer before trying to dial, By default public
|
|
67
|
+
* addresses will be dialled before private (e.g. loopback or LAN) addresses.
|
|
55
68
|
*/
|
|
56
69
|
addressSorter?: AddressSorter
|
|
57
70
|
|
|
58
71
|
/**
|
|
59
|
-
*
|
|
72
|
+
* The maximum number of dials across all peers to execute in parallel.
|
|
73
|
+
* (default: 100)
|
|
60
74
|
*/
|
|
61
75
|
maxParallelDials?: number
|
|
62
76
|
|
|
63
77
|
/**
|
|
64
|
-
*
|
|
78
|
+
* To prevent individual peers with large amounts of multiaddrs swamping the
|
|
79
|
+
* dial queue, this value controls how many addresses to dial in parallel per
|
|
80
|
+
* peer. So for example if two peers have 10 addresses and this value is set
|
|
81
|
+
* at 5, we will dial 5 addresses from each at a time. (default: 10)
|
|
65
82
|
*/
|
|
66
|
-
|
|
83
|
+
maxParallelDialsPerPeer?: number
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Maximum number of addresses allowed for a given peer - if a peer has more
|
|
87
|
+
* addresses than this then the dial will fail. (default: 25)
|
|
88
|
+
*/
|
|
89
|
+
maxPeerAddrsToDial?: number
|
|
67
90
|
|
|
68
91
|
/**
|
|
69
92
|
* How long a dial attempt is allowed to take, including DNS resolution
|
|
@@ -73,26 +96,15 @@ export interface ConnectionManagerConfig {
|
|
|
73
96
|
|
|
74
97
|
/**
|
|
75
98
|
* When a new inbound connection is opened, the upgrade process (e.g. protect,
|
|
76
|
-
* encrypt, multiplex etc) must complete within this number of ms.
|
|
77
|
-
*/
|
|
78
|
-
inboundUpgradeTimeout: number
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Number of max concurrent dials per peer
|
|
99
|
+
* encrypt, multiplex etc) must complete within this number of ms. (default: 30s)
|
|
82
100
|
*/
|
|
83
|
-
|
|
101
|
+
inboundUpgradeTimeout?: number
|
|
84
102
|
|
|
85
103
|
/**
|
|
86
|
-
* Multiaddr resolvers to use when
|
|
104
|
+
* Multiaddr resolvers to use when dialling
|
|
87
105
|
*/
|
|
88
106
|
resolvers?: Record<string, Resolver>
|
|
89
107
|
|
|
90
|
-
/**
|
|
91
|
-
* On startup we try to dial any peer that has previously been
|
|
92
|
-
* tagged with KEEP_ALIVE up to this timeout in ms. (default: 60000)
|
|
93
|
-
*/
|
|
94
|
-
startupReconnectTimeout?: number
|
|
95
|
-
|
|
96
108
|
/**
|
|
97
109
|
* A list of multiaddrs that will always be allowed (except if they are in the
|
|
98
110
|
* deny list) to open connections to this node even if we've reached maxConnections
|
|
@@ -107,103 +119,152 @@ export interface ConnectionManagerConfig {
|
|
|
107
119
|
|
|
108
120
|
/**
|
|
109
121
|
* If more than this many connections are opened per second by a single
|
|
110
|
-
* host, reject subsequent connections
|
|
122
|
+
* host, reject subsequent connections. (default: 5)
|
|
111
123
|
*/
|
|
112
124
|
inboundConnectionThreshold?: number
|
|
113
125
|
|
|
114
126
|
/**
|
|
115
127
|
* The maximum number of parallel incoming connections allowed that have yet to
|
|
116
|
-
* complete the connection upgrade - e.g. choosing connection encryption, muxer, etc
|
|
128
|
+
* complete the connection upgrade - e.g. choosing connection encryption, muxer, etc.
|
|
129
|
+
* (default: 10)
|
|
117
130
|
*/
|
|
118
131
|
maxIncomingPendingConnections?: number
|
|
119
132
|
}
|
|
120
133
|
|
|
121
|
-
const defaultOptions
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
maxIncomingPendingConnections: 10
|
|
134
|
+
const defaultOptions = {
|
|
135
|
+
minConnections: MIN_CONNECTIONS,
|
|
136
|
+
maxConnections: MAX_CONNECTIONS,
|
|
137
|
+
inboundConnectionThreshold: INBOUND_CONNECTION_THRESHOLD,
|
|
138
|
+
maxIncomingPendingConnections: MAX_INCOMING_PENDING_CONNECTIONS,
|
|
139
|
+
autoDialConcurrency: AUTO_DIAL_CONCURRENCY,
|
|
140
|
+
autoDialPriority: AUTO_DIAL_PRIORITY
|
|
129
141
|
}
|
|
130
142
|
|
|
131
|
-
const STARTUP_RECONNECT_TIMEOUT = 60000
|
|
132
|
-
|
|
133
143
|
export interface DefaultConnectionManagerComponents {
|
|
134
144
|
peerId: PeerId
|
|
135
145
|
metrics?: Metrics
|
|
136
146
|
upgrader: Upgrader
|
|
137
147
|
peerStore: PeerStore
|
|
138
|
-
|
|
148
|
+
transportManager: TransportManager
|
|
149
|
+
connectionGater: ConnectionGater
|
|
139
150
|
}
|
|
140
151
|
|
|
141
|
-
export
|
|
152
|
+
export interface OpenConnectionOptions extends AbortOptions {
|
|
153
|
+
priority?: number
|
|
154
|
+
}
|
|
142
155
|
|
|
143
156
|
/**
|
|
144
157
|
* Responsible for managing known connections.
|
|
145
158
|
*/
|
|
146
159
|
export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEvents> implements ConnectionManager, Startable {
|
|
147
|
-
private readonly components: DefaultConnectionManagerComponents
|
|
148
|
-
private readonly opts: ConnectionManagerInit
|
|
149
|
-
private readonly connections: Map<string, Connection[]>
|
|
150
160
|
private started: boolean
|
|
151
|
-
private readonly
|
|
152
|
-
private readonly startupReconnectTimeout: number
|
|
153
|
-
private connectOnStartupController?: TimeoutController
|
|
154
|
-
private readonly dialTimeout: number
|
|
161
|
+
private readonly connections: PeerMap<Connection[]>
|
|
155
162
|
private readonly allow: Multiaddr[]
|
|
156
163
|
private readonly deny: Multiaddr[]
|
|
157
|
-
private readonly
|
|
164
|
+
private readonly maxIncomingPendingConnections: number
|
|
158
165
|
private incomingPendingConnections: number
|
|
166
|
+
private readonly maxConnections: number
|
|
159
167
|
|
|
160
|
-
|
|
168
|
+
public readonly dialQueue: DialQueue
|
|
169
|
+
public readonly autoDial: AutoDial
|
|
170
|
+
public readonly connectionPruner: ConnectionPruner
|
|
171
|
+
private readonly inboundConnectionRateLimiter: RateLimiterMemory
|
|
172
|
+
|
|
173
|
+
private readonly peerStore: PeerStore
|
|
174
|
+
private readonly metrics?: Metrics
|
|
175
|
+
|
|
176
|
+
constructor (components: DefaultConnectionManagerComponents, init: ConnectionManagerInit = {}) {
|
|
161
177
|
super()
|
|
162
178
|
|
|
163
|
-
this.
|
|
179
|
+
this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections
|
|
180
|
+
const minConnections = init.minConnections ?? defaultOptions.minConnections
|
|
164
181
|
|
|
165
|
-
if (this.
|
|
182
|
+
if (this.maxConnections < minConnections) {
|
|
166
183
|
throw new CodeError('Connection Manager maxConnections must be greater than minConnections', codes.ERR_INVALID_PARAMETERS)
|
|
167
184
|
}
|
|
168
185
|
|
|
169
|
-
log('options: %o', this.opts)
|
|
170
|
-
|
|
171
|
-
this.components = components
|
|
172
|
-
|
|
173
186
|
/**
|
|
174
187
|
* Map of connections per peer
|
|
175
188
|
*/
|
|
176
|
-
this.connections = new
|
|
189
|
+
this.connections = new PeerMap()
|
|
177
190
|
|
|
178
191
|
this.started = false
|
|
179
192
|
|
|
180
|
-
if (init.maxEventLoopDelay != null && init.maxEventLoopDelay > 0 && init.maxEventLoopDelay !== Infinity) {
|
|
181
|
-
this.latencyMonitor = new LatencyMonitor({
|
|
182
|
-
latencyCheckIntervalMs: init.pollInterval,
|
|
183
|
-
dataEmitIntervalMs: init.pollInterval
|
|
184
|
-
})
|
|
185
|
-
}
|
|
186
|
-
|
|
187
193
|
try {
|
|
188
194
|
// This emitter gets listened to a lot
|
|
189
195
|
setMaxListeners?.(Infinity, this)
|
|
190
196
|
} catch {}
|
|
191
197
|
|
|
198
|
+
this.peerStore = components.peerStore
|
|
199
|
+
this.metrics = components.metrics
|
|
200
|
+
|
|
192
201
|
this.onConnect = this.onConnect.bind(this)
|
|
193
202
|
this.onDisconnect = this.onDisconnect.bind(this)
|
|
194
203
|
|
|
195
|
-
|
|
196
|
-
this.dialTimeout = init.dialTimeout ?? 30000
|
|
197
|
-
|
|
204
|
+
// allow/deny lists
|
|
198
205
|
this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
|
|
199
206
|
this.deny = (init.deny ?? []).map(ma => multiaddr(ma))
|
|
200
207
|
|
|
208
|
+
this.incomingPendingConnections = 0
|
|
209
|
+
this.maxIncomingPendingConnections = init.maxIncomingPendingConnections ?? defaultOptions.maxIncomingPendingConnections
|
|
210
|
+
|
|
211
|
+
// controls individual peers trying to dial us too quickly
|
|
201
212
|
this.inboundConnectionRateLimiter = new RateLimiterMemory({
|
|
202
|
-
points:
|
|
213
|
+
points: init.inboundConnectionThreshold ?? defaultOptions.inboundConnectionThreshold,
|
|
203
214
|
duration: 1
|
|
204
215
|
})
|
|
205
216
|
|
|
206
|
-
|
|
217
|
+
// controls what happens when we don't have enough connections
|
|
218
|
+
this.autoDial = new AutoDial({
|
|
219
|
+
connectionManager: this,
|
|
220
|
+
peerStore: components.peerStore
|
|
221
|
+
}, {
|
|
222
|
+
minConnections,
|
|
223
|
+
autoDialConcurrency: init.autoDialConcurrency ?? defaultOptions.autoDialConcurrency,
|
|
224
|
+
autoDialPriority: init.autoDialPriority ?? defaultOptions.autoDialPriority
|
|
225
|
+
})
|
|
226
|
+
// check the min connection limit whenever a peer disconnects
|
|
227
|
+
this.addEventListener('peer:disconnect', () => {
|
|
228
|
+
this.autoDial.autoDial()
|
|
229
|
+
.catch(err => {
|
|
230
|
+
log.error(err)
|
|
231
|
+
})
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
// controls what happens when we have too many connections
|
|
235
|
+
this.connectionPruner = new ConnectionPruner({
|
|
236
|
+
connectionManager: this,
|
|
237
|
+
peerStore: components.peerStore
|
|
238
|
+
}, {
|
|
239
|
+
maxConnections: this.maxConnections,
|
|
240
|
+
allow: this.allow
|
|
241
|
+
})
|
|
242
|
+
// check the max connection limit whenever a peer connects
|
|
243
|
+
this.addEventListener('peer:connect', () => {
|
|
244
|
+
this.connectionPruner.maybePruneConnections()
|
|
245
|
+
.catch(err => {
|
|
246
|
+
log.error(err)
|
|
247
|
+
})
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
this.dialQueue = new DialQueue({
|
|
251
|
+
peerId: components.peerId,
|
|
252
|
+
metrics: components.metrics,
|
|
253
|
+
peerStore: components.peerStore,
|
|
254
|
+
transportManager: components.transportManager,
|
|
255
|
+
connectionGater: components.connectionGater
|
|
256
|
+
}, {
|
|
257
|
+
addressSorter: init.addressSorter ?? publicAddressesFirst,
|
|
258
|
+
maxParallelDials: init.maxParallelDials ?? MAX_PARALLEL_DIALS,
|
|
259
|
+
maxPeerAddrsToDial: init.maxPeerAddrsToDial ?? MAX_PEER_ADDRS_TO_DIAL,
|
|
260
|
+
dialTimeout: init.dialTimeout ?? DIAL_TIMEOUT,
|
|
261
|
+
resolvers: init.resolvers ?? {
|
|
262
|
+
dnsaddr: dnsaddrResolver
|
|
263
|
+
}
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
components.upgrader.addEventListener('connection', this.onConnect)
|
|
267
|
+
components.upgrader.addEventListener('connectionEnd', this.onDisconnect)
|
|
207
268
|
}
|
|
208
269
|
|
|
209
270
|
isStarted (): boolean {
|
|
@@ -216,7 +277,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
216
277
|
*/
|
|
217
278
|
async start (): Promise<void> {
|
|
218
279
|
// track inbound/outbound connections
|
|
219
|
-
this.
|
|
280
|
+
this.metrics?.registerMetricGroup('libp2p_connection_manager_connections', {
|
|
220
281
|
calculate: () => {
|
|
221
282
|
const metric = {
|
|
222
283
|
inbound: 0,
|
|
@@ -238,7 +299,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
238
299
|
})
|
|
239
300
|
|
|
240
301
|
// track total number of streams per protocol
|
|
241
|
-
this.
|
|
302
|
+
this.metrics?.registerMetricGroup('libp2p_protocol_streams_total', {
|
|
242
303
|
label: 'protocol',
|
|
243
304
|
calculate: () => {
|
|
244
305
|
const metric: Record<string, number> = {}
|
|
@@ -258,7 +319,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
258
319
|
})
|
|
259
320
|
|
|
260
321
|
// track 90th percentile of streams per protocol
|
|
261
|
-
this.
|
|
322
|
+
this.metrics?.registerMetricGroup('libp2p_connection_manager_protocol_streams_per_connection_90th_percentile', {
|
|
262
323
|
label: 'protocol',
|
|
263
324
|
calculate: () => {
|
|
264
325
|
const allStreams: Record<string, number[]> = {}
|
|
@@ -293,26 +354,20 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
293
354
|
}
|
|
294
355
|
})
|
|
295
356
|
|
|
296
|
-
|
|
297
|
-
this.latencyMonitor?.start()
|
|
298
|
-
this._onLatencyMeasure = this._onLatencyMeasure.bind(this)
|
|
299
|
-
this.latencyMonitor?.addEventListener('data', this._onLatencyMeasure)
|
|
357
|
+
this.autoDial.start()
|
|
300
358
|
|
|
301
359
|
this.started = true
|
|
302
360
|
log('started')
|
|
303
361
|
}
|
|
304
362
|
|
|
305
363
|
async afterStart (): Promise<void> {
|
|
306
|
-
this.components.upgrader.addEventListener('connection', this.onConnect)
|
|
307
|
-
this.components.upgrader.addEventListener('connectionEnd', this.onDisconnect)
|
|
308
|
-
|
|
309
364
|
// re-connect to any peers with the KEEP_ALIVE tag
|
|
310
365
|
void Promise.resolve()
|
|
311
366
|
.then(async () => {
|
|
312
367
|
const keepAlivePeers: PeerId[] = []
|
|
313
368
|
|
|
314
|
-
for (const peer of await this.
|
|
315
|
-
const tags = await this.
|
|
369
|
+
for (const peer of await this.peerStore.all()) {
|
|
370
|
+
const tags = await this.peerStore.getTags(peer.id)
|
|
316
371
|
const hasKeepAlive = tags.filter(tag => tag.name === KEEP_ALIVE).length > 0
|
|
317
372
|
|
|
318
373
|
if (hasKeepAlive) {
|
|
@@ -320,19 +375,9 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
320
375
|
}
|
|
321
376
|
}
|
|
322
377
|
|
|
323
|
-
this.connectOnStartupController?.clear()
|
|
324
|
-
this.connectOnStartupController = new TimeoutController(this.startupReconnectTimeout)
|
|
325
|
-
|
|
326
|
-
try {
|
|
327
|
-
// fails on node < 15.4
|
|
328
|
-
setMaxListeners?.(Infinity, this.connectOnStartupController.signal)
|
|
329
|
-
} catch {}
|
|
330
|
-
|
|
331
378
|
await Promise.all(
|
|
332
379
|
keepAlivePeers.map(async peer => {
|
|
333
|
-
await this.openConnection(peer
|
|
334
|
-
signal: this.connectOnStartupController?.signal
|
|
335
|
-
})
|
|
380
|
+
await this.openConnection(peer)
|
|
336
381
|
.catch(err => {
|
|
337
382
|
log.error(err)
|
|
338
383
|
})
|
|
@@ -342,34 +387,17 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
342
387
|
.catch(err => {
|
|
343
388
|
log.error(err)
|
|
344
389
|
})
|
|
345
|
-
.finally(() => {
|
|
346
|
-
this.connectOnStartupController?.clear()
|
|
347
|
-
})
|
|
348
|
-
}
|
|
349
390
|
|
|
350
|
-
|
|
351
|
-
// if we are still dialing KEEP_ALIVE peers, abort those dials
|
|
352
|
-
this.connectOnStartupController?.abort()
|
|
353
|
-
this.components.upgrader.removeEventListener('connection', this.onConnect)
|
|
354
|
-
this.components.upgrader.removeEventListener('connectionEnd', this.onDisconnect)
|
|
391
|
+
this.autoDial.afterStart()
|
|
355
392
|
}
|
|
356
393
|
|
|
357
394
|
/**
|
|
358
395
|
* Stops the Connection Manager
|
|
359
396
|
*/
|
|
360
397
|
async stop (): Promise<void> {
|
|
361
|
-
this.
|
|
362
|
-
this.
|
|
363
|
-
|
|
364
|
-
this.started = false
|
|
365
|
-
await this._close()
|
|
366
|
-
log('stopped')
|
|
367
|
-
}
|
|
398
|
+
this.dialQueue.stop()
|
|
399
|
+
this.autoDial.stop()
|
|
368
400
|
|
|
369
|
-
/**
|
|
370
|
-
* Cleans up the connections
|
|
371
|
-
*/
|
|
372
|
-
async _close (): Promise<void> {
|
|
373
401
|
// Close all connections we're tracking
|
|
374
402
|
const tasks: Array<Promise<void>> = []
|
|
375
403
|
for (const connectionList of this.connections.values()) {
|
|
@@ -387,6 +415,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
387
415
|
log('closing %d connections', tasks.length)
|
|
388
416
|
await Promise.all(tasks)
|
|
389
417
|
this.connections.clear()
|
|
418
|
+
|
|
419
|
+
log('stopped')
|
|
390
420
|
}
|
|
391
421
|
|
|
392
422
|
onConnect (evt: CustomEvent<Connection>): void {
|
|
@@ -408,23 +438,18 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
408
438
|
}
|
|
409
439
|
|
|
410
440
|
const peerId = connection.remotePeer
|
|
411
|
-
const
|
|
412
|
-
const storedConns = this.connections.get(peerIdStr)
|
|
441
|
+
const storedConns = this.connections.get(peerId)
|
|
413
442
|
|
|
414
443
|
if (storedConns != null) {
|
|
415
444
|
storedConns.push(connection)
|
|
416
445
|
} else {
|
|
417
|
-
this.connections.set(
|
|
446
|
+
this.connections.set(peerId, [connection])
|
|
418
447
|
}
|
|
419
448
|
|
|
420
449
|
if (peerId.publicKey != null) {
|
|
421
|
-
await this.
|
|
450
|
+
await this.peerStore.keyBook.set(peerId, peerId.publicKey)
|
|
422
451
|
}
|
|
423
452
|
|
|
424
|
-
const numConnections = this.getConnections().length
|
|
425
|
-
const toPrune = numConnections - this.opts.maxConnections
|
|
426
|
-
|
|
427
|
-
await this._checkMaxLimit('maxConnections', numConnections, toPrune)
|
|
428
453
|
this.dispatchEvent(new CustomEvent<Connection>('peer:connect', { detail: connection }))
|
|
429
454
|
}
|
|
430
455
|
|
|
@@ -439,7 +464,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
439
464
|
return
|
|
440
465
|
}
|
|
441
466
|
|
|
442
|
-
const peerId = connection.remotePeer
|
|
467
|
+
const peerId = connection.remotePeer
|
|
443
468
|
let storedConn = this.connections.get(peerId)
|
|
444
469
|
|
|
445
470
|
if (storedConn != null && storedConn.length > 1) {
|
|
@@ -453,7 +478,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
453
478
|
|
|
454
479
|
getConnections (peerId?: PeerId): Connection[] {
|
|
455
480
|
if (peerId != null) {
|
|
456
|
-
return this.connections.get(peerId
|
|
481
|
+
return this.connections.get(peerId) ?? []
|
|
457
482
|
}
|
|
458
483
|
|
|
459
484
|
let conns: Connection[] = []
|
|
@@ -465,19 +490,15 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
465
490
|
return conns
|
|
466
491
|
}
|
|
467
492
|
|
|
468
|
-
getConnectionsMap ():
|
|
493
|
+
getConnectionsMap (): PeerMap<Connection[]> {
|
|
469
494
|
return this.connections
|
|
470
495
|
}
|
|
471
496
|
|
|
472
|
-
async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options:
|
|
473
|
-
const { peerId
|
|
474
|
-
|
|
475
|
-
if (peerId == null && multiaddrs.length === 0) {
|
|
476
|
-
throw new CodeError('Can only open connections to PeerIds or Multiaddrs', codes.ERR_INVALID_PARAMETERS)
|
|
477
|
-
}
|
|
497
|
+
async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise<Connection> {
|
|
498
|
+
const { peerId } = getPeerAddress(peerIdOrMultiaddr)
|
|
478
499
|
|
|
479
500
|
if (peerId != null) {
|
|
480
|
-
log('dial
|
|
501
|
+
log('dial %p', peerId)
|
|
481
502
|
const existingConnections = this.getConnections(peerId)
|
|
482
503
|
|
|
483
504
|
if (existingConnections.length > 0) {
|
|
@@ -487,53 +508,37 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
487
508
|
}
|
|
488
509
|
}
|
|
489
510
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
511
|
+
const connection = await this.dialQueue.dial(peerIdOrMultiaddr, {
|
|
512
|
+
...options,
|
|
513
|
+
priority: options.priority ?? DEFAULT_DIAL_PRIORITY
|
|
514
|
+
})
|
|
515
|
+
let peerConnections = this.connections.get(connection.remotePeer)
|
|
495
516
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
} catch {}
|
|
517
|
+
if (peerConnections == null) {
|
|
518
|
+
peerConnections = []
|
|
519
|
+
this.connections.set(connection.remotePeer, peerConnections)
|
|
500
520
|
}
|
|
501
521
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (peerConnections == null) {
|
|
508
|
-
peerConnections = []
|
|
509
|
-
this.connections.set(connection.remotePeer.toString(), peerConnections)
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// we get notified of connections via the Upgrader emitting "connection"
|
|
513
|
-
// events, double check we aren't already tracking this connection before
|
|
514
|
-
// storing it
|
|
515
|
-
let trackedConnection = false
|
|
522
|
+
// we get notified of connections via the Upgrader emitting "connection"
|
|
523
|
+
// events, double check we aren't already tracking this connection before
|
|
524
|
+
// storing it
|
|
525
|
+
let trackedConnection = false
|
|
516
526
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (!trackedConnection) {
|
|
524
|
-
peerConnections.push(connection)
|
|
527
|
+
for (const conn of peerConnections) {
|
|
528
|
+
if (conn.id === connection.id) {
|
|
529
|
+
trackedConnection = true
|
|
525
530
|
}
|
|
531
|
+
}
|
|
526
532
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
if (timeoutController != null) {
|
|
530
|
-
timeoutController.clear()
|
|
531
|
-
}
|
|
533
|
+
if (!trackedConnection) {
|
|
534
|
+
peerConnections.push(connection)
|
|
532
535
|
}
|
|
536
|
+
|
|
537
|
+
return connection
|
|
533
538
|
}
|
|
534
539
|
|
|
535
540
|
async closeConnections (peerId: PeerId): Promise<void> {
|
|
536
|
-
const connections = this.connections.get(peerId
|
|
541
|
+
const connections = this.connections.get(peerId) ?? []
|
|
537
542
|
|
|
538
543
|
await Promise.all(
|
|
539
544
|
connections.map(async connection => {
|
|
@@ -542,148 +547,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
542
547
|
)
|
|
543
548
|
}
|
|
544
549
|
|
|
545
|
-
/**
|
|
546
|
-
* Get all open connections with a peer
|
|
547
|
-
*/
|
|
548
|
-
getAll (peerId: PeerId): Connection[] {
|
|
549
|
-
if (!isPeerId(peerId)) {
|
|
550
|
-
throw new CodeError('peerId must be an instance of peer-id', codes.ERR_INVALID_PARAMETERS)
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const id = peerId.toString()
|
|
554
|
-
const connections = this.connections.get(id)
|
|
555
|
-
|
|
556
|
-
// Return all open connections
|
|
557
|
-
if (connections != null) {
|
|
558
|
-
return connections.filter(connection => connection.stat.status === STATUS.OPEN)
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return []
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* If the event loop is slow, maybe close a connection
|
|
566
|
-
*/
|
|
567
|
-
_onLatencyMeasure (evt: CustomEvent<SummaryObject>): void {
|
|
568
|
-
const { detail: summary } = evt
|
|
569
|
-
|
|
570
|
-
this._checkMaxLimit('maxEventLoopDelay', summary.avgMs, 1)
|
|
571
|
-
.catch(err => {
|
|
572
|
-
log.error(err)
|
|
573
|
-
})
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
/**
|
|
577
|
-
* If the `value` of `name` has exceeded its limit, maybe close a connection
|
|
578
|
-
*/
|
|
579
|
-
async _checkMaxLimit (name: keyof ConnectionManagerInit, value: number, toPrune: number = 1): Promise<void> {
|
|
580
|
-
const limit = this.opts[name]
|
|
581
|
-
|
|
582
|
-
if (limit == null) {
|
|
583
|
-
log.trace('limit %s was not set so it cannot be applied', name)
|
|
584
|
-
return
|
|
585
|
-
}
|
|
586
|
-
if (limit === Infinity) {
|
|
587
|
-
log.trace('limit %s is Infinity so it cannot be applied', name)
|
|
588
|
-
return
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
log.trace('checking limit of %s. current value: %d of %d', name, value, limit)
|
|
592
|
-
if (value > limit) {
|
|
593
|
-
log('%s: limit exceeded: %p, %d/%d, pruning %d connection(s)', this.components.peerId, name, value, limit, toPrune)
|
|
594
|
-
await this._pruneConnections(toPrune)
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/**
|
|
599
|
-
* If we have more connections than our maximum, select some excess connections
|
|
600
|
-
* to prune based on peer value
|
|
601
|
-
*/
|
|
602
|
-
async _pruneConnections (toPrune: number): Promise<void> {
|
|
603
|
-
const connections = this.getConnections()
|
|
604
|
-
const peerValues = new PeerMap<number>()
|
|
605
|
-
|
|
606
|
-
// work out peer values
|
|
607
|
-
for (const connection of connections) {
|
|
608
|
-
const remotePeer = connection.remotePeer
|
|
609
|
-
|
|
610
|
-
if (peerValues.has(remotePeer)) {
|
|
611
|
-
continue
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
const tags = await this.components.peerStore.getTags(remotePeer)
|
|
615
|
-
|
|
616
|
-
// sum all tag values
|
|
617
|
-
peerValues.set(remotePeer, tags.reduce((acc, curr) => {
|
|
618
|
-
return acc + curr.value
|
|
619
|
-
}, 0))
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
// sort by value, lowest to highest
|
|
623
|
-
const sortedConnections = connections.sort((a, b) => {
|
|
624
|
-
const peerAValue = peerValues.get(a.remotePeer) ?? 0
|
|
625
|
-
const peerBValue = peerValues.get(b.remotePeer) ?? 0
|
|
626
|
-
|
|
627
|
-
if (peerAValue > peerBValue) {
|
|
628
|
-
return 1
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if (peerAValue < peerBValue) {
|
|
632
|
-
return -1
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// if the peers have an equal tag value then we want to close short-lived connections first
|
|
636
|
-
const connectionALifespan = a.stat.timeline.open
|
|
637
|
-
const connectionBLifespan = b.stat.timeline.open
|
|
638
|
-
|
|
639
|
-
if (connectionALifespan < connectionBLifespan) {
|
|
640
|
-
return 1
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (connectionALifespan > connectionBLifespan) {
|
|
644
|
-
return -1
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
return 0
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
// close some connections
|
|
651
|
-
const toClose = []
|
|
652
|
-
|
|
653
|
-
for (const connection of sortedConnections) {
|
|
654
|
-
log('too many connections open - closing a connection to %p', connection.remotePeer)
|
|
655
|
-
// check allow list
|
|
656
|
-
const connectionInAllowList = this.allow.some((ma) => {
|
|
657
|
-
return connection.remoteAddr.toString().startsWith(ma.toString())
|
|
658
|
-
})
|
|
659
|
-
|
|
660
|
-
// Connections in the allow list should be excluded from pruning
|
|
661
|
-
if (!connectionInAllowList) {
|
|
662
|
-
toClose.push(connection)
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
if (toClose.length === toPrune) {
|
|
666
|
-
break
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
// close connections
|
|
671
|
-
await Promise.all(
|
|
672
|
-
toClose.map(async connection => {
|
|
673
|
-
try {
|
|
674
|
-
await connection.close()
|
|
675
|
-
} catch (err) {
|
|
676
|
-
log.error(err)
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// TODO: should not need to invoke this manually
|
|
680
|
-
this.onDisconnect(new CustomEvent<Connection>('connectionEnd', {
|
|
681
|
-
detail: connection
|
|
682
|
-
}))
|
|
683
|
-
})
|
|
684
|
-
)
|
|
685
|
-
}
|
|
686
|
-
|
|
687
550
|
async acceptIncomingConnection (maConn: MultiaddrConnection): Promise<boolean> {
|
|
688
551
|
// check deny list
|
|
689
552
|
const denyConnection = this.deny.some(ma => {
|
|
@@ -707,7 +570,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
707
570
|
}
|
|
708
571
|
|
|
709
572
|
// check pending connections
|
|
710
|
-
if (this.incomingPendingConnections === this.
|
|
573
|
+
if (this.incomingPendingConnections === this.maxIncomingPendingConnections) {
|
|
711
574
|
log('connection from %s refused - incomingPendingConnections exceeded by peer %s', maConn.remoteAddr)
|
|
712
575
|
return false
|
|
713
576
|
}
|
|
@@ -723,7 +586,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
723
586
|
}
|
|
724
587
|
}
|
|
725
588
|
|
|
726
|
-
if (this.getConnections().length < this.
|
|
589
|
+
if (this.getConnections().length < this.maxConnections) {
|
|
727
590
|
this.incomingPendingConnections++
|
|
728
591
|
|
|
729
592
|
return true
|
|
@@ -736,4 +599,8 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
736
599
|
afterUpgradeInbound (): void {
|
|
737
600
|
this.incomingPendingConnections--
|
|
738
601
|
}
|
|
602
|
+
|
|
603
|
+
getDialQueue (): PendingDial[] {
|
|
604
|
+
return this.dialQueue.pendingDials
|
|
605
|
+
}
|
|
739
606
|
}
|