libp2p 0.37.3-676cee2 → 0.37.3-6eaab2e
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/README.md +1 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +7 -3
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection-manager/dialer/index.d.ts +4 -4
- package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
- package/dist/src/connection-manager/dialer/index.js +10 -10
- package/dist/src/connection-manager/dialer/index.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +15 -11
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +169 -62
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/constants.d.ts +4 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +4 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/fetch/index.d.ts +4 -0
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/fetch/index.js +15 -5
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/identify/index.d.ts +1 -1
- package/dist/src/identify/index.d.ts.map +1 -1
- package/dist/src/identify/index.js +9 -10
- package/dist/src/identify/index.js.map +1 -1
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +2 -12
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/metrics/index.d.ts +2 -2
- package/dist/src/metrics/index.d.ts.map +1 -1
- package/dist/src/metrics/index.js +6 -2
- package/dist/src/metrics/index.js.map +1 -1
- package/dist/src/ping/index.d.ts +4 -0
- package/dist/src/ping/index.d.ts.map +1 -1
- package/dist/src/ping/index.js +16 -6
- package/dist/src/ping/index.js.map +1 -1
- package/dist/src/upgrader.d.ts +6 -0
- package/dist/src/upgrader.d.ts.map +1 -1
- package/dist/src/upgrader.js +83 -59
- package/dist/src/upgrader.js.map +1 -1
- package/package.json +14 -13
- package/src/config.ts +7 -3
- package/src/connection-manager/dialer/index.ts +10 -10
- package/src/connection-manager/index.ts +220 -76
- package/src/constants.ts +5 -0
- package/src/fetch/index.ts +23 -6
- package/src/identify/index.ts +11 -12
- package/src/libp2p.ts +2 -13
- package/src/metrics/index.ts +8 -4
- package/src/ping/index.ts +24 -8
- package/src/upgrader.ts +95 -61
|
@@ -7,7 +7,6 @@ import retimer from 'retimer'
|
|
|
7
7
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
8
8
|
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
|
|
9
9
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
10
|
-
import { trackedMap } from '@libp2p/tracked-map'
|
|
11
10
|
import { codes } from '../errors.js'
|
|
12
11
|
import { isPeerId, PeerId } from '@libp2p/interface-peer-id'
|
|
13
12
|
import { setMaxListeners } from 'events'
|
|
@@ -18,6 +17,9 @@ import * as STATUS from '@libp2p/interface-connection/status'
|
|
|
18
17
|
import { Dialer } from './dialer/index.js'
|
|
19
18
|
import type { AddressSorter } from '@libp2p/interface-peer-store'
|
|
20
19
|
import type { Resolver } from '@multiformats/multiaddr'
|
|
20
|
+
import { PeerMap } from '@libp2p/peer-collections'
|
|
21
|
+
import { TimeoutController } from 'timeout-abort-controller'
|
|
22
|
+
import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
|
|
21
23
|
|
|
22
24
|
const log = logger('libp2p:connection-manager')
|
|
23
25
|
|
|
@@ -30,13 +32,12 @@ const defaultOptions: Partial<ConnectionManagerInit> = {
|
|
|
30
32
|
maxEventLoopDelay: Infinity,
|
|
31
33
|
pollInterval: 2000,
|
|
32
34
|
autoDialInterval: 10000,
|
|
33
|
-
movingAverageInterval: 60000
|
|
34
|
-
defaultPeerValue: 0.5
|
|
35
|
+
movingAverageInterval: 60000
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
const METRICS_SYSTEM = 'libp2p'
|
|
37
39
|
const METRICS_COMPONENT = 'connection-manager'
|
|
38
|
-
const
|
|
39
|
-
const METRICS_PEER_VALUES = 'peer-values'
|
|
40
|
+
const STARTUP_RECONNECT_TIMEOUT = 60000
|
|
40
41
|
|
|
41
42
|
export interface ConnectionManagerInit {
|
|
42
43
|
/**
|
|
@@ -79,11 +80,6 @@ export interface ConnectionManagerInit {
|
|
|
79
80
|
*/
|
|
80
81
|
movingAverageInterval?: number
|
|
81
82
|
|
|
82
|
-
/**
|
|
83
|
-
* The value of the peer
|
|
84
|
-
*/
|
|
85
|
-
defaultPeerValue?: number
|
|
86
|
-
|
|
87
83
|
/**
|
|
88
84
|
* If true, try to connect to all discovered peers up to the connection manager limit
|
|
89
85
|
*/
|
|
@@ -111,10 +107,17 @@ export interface ConnectionManagerInit {
|
|
|
111
107
|
maxAddrsToDial?: number
|
|
112
108
|
|
|
113
109
|
/**
|
|
114
|
-
* How long a dial attempt is allowed to take
|
|
110
|
+
* How long a dial attempt is allowed to take, including DNS resolution
|
|
111
|
+
* of the multiaddr, opening a socket and upgrading it to a Connection.
|
|
115
112
|
*/
|
|
116
113
|
dialTimeout?: number
|
|
117
114
|
|
|
115
|
+
/**
|
|
116
|
+
* When a new inbound connection is opened, the upgrade process (e.g. protect,
|
|
117
|
+
* encrypt, multiplex etc) must complete within this number of ms.
|
|
118
|
+
*/
|
|
119
|
+
inboundUpgradeTimeout: number
|
|
120
|
+
|
|
118
121
|
/**
|
|
119
122
|
* Number of max concurrent dials per peer
|
|
120
123
|
*/
|
|
@@ -124,6 +127,12 @@ export interface ConnectionManagerInit {
|
|
|
124
127
|
* Multiaddr resolvers to use when dialing
|
|
125
128
|
*/
|
|
126
129
|
resolvers?: Record<string, Resolver>
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* On startup we try to dial any peer that has previously been
|
|
133
|
+
* tagged with KEEP_ALIVE up to this timeout in ms. (default: 60000)
|
|
134
|
+
*/
|
|
135
|
+
startupReconnectTimeout?: number
|
|
127
136
|
}
|
|
128
137
|
|
|
129
138
|
export interface ConnectionManagerEvents {
|
|
@@ -138,11 +147,13 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
138
147
|
public readonly dialer: Dialer
|
|
139
148
|
private components = new Components()
|
|
140
149
|
private readonly opts: Required<ConnectionManagerInit>
|
|
141
|
-
private readonly peerValues: Map<string, number>
|
|
142
150
|
private readonly connections: Map<string, Connection[]>
|
|
143
151
|
private started: boolean
|
|
144
152
|
private timer?: ReturnType<retimer>
|
|
145
153
|
private readonly latencyMonitor: LatencyMonitor
|
|
154
|
+
private readonly startupReconnectTimeout: number
|
|
155
|
+
private connectOnStartupController?: TimeoutController
|
|
156
|
+
private readonly dialTimeout: number
|
|
146
157
|
|
|
147
158
|
constructor (init: ConnectionManagerInit) {
|
|
148
159
|
super()
|
|
@@ -155,25 +166,10 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
155
166
|
|
|
156
167
|
log('options: %o', this.opts)
|
|
157
168
|
|
|
158
|
-
/**
|
|
159
|
-
* Map of peer identifiers to their peer value for pruning connections.
|
|
160
|
-
*
|
|
161
|
-
* @type {Map<string, number>}
|
|
162
|
-
*/
|
|
163
|
-
this.peerValues = trackedMap({
|
|
164
|
-
component: METRICS_COMPONENT,
|
|
165
|
-
metric: METRICS_PEER_VALUES,
|
|
166
|
-
metrics: this.components.getMetrics()
|
|
167
|
-
})
|
|
168
|
-
|
|
169
169
|
/**
|
|
170
170
|
* Map of connections per peer
|
|
171
171
|
*/
|
|
172
|
-
this.connections =
|
|
173
|
-
component: METRICS_COMPONENT,
|
|
174
|
-
metric: METRICS_PEER_CONNECTIONS,
|
|
175
|
-
metrics: this.components.getMetrics()
|
|
176
|
-
})
|
|
172
|
+
this.connections = new Map()
|
|
177
173
|
|
|
178
174
|
this.started = false
|
|
179
175
|
this._checkMetrics = this._checkMetrics.bind(this)
|
|
@@ -192,12 +188,103 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
192
188
|
|
|
193
189
|
this.onConnect = this.onConnect.bind(this)
|
|
194
190
|
this.onDisconnect = this.onDisconnect.bind(this)
|
|
191
|
+
|
|
192
|
+
this.startupReconnectTimeout = init.startupReconnectTimeout ?? STARTUP_RECONNECT_TIMEOUT
|
|
193
|
+
this.dialTimeout = init.dialTimeout ?? 30000
|
|
195
194
|
}
|
|
196
195
|
|
|
197
196
|
init (components: Components): void {
|
|
198
197
|
this.components = components
|
|
199
198
|
|
|
200
199
|
this.dialer.init(components)
|
|
200
|
+
|
|
201
|
+
// track inbound/outbound connections
|
|
202
|
+
this.components.getMetrics()?.updateComponentMetric({
|
|
203
|
+
system: METRICS_SYSTEM,
|
|
204
|
+
component: METRICS_COMPONENT,
|
|
205
|
+
metric: 'connections',
|
|
206
|
+
label: 'direction',
|
|
207
|
+
value: () => {
|
|
208
|
+
const metric = {
|
|
209
|
+
inbound: 0,
|
|
210
|
+
outbound: 0
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (const conns of this.connections.values()) {
|
|
214
|
+
for (const conn of conns) {
|
|
215
|
+
if (conn.stat.direction === 'inbound') {
|
|
216
|
+
metric.inbound++
|
|
217
|
+
} else {
|
|
218
|
+
metric.outbound++
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return metric
|
|
224
|
+
}
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
// track total number of streams per protocol
|
|
228
|
+
this.components.getMetrics()?.updateComponentMetric({
|
|
229
|
+
system: METRICS_SYSTEM,
|
|
230
|
+
component: METRICS_COMPONENT,
|
|
231
|
+
metric: 'protocol-streams-total',
|
|
232
|
+
label: 'protocol',
|
|
233
|
+
value: () => {
|
|
234
|
+
const metric: Record<string, number> = {}
|
|
235
|
+
|
|
236
|
+
for (const conns of this.connections.values()) {
|
|
237
|
+
for (const conn of conns) {
|
|
238
|
+
for (const stream of conn.streams) {
|
|
239
|
+
const key = `${stream.stat.direction} ${stream.stat.protocol ?? 'unnegotiated'}`
|
|
240
|
+
|
|
241
|
+
metric[key] = (metric[key] ?? 0) + 1
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return metric
|
|
247
|
+
}
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
// track 90th percentile of streams per protocol
|
|
251
|
+
this.components.getMetrics()?.updateComponentMetric({
|
|
252
|
+
system: METRICS_SYSTEM,
|
|
253
|
+
component: METRICS_COMPONENT,
|
|
254
|
+
metric: 'protocol-streams-per-connection-90th-percentile',
|
|
255
|
+
label: 'protocol',
|
|
256
|
+
value: () => {
|
|
257
|
+
const allStreams: Record<string, number[]> = {}
|
|
258
|
+
|
|
259
|
+
for (const conns of this.connections.values()) {
|
|
260
|
+
for (const conn of conns) {
|
|
261
|
+
const streams: Record<string, number> = {}
|
|
262
|
+
|
|
263
|
+
for (const stream of conn.streams) {
|
|
264
|
+
const key = `${stream.stat.direction} ${stream.stat.protocol ?? 'unnegotiated'}`
|
|
265
|
+
|
|
266
|
+
streams[key] = (streams[key] ?? 0) + 1
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
for (const [protocol, count] of Object.entries(streams)) {
|
|
270
|
+
allStreams[protocol] = allStreams[protocol] ?? []
|
|
271
|
+
allStreams[protocol].push(count)
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const metric: Record<string, number> = {}
|
|
277
|
+
|
|
278
|
+
for (let [protocol, counts] of Object.entries(allStreams)) {
|
|
279
|
+
counts = counts.sort((a, b) => a - b)
|
|
280
|
+
|
|
281
|
+
const index = Math.floor(counts.length * 0.9)
|
|
282
|
+
metric[protocol] = counts[index]
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return metric
|
|
286
|
+
}
|
|
287
|
+
})
|
|
201
288
|
}
|
|
202
289
|
|
|
203
290
|
isStarted () {
|
|
@@ -226,9 +313,43 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
226
313
|
async afterStart () {
|
|
227
314
|
this.components.getUpgrader().addEventListener('connection', this.onConnect)
|
|
228
315
|
this.components.getUpgrader().addEventListener('connectionEnd', this.onDisconnect)
|
|
316
|
+
|
|
317
|
+
// re-connect to any peers with the KEEP_ALIVE tag
|
|
318
|
+
void Promise.resolve()
|
|
319
|
+
.then(async () => {
|
|
320
|
+
const keepAlivePeers: PeerId[] = []
|
|
321
|
+
|
|
322
|
+
for (const peer of await this.components.getPeerStore().all()) {
|
|
323
|
+
const tags = await this.components.getPeerStore().getTags(peer.id)
|
|
324
|
+
const hasKeepAlive = tags.filter(tag => tag.name === KEEP_ALIVE).length > 0
|
|
325
|
+
|
|
326
|
+
if (hasKeepAlive) {
|
|
327
|
+
keepAlivePeers.push(peer.id)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
this.connectOnStartupController?.clear()
|
|
332
|
+
this.connectOnStartupController = new TimeoutController(this.startupReconnectTimeout)
|
|
333
|
+
|
|
334
|
+
await Promise.all(
|
|
335
|
+
keepAlivePeers.map(async peer => {
|
|
336
|
+
await this.openConnection(peer, {
|
|
337
|
+
signal: this.connectOnStartupController?.signal
|
|
338
|
+
})
|
|
339
|
+
.catch(err => {
|
|
340
|
+
log.error(err)
|
|
341
|
+
})
|
|
342
|
+
})
|
|
343
|
+
)
|
|
344
|
+
})
|
|
345
|
+
.finally(() => {
|
|
346
|
+
this.connectOnStartupController?.clear()
|
|
347
|
+
})
|
|
229
348
|
}
|
|
230
349
|
|
|
231
350
|
async beforeStop () {
|
|
351
|
+
// if we are still dialing KEEP_ALIVE peers, abort those dials
|
|
352
|
+
this.connectOnStartupController?.abort()
|
|
232
353
|
this.components.getUpgrader().removeEventListener('connection', this.onConnect)
|
|
233
354
|
this.components.getUpgrader().removeEventListener('connectionEnd', this.onDisconnect)
|
|
234
355
|
}
|
|
@@ -271,18 +392,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
271
392
|
this.connections.clear()
|
|
272
393
|
}
|
|
273
394
|
|
|
274
|
-
/**
|
|
275
|
-
* Sets the value of the given peer. Peers with lower values
|
|
276
|
-
* will be disconnected first.
|
|
277
|
-
*/
|
|
278
|
-
setPeerValue (peerId: PeerId, value: number) {
|
|
279
|
-
if (value < 0 || value > 1) {
|
|
280
|
-
throw new Error('value should be a number between 0 and 1')
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
this.peerValues.set(peerId.toString(), value)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
395
|
/**
|
|
287
396
|
* Checks the libp2p metrics to determine if any values have exceeded
|
|
288
397
|
* the configured maximums.
|
|
@@ -340,10 +449,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
340
449
|
await this.components.getPeerStore().keyBook.set(peerId, peerId.publicKey)
|
|
341
450
|
}
|
|
342
451
|
|
|
343
|
-
if (!this.peerValues.has(peerIdStr)) {
|
|
344
|
-
this.peerValues.set(peerIdStr, this.opts.defaultPeerValue)
|
|
345
|
-
}
|
|
346
|
-
|
|
347
452
|
const numConnections = this.getConnections().length
|
|
348
453
|
const toPrune = numConnections - this.opts.maxConnections
|
|
349
454
|
|
|
@@ -370,7 +475,6 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
370
475
|
this.connections.set(peerId, storedConn)
|
|
371
476
|
} else if (storedConn != null) {
|
|
372
477
|
this.connections.delete(peerId)
|
|
373
|
-
this.peerValues.delete(connection.remotePeer.toString())
|
|
374
478
|
this.dispatchEvent(new CustomEvent<Connection>('peer:disconnect', { detail: connection }))
|
|
375
479
|
|
|
376
480
|
this.components.getMetrics()?.onPeerDisconnected(connection.remotePeer)
|
|
@@ -391,7 +495,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
391
495
|
return conns
|
|
392
496
|
}
|
|
393
497
|
|
|
394
|
-
async openConnection (peerId: PeerId, options
|
|
498
|
+
async openConnection (peerId: PeerId, options: AbortOptions = {}): Promise<Connection> {
|
|
395
499
|
log('dial to %p', peerId)
|
|
396
500
|
const existingConnections = this.getConnections(peerId)
|
|
397
501
|
|
|
@@ -401,30 +505,43 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
401
505
|
return existingConnections[0]
|
|
402
506
|
}
|
|
403
507
|
|
|
404
|
-
|
|
405
|
-
let peerConnections = this.connections.get(peerId.toString())
|
|
508
|
+
let timeoutController: TimeoutController | undefined
|
|
406
509
|
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
|
|
510
|
+
if (options?.signal == null) {
|
|
511
|
+
timeoutController = new TimeoutController(this.dialTimeout)
|
|
512
|
+
options.signal = timeoutController.signal
|
|
410
513
|
}
|
|
411
514
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
let trackedConnection = false
|
|
515
|
+
try {
|
|
516
|
+
const connection = await this.dialer.dial(peerId, options)
|
|
517
|
+
let peerConnections = this.connections.get(peerId.toString())
|
|
416
518
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
519
|
+
if (peerConnections == null) {
|
|
520
|
+
peerConnections = []
|
|
521
|
+
this.connections.set(peerId.toString(), peerConnections)
|
|
420
522
|
}
|
|
421
|
-
}
|
|
422
523
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
524
|
+
// we get notified of connections via the Upgrader emitting "connection"
|
|
525
|
+
// events, double check we aren't already tracking this connection before
|
|
526
|
+
// storing it
|
|
527
|
+
let trackedConnection = false
|
|
426
528
|
|
|
427
|
-
|
|
529
|
+
for (const conn of peerConnections) {
|
|
530
|
+
if (conn.id === connection.id) {
|
|
531
|
+
trackedConnection = true
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
if (!trackedConnection) {
|
|
536
|
+
peerConnections.push(connection)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
return connection
|
|
540
|
+
} finally {
|
|
541
|
+
if (timeoutController != null) {
|
|
542
|
+
timeoutController.clear()
|
|
543
|
+
}
|
|
544
|
+
}
|
|
428
545
|
}
|
|
429
546
|
|
|
430
547
|
async closeConnections (peerId: PeerId): Promise<void> {
|
|
@@ -475,7 +592,7 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
475
592
|
const limit = this.opts[name]
|
|
476
593
|
log.trace('checking limit of %s. current value: %d of %d', name, value, limit)
|
|
477
594
|
if (value > limit) {
|
|
478
|
-
log('%s: limit exceeded: %p, %d, pruning %d connection(s)', this.components.getPeerId(), name, value, toPrune)
|
|
595
|
+
log('%s: limit exceeded: %p, %d/%d, pruning %d connection(s)', this.components.getPeerId(), name, value, limit, toPrune)
|
|
479
596
|
await this._maybePruneConnections(toPrune)
|
|
480
597
|
}
|
|
481
598
|
}
|
|
@@ -491,22 +608,49 @@ export class DefaultConnectionManager extends EventEmitter<ConnectionManagerEven
|
|
|
491
608
|
return
|
|
492
609
|
}
|
|
493
610
|
|
|
494
|
-
const peerValues =
|
|
495
|
-
log.trace('sorted peer values: %j', peerValues)
|
|
611
|
+
const peerValues = new PeerMap<number>()
|
|
496
612
|
|
|
497
|
-
|
|
613
|
+
// work out peer values
|
|
614
|
+
for (const connection of connections) {
|
|
615
|
+
const remotePeer = connection.remotePeer
|
|
498
616
|
|
|
499
|
-
|
|
500
|
-
|
|
617
|
+
if (peerValues.has(remotePeer)) {
|
|
618
|
+
continue
|
|
619
|
+
}
|
|
501
620
|
|
|
502
|
-
|
|
503
|
-
if (connection.remotePeer.toString() === peerId) {
|
|
504
|
-
toClose.push(connection)
|
|
505
|
-
}
|
|
621
|
+
const tags = await this.components.getPeerStore().getTags(remotePeer)
|
|
506
622
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
623
|
+
// sum all tag values
|
|
624
|
+
peerValues.set(remotePeer, tags.reduce((acc, curr) => {
|
|
625
|
+
return acc + curr.value
|
|
626
|
+
}, 0))
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
// sort by value, lowest to highest
|
|
630
|
+
const sortedConnections = connections.sort((a, b) => {
|
|
631
|
+
const peerAValue = peerValues.get(a.remotePeer) ?? 0
|
|
632
|
+
const peerBValue = peerValues.get(b.remotePeer) ?? 0
|
|
633
|
+
|
|
634
|
+
if (peerAValue > peerBValue) {
|
|
635
|
+
return 1
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (peerAValue < peerBValue) {
|
|
639
|
+
return -1
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return 0
|
|
643
|
+
})
|
|
644
|
+
|
|
645
|
+
// close some connections
|
|
646
|
+
const toClose = []
|
|
647
|
+
|
|
648
|
+
for (const connection of sortedConnections) {
|
|
649
|
+
log('too many connections open - closing a connection to %p', connection.remotePeer)
|
|
650
|
+
toClose.push(connection)
|
|
651
|
+
|
|
652
|
+
if (toClose.length === toPrune) {
|
|
653
|
+
break
|
|
510
654
|
}
|
|
511
655
|
}
|
|
512
656
|
|
package/src/constants.ts
CHANGED
package/src/fetch/index.ts
CHANGED
|
@@ -10,10 +10,10 @@ import type { Stream } from '@libp2p/interface-connection'
|
|
|
10
10
|
import type { IncomingStreamData } from '@libp2p/interface-registrar'
|
|
11
11
|
import type { Components } from '@libp2p/components'
|
|
12
12
|
import type { AbortOptions } from '@libp2p/interfaces'
|
|
13
|
-
import type { Duplex } from 'it-stream-types'
|
|
14
13
|
import { abortableDuplex } from 'abortable-iterator'
|
|
15
14
|
import { pipe } from 'it-pipe'
|
|
16
15
|
import first from 'it-first'
|
|
16
|
+
import { TimeoutController } from 'timeout-abort-controller'
|
|
17
17
|
|
|
18
18
|
const log = logger('libp2p:fetch')
|
|
19
19
|
|
|
@@ -21,6 +21,11 @@ export interface FetchServiceInit {
|
|
|
21
21
|
protocolPrefix: string
|
|
22
22
|
maxInboundStreams: number
|
|
23
23
|
maxOutboundStreams: number
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* How long we should wait for a remote peer to send any data
|
|
27
|
+
*/
|
|
28
|
+
timeout: number
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
export interface HandleMessageOptions {
|
|
@@ -86,14 +91,22 @@ export class FetchService implements Startable {
|
|
|
86
91
|
log('dialing %s to %p', this.protocol, peer)
|
|
87
92
|
|
|
88
93
|
const connection = await this.components.getConnectionManager().openConnection(peer, options)
|
|
89
|
-
|
|
90
|
-
let
|
|
94
|
+
let timeoutController
|
|
95
|
+
let signal = options.signal
|
|
91
96
|
|
|
92
|
-
//
|
|
93
|
-
if (
|
|
94
|
-
|
|
97
|
+
// create a timeout if no abort signal passed
|
|
98
|
+
if (signal == null) {
|
|
99
|
+
timeoutController = new TimeoutController(this.init.timeout)
|
|
100
|
+
signal = timeoutController.signal
|
|
95
101
|
}
|
|
96
102
|
|
|
103
|
+
const stream = await connection.newStream([this.protocol], {
|
|
104
|
+
signal
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// make stream abortable
|
|
108
|
+
const source = abortableDuplex(stream, signal)
|
|
109
|
+
|
|
97
110
|
try {
|
|
98
111
|
const result = await pipe(
|
|
99
112
|
[FetchRequest.encode({ identifier: key })],
|
|
@@ -129,6 +142,10 @@ export class FetchService implements Startable {
|
|
|
129
142
|
|
|
130
143
|
return result ?? null
|
|
131
144
|
} finally {
|
|
145
|
+
if (timeoutController != null) {
|
|
146
|
+
timeoutController.clear()
|
|
147
|
+
}
|
|
148
|
+
|
|
132
149
|
stream.close()
|
|
133
150
|
}
|
|
134
151
|
}
|
package/src/identify/index.ts
CHANGED
|
@@ -30,9 +30,6 @@ import type { Duplex } from 'it-stream-types'
|
|
|
30
30
|
|
|
31
31
|
const log = logger('libp2p:identify')
|
|
32
32
|
|
|
33
|
-
// https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L48
|
|
34
|
-
const IDENTIFY_TIMEOUT = 60000
|
|
35
|
-
|
|
36
33
|
// https://github.com/libp2p/go-libp2p/blob/8d2e54e1637041d5cf4fac1e531287560bd1f4ac/p2p/protocol/identify/id.go#L52
|
|
37
34
|
const MAX_IDENTIFY_MESSAGE_SIZE = 1024 * 8
|
|
38
35
|
|
|
@@ -54,7 +51,7 @@ export interface IdentifyServiceInit {
|
|
|
54
51
|
/**
|
|
55
52
|
* How long we should wait for a remote peer to send their identify response
|
|
56
53
|
*/
|
|
57
|
-
timeout
|
|
54
|
+
timeout: number
|
|
58
55
|
|
|
59
56
|
/**
|
|
60
57
|
* Identify responses larger than this in bytes will be rejected (default: 8192)
|
|
@@ -167,7 +164,7 @@ export class IdentifyService implements Startable {
|
|
|
167
164
|
const protocols = await this.components.getPeerStore().protoBook.get(this.components.getPeerId())
|
|
168
165
|
|
|
169
166
|
const pushes = connections.map(async connection => {
|
|
170
|
-
const timeoutController = new TimeoutController(this.init.timeout
|
|
167
|
+
const timeoutController = new TimeoutController(this.init.timeout)
|
|
171
168
|
let stream: Stream | undefined
|
|
172
169
|
|
|
173
170
|
try {
|
|
@@ -229,19 +226,21 @@ export class IdentifyService implements Startable {
|
|
|
229
226
|
}
|
|
230
227
|
|
|
231
228
|
async _identify (connection: Connection, options: AbortOptions = {}): Promise<Identify> {
|
|
232
|
-
const stream = await connection.newStream([this.identifyProtocolStr], options)
|
|
233
|
-
let source: Duplex<Uint8Array> = stream
|
|
234
229
|
let timeoutController
|
|
235
230
|
let signal = options.signal
|
|
236
231
|
|
|
237
232
|
// create a timeout if no abort signal passed
|
|
238
233
|
if (signal == null) {
|
|
239
|
-
timeoutController = new TimeoutController(this.init.timeout
|
|
234
|
+
timeoutController = new TimeoutController(this.init.timeout)
|
|
240
235
|
signal = timeoutController.signal
|
|
241
236
|
}
|
|
242
237
|
|
|
243
|
-
|
|
244
|
-
|
|
238
|
+
const stream = await connection.newStream([this.identifyProtocolStr], {
|
|
239
|
+
signal
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
// make stream abortable
|
|
243
|
+
const source = abortableDuplex(stream, signal)
|
|
245
244
|
|
|
246
245
|
try {
|
|
247
246
|
const data = await pipe(
|
|
@@ -370,7 +369,7 @@ export class IdentifyService implements Startable {
|
|
|
370
369
|
*/
|
|
371
370
|
async _handleIdentify (data: IncomingStreamData) {
|
|
372
371
|
const { connection, stream } = data
|
|
373
|
-
const timeoutController = new TimeoutController(this.init.timeout
|
|
372
|
+
const timeoutController = new TimeoutController(this.init.timeout)
|
|
374
373
|
|
|
375
374
|
try {
|
|
376
375
|
const publicKey = this.components.getPeerId().publicKey ?? new Uint8Array(0)
|
|
@@ -421,7 +420,7 @@ export class IdentifyService implements Startable {
|
|
|
421
420
|
*/
|
|
422
421
|
async _handlePush (data: IncomingStreamData) {
|
|
423
422
|
const { connection, stream } = data
|
|
424
|
-
const timeoutController = new TimeoutController(this.init.timeout
|
|
423
|
+
const timeoutController = new TimeoutController(this.init.timeout)
|
|
425
424
|
|
|
426
425
|
let message: Identify | undefined
|
|
427
426
|
try {
|
package/src/libp2p.ts
CHANGED
|
@@ -124,7 +124,8 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|
|
124
124
|
// Set up the Upgrader
|
|
125
125
|
this.components.setUpgrader(new DefaultUpgrader(this.components, {
|
|
126
126
|
connectionEncryption: (init.connectionEncryption ?? []).map(component => this.configureComponent(component)),
|
|
127
|
-
muxers: (init.streamMuxers ?? []).map(component => this.configureComponent(component))
|
|
127
|
+
muxers: (init.streamMuxers ?? []).map(component => this.configureComponent(component)),
|
|
128
|
+
inboundUpgradeTimeout: init.connectionManager.inboundUpgradeTimeout
|
|
128
129
|
}))
|
|
129
130
|
|
|
130
131
|
// Create the Connection Manager
|
|
@@ -309,18 +310,6 @@ export class Libp2pNode extends EventEmitter<Libp2pEvents> implements Libp2p {
|
|
|
309
310
|
)
|
|
310
311
|
|
|
311
312
|
log('libp2p has started')
|
|
312
|
-
|
|
313
|
-
// Once we start, emit any peers we may have already discovered
|
|
314
|
-
// TODO: this should be removed, as we already discovered these peers in the past
|
|
315
|
-
await this.components.getPeerStore().forEach(peer => {
|
|
316
|
-
this.dispatchEvent(new CustomEvent<PeerInfo>('peer:discovery', {
|
|
317
|
-
detail: {
|
|
318
|
-
id: peer.id,
|
|
319
|
-
multiaddrs: peer.addresses.map(addr => addr.multiaddr),
|
|
320
|
-
protocols: peer.protocols
|
|
321
|
-
}
|
|
322
|
-
}))
|
|
323
|
-
})
|
|
324
313
|
} catch (err: any) {
|
|
325
314
|
log.error('An error occurred starting libp2p', err)
|
|
326
315
|
await this.stop()
|
package/src/metrics/index.ts
CHANGED
|
@@ -3,7 +3,7 @@ import each from 'it-foreach'
|
|
|
3
3
|
import LRU from 'hashlru'
|
|
4
4
|
import { METRICS as defaultOptions } from '../constants.js'
|
|
5
5
|
import { DefaultStats, StatsInit } from './stats.js'
|
|
6
|
-
import type { ComponentMetricsUpdate, Metrics, Stats, TrackStreamOptions } from '@libp2p/interface-metrics'
|
|
6
|
+
import type { ComponentMetricsUpdate, Metrics, Stats, TrackedMetric, TrackStreamOptions } from '@libp2p/interface-metrics'
|
|
7
7
|
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
8
8
|
import type { Startable } from '@libp2p/interfaces/startable'
|
|
9
9
|
import type { Duplex } from 'it-stream-types'
|
|
@@ -41,7 +41,7 @@ export class DefaultMetrics implements Metrics, Startable {
|
|
|
41
41
|
private readonly protocolStats: Map<string, DefaultStats>
|
|
42
42
|
private readonly oldPeers: ReturnType<typeof LRU>
|
|
43
43
|
private running: boolean
|
|
44
|
-
private readonly systems: Map<string, Map<string, Map<string,
|
|
44
|
+
private readonly systems: Map<string, Map<string, Map<string, TrackedMetric>>>
|
|
45
45
|
private readonly statsInit: StatsInit
|
|
46
46
|
|
|
47
47
|
constructor (init: MetricsInit) {
|
|
@@ -115,7 +115,7 @@ export class DefaultMetrics implements Metrics, Startable {
|
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
updateComponentMetric (update: ComponentMetricsUpdate) {
|
|
118
|
-
const { system = 'libp2p', component, metric, value } = update
|
|
118
|
+
const { system = 'libp2p', component, metric, value, label, help } = update
|
|
119
119
|
|
|
120
120
|
if (!this.systems.has(system)) {
|
|
121
121
|
this.systems.set(system, new Map())
|
|
@@ -137,7 +137,11 @@ export class DefaultMetrics implements Metrics, Startable {
|
|
|
137
137
|
throw new Error('Unknown metric component')
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
componentMetrics.set(metric,
|
|
140
|
+
componentMetrics.set(metric, {
|
|
141
|
+
label,
|
|
142
|
+
help,
|
|
143
|
+
calculate: typeof value !== 'function' ? () => value : value
|
|
144
|
+
})
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
/**
|