mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-23 12:31:57 +00:00
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
bbdd559a02 | ||
|
4070dcdf55 | ||
|
cb0d7d6c99 | ||
|
d1c48dcbed | ||
|
c4a442788b | ||
|
70a4bb9451 | ||
|
a0516ebc85 | ||
|
b425fa1230 | ||
|
0a485d07b3 | ||
|
0c3ed0a4ac | ||
|
09a0f940df | ||
|
a642ad2a03 | ||
|
8ce2f08589 | ||
|
fe0d9828bb | ||
|
c8e1b08c19 | ||
|
faf1f89d9e | ||
|
76f4ea5e8a | ||
|
2f0b311df7 |
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- run: npx aegir lint
|
||||
- run: npx aegir build
|
||||
- run: npx aegir dep-check
|
||||
- uses: ipfs/aegir/actions/bundle-size@v32.1.0
|
||||
- uses: ipfs/aegir/actions/bundle-size@master
|
||||
name: size
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,3 +1,45 @@
|
||||
## [0.35.7](https://github.com/libp2p/js-libp2p/compare/v0.35.2...v0.35.7) (2021-12-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add tracked map ([#1069](https://github.com/libp2p/js-libp2p/issues/1069)) ([b425fa1](https://github.com/libp2p/js-libp2p/commit/b425fa12304def2a007d43a0aa445c28b766ed02))
|
||||
* clean up pending dial targets ([#1059](https://github.com/libp2p/js-libp2p/issues/1059)) ([bdc9f16](https://github.com/libp2p/js-libp2p/commit/bdc9f16d0cbe56ccf26822f11068e7795bcef046))
|
||||
* fix uncaught promise rejection when finding peers ([#1044](https://github.com/libp2p/js-libp2p/issues/1044)) ([3b683e7](https://github.com/libp2p/js-libp2p/commit/3b683e715686163e229b7b5c3a892327dfd4fc63))
|
||||
* increase the maxlisteners for timeout controllers ([#1065](https://github.com/libp2p/js-libp2p/issues/1065)) ([09a0f94](https://github.com/libp2p/js-libp2p/commit/09a0f940df7fdb4ece34604e85693709df5c213e))
|
||||
* main ci ([#1079](https://github.com/libp2p/js-libp2p/issues/1079)) ([d1c48dc](https://github.com/libp2p/js-libp2p/commit/d1c48dcbeded828f2dd3044cc9aed3f17f02846d))
|
||||
* make error codes consistent ([#1054](https://github.com/libp2p/js-libp2p/issues/1054)) ([b25e0fe](https://github.com/libp2p/js-libp2p/commit/b25e0fe5312db58a06c39500ae84c50fed3a93bd))
|
||||
* type definitions for big dialrequest and persistent peerstore ([#1078](https://github.com/libp2p/js-libp2p/issues/1078)) ([cb0d7d6](https://github.com/libp2p/js-libp2p/commit/cb0d7d6c99d179498f04e76df76e70e4f7d41c4c))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow per-component metrics to be collected ([#1061](https://github.com/libp2p/js-libp2p/issues/1061)) ([2f0b311](https://github.com/libp2p/js-libp2p/commit/2f0b311df7127aa44512c2008142d4ca30268986)), closes [#1060](https://github.com/libp2p/js-libp2p/issues/1060)
|
||||
|
||||
|
||||
|
||||
## [0.35.6](https://github.com/libp2p/js-libp2p/compare/v0.35.5...v0.35.6) (2021-12-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* increase the maxlisteners for timeout controllers ([#1065](https://github.com/libp2p/js-libp2p/issues/1065)) ([09a0f94](https://github.com/libp2p/js-libp2p/commit/09a0f940df7fdb4ece34604e85693709df5c213e))
|
||||
|
||||
|
||||
|
||||
## [0.35.5](https://github.com/libp2p/js-libp2p/compare/v0.35.4...v0.35.5) (2021-12-15)
|
||||
|
||||
|
||||
|
||||
## [0.35.4](https://github.com/libp2p/js-libp2p/compare/v0.35.3...v0.35.4) (2021-12-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow per-component metrics to be collected ([#1061](https://github.com/libp2p/js-libp2p/issues/1061)) ([2f0b311](https://github.com/libp2p/js-libp2p/commit/2f0b311df7127aa44512c2008142d4ca30268986)), closes [#1060](https://github.com/libp2p/js-libp2p/issues/1060)
|
||||
|
||||
|
||||
|
||||
## [0.35.3](https://github.com/libp2p/js-libp2p/compare/v0.35.2...v0.35.3) (2021-12-13)
|
||||
|
||||
|
||||
|
@@ -23,8 +23,8 @@
|
||||
<a href="https://david-dm.org/libp2p/js-libp2p"><img src="https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square" /></a>
|
||||
<a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D12.0.0-orange.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/npm-%3E%3D7.0.0-orange.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D15.0.0-orange.svg?style=flat-square" /></a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
|
@@ -675,15 +675,15 @@ const { NOISE } = require('libp2p-noise')
|
||||
const LevelDatastore = require('datastore-level')
|
||||
|
||||
const datastore = new LevelDatastore('path/to/store')
|
||||
const dsInstant = await datastore.open()
|
||||
await datastore.open() // level database must be ready before node boot
|
||||
|
||||
const node = await Libp2p.create({
|
||||
datastore, // pass the opened datastore
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE]
|
||||
},
|
||||
datastore: dsInstant,
|
||||
peerStore: {
|
||||
persistence: true,
|
||||
threshold: 5
|
||||
@@ -806,8 +806,8 @@ protocols: [
|
||||
|
||||
As libp2p is designed to be a modular networking library, its usage will vary based on individual project needs. We've included links to some existing project configurations for your reference, in case you wish to replicate their configuration:
|
||||
|
||||
- [libp2p-ipfs-nodejs](https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs/src/core/runtime/libp2p-nodejs.js) - libp2p configuration used by js-ipfs when running in Node.js
|
||||
- [libp2p-ipfs-browser](https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs/src/core/runtime/libp2p-browser.js) - libp2p configuration used by js-ipfs when running in a Browser (that supports WebRTC)
|
||||
- [libp2p-ipfs-nodejs](https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-core-config/src/libp2p.js) - libp2p configuration used by js-ipfs when running in Node.js
|
||||
- [libp2p-ipfs-browser](https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-core-config/src/libp2p.browser.js) - libp2p configuration used by js-ipfs when running in a Browser (that supports WebRTC)
|
||||
|
||||
If you have developed a project using `js-libp2p`, please consider submitting your configuration to this list so that it can be found easily by other users.
|
||||
|
||||
|
21
package.json
21
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.35.3",
|
||||
"version": "0.35.7",
|
||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@@ -152,7 +152,7 @@
|
||||
"libp2p-bootstrap": "^0.14.0",
|
||||
"libp2p-delegated-content-routing": "^0.11.0",
|
||||
"libp2p-delegated-peer-routing": "^0.11.1",
|
||||
"libp2p-floodsub": "^0.27.0",
|
||||
"libp2p-floodsub": "^0.28.0",
|
||||
"libp2p-gossipsub": "^0.12.1",
|
||||
"libp2p-interfaces-compliance-tests": "^2.0.1",
|
||||
"libp2p-interop": "^0.5.0",
|
||||
@@ -181,9 +181,9 @@
|
||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||
"Maciej Krüger <mkg20001@gmail.com>",
|
||||
"Hugo Dias <mail@hugodias.me>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"Chris Dostert <chrisdostert@users.noreply.github.com>",
|
||||
"Volker Mische <volker.mische@gmail.com>",
|
||||
"Chris Dostert <chrisdostert@users.noreply.github.com>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"Robert Kiel <robert.kiel@hoprnet.org>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"zeim839 <50573884+zeim839@users.noreply.github.com>",
|
||||
@@ -193,22 +193,23 @@
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"Franck Royer <franck@royer.one>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"Vít Habada <vithabada93@gmail.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"acolytec3 <17355484+acolytec3@users.noreply.github.com>",
|
||||
"Alan Smithee <ggnore.alan.smithee@gmail.com>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"Didrik Nordström <didrik.nordstrom@gmail.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
|
||||
"TJKoury <TJKoury@gmail.com>",
|
||||
"TheStarBoys <41286328+TheStarBoys@users.noreply.github.com>",
|
||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||
"Tim Daubenschütz <tim@daubenschuetz.de>",
|
||||
"XiaoZhang <zxinmyth@gmail.com>",
|
||||
"Yusef Napora <yusef@napora.org>",
|
||||
"Zane Starr <zcstarr@gmail.com>",
|
||||
"ebinks <elizabethjbinks@gmail.com>",
|
||||
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
|
||||
"greenSnot <greenSnot@users.noreply.github.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"mayerwin <mayerwin@users.noreply.github.com>",
|
||||
"mcclure <andi.m.mcclure@gmail.com>",
|
||||
@@ -217,7 +218,8 @@
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"shresthagrawal <34920931+shresthagrawal@users.noreply.github.com>",
|
||||
"swedneck <40505480+swedneck@users.noreply.github.com>",
|
||||
"greenSnot <greenSnot@users.noreply.github.com>",
|
||||
"tuyennhv <vutuyen2636@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
"Aleksei <vozhdb@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
@@ -248,6 +250,7 @@
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Philipp Muens <raute1337@gmx.de>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Smite Chow <xiaopengyou@live.com>"
|
||||
"Smite Chow <xiaopengyou@live.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>"
|
||||
]
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@ const LatencyMonitor = require('./latency-monitor')
|
||||
const retimer = require('retimer')
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const trackedMap = require('../metrics/tracked-map')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const {
|
||||
@@ -32,6 +32,10 @@ const defaultOptions = {
|
||||
defaultPeerValue: 1
|
||||
}
|
||||
|
||||
const METRICS_COMPONENT = 'connection-manager'
|
||||
const METRICS_PEER_CONNECTIONS = 'peer-connections'
|
||||
const METRICS_PEER_VALUES = 'peer-values'
|
||||
|
||||
/**
|
||||
* @typedef {import('../')} Libp2p
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
@@ -83,14 +87,14 @@ class ConnectionManager extends EventEmitter {
|
||||
*
|
||||
* @type {Map<string, number>}
|
||||
*/
|
||||
this._peerValues = new Map()
|
||||
this._peerValues = trackedMap(METRICS_COMPONENT, METRICS_PEER_VALUES, this._libp2p.metrics)
|
||||
|
||||
/**
|
||||
* Map of connections per peer
|
||||
*
|
||||
* @type {Map<string, Connection[]>}
|
||||
*/
|
||||
this.connections = new Map()
|
||||
this.connections = trackedMap(METRICS_COMPONENT, METRICS_PEER_CONNECTIONS, this._libp2p.metrics)
|
||||
|
||||
this._started = false
|
||||
this._timer = null
|
||||
@@ -211,6 +215,7 @@ class ConnectionManager extends EventEmitter {
|
||||
const storedConn = this.connections.get(peerIdStr)
|
||||
|
||||
this.emit('peer:connect', connection)
|
||||
|
||||
if (storedConn) {
|
||||
storedConn.push(connection)
|
||||
} else {
|
||||
@@ -243,6 +248,8 @@ class ConnectionManager extends EventEmitter {
|
||||
this.connections.delete(peerId)
|
||||
this._peerValues.delete(connection.remotePeer.toB58String())
|
||||
this.emit('peer:disconnect', connection)
|
||||
|
||||
this._libp2p.metrics && this._libp2p.metrics.onPeerDisconnected(connection.remotePeer)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -9,11 +9,12 @@ const { Multiaddr } = require('multiaddr')
|
||||
const { TimeoutController } = require('timeout-abort-controller')
|
||||
const { AbortError } = require('abortable-iterator')
|
||||
const { anySignal } = require('any-signal')
|
||||
|
||||
// @ts-expect-error setMaxListeners is missing from the types
|
||||
const { setMaxListeners } = require('events')
|
||||
const DialRequest = require('./dial-request')
|
||||
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
|
||||
const getPeer = require('../get-peer')
|
||||
|
||||
const trackedMap = require('../metrics/tracked-map')
|
||||
const { codes } = require('../errors')
|
||||
const {
|
||||
DIAL_TIMEOUT,
|
||||
@@ -22,6 +23,10 @@ const {
|
||||
MAX_ADDRS_TO_DIAL
|
||||
} = require('../constants')
|
||||
|
||||
const METRICS_COMPONENT = 'dialler'
|
||||
const METRICS_PENDING_DIALS = 'pending-dials'
|
||||
const METRICS_PENDING_DIAL_TARGETS = 'pending-dial-targets'
|
||||
|
||||
/**
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
@@ -44,14 +49,15 @@ const {
|
||||
* @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
|
||||
* @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
|
||||
* @property {Record<string, Resolver>} [resolvers = {}] - multiaddr resolvers to use when dialing
|
||||
* @property {import('../metrics')} [metrics]
|
||||
*
|
||||
* @typedef DialTarget
|
||||
* @property {string} id
|
||||
* @property {Multiaddr[]} addrs
|
||||
*
|
||||
* @typedef PendingDial
|
||||
* @property {DialRequest} dialRequest
|
||||
* @property {TimeoutController} controller
|
||||
* @property {import('./dial-request')} dialRequest
|
||||
* @property {import('timeout-abort-controller').TimeoutController} controller
|
||||
* @property {Promise<Connection>} promise
|
||||
* @property {function():void} destroy
|
||||
*/
|
||||
@@ -69,7 +75,8 @@ class Dialer {
|
||||
maxAddrsToDial = MAX_ADDRS_TO_DIAL,
|
||||
dialTimeout = DIAL_TIMEOUT,
|
||||
maxDialsPerPeer = MAX_PER_PEER_DIALS,
|
||||
resolvers = {}
|
||||
resolvers = {},
|
||||
metrics
|
||||
}) {
|
||||
this.transportManager = transportManager
|
||||
this.peerStore = peerStore
|
||||
@@ -79,8 +86,12 @@ class Dialer {
|
||||
this.timeout = dialTimeout
|
||||
this.maxDialsPerPeer = maxDialsPerPeer
|
||||
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
|
||||
this._pendingDials = new Map()
|
||||
this._pendingDialTargets = new Map()
|
||||
|
||||
/** @type {Map<string, PendingDial>} */
|
||||
this._pendingDials = trackedMap(METRICS_COMPONENT, METRICS_PENDING_DIALS, metrics)
|
||||
|
||||
/** @type {Map<string, { resolve: (value: any) => void, reject: (err: Error) => void}>} */
|
||||
this._pendingDialTargets = trackedMap(METRICS_COMPONENT, METRICS_PENDING_DIAL_TARGETS, metrics)
|
||||
|
||||
for (const [key, value] of Object.entries(resolvers)) {
|
||||
Multiaddr.resolvers.set(key, value)
|
||||
@@ -241,6 +252,10 @@ class Dialer {
|
||||
|
||||
// Combine the timeout signal and options.signal, if provided
|
||||
const timeoutController = new TimeoutController(this.timeout)
|
||||
// this controller will potentially be used while dialing lots of
|
||||
// peers so prevent MaxListenersExceededWarning appearing in the console
|
||||
setMaxListeners && setMaxListeners(Infinity, timeoutController.signal)
|
||||
|
||||
const signals = [timeoutController.signal]
|
||||
options.signal && signals.push(options.signal)
|
||||
const signal = anySignal(signals)
|
||||
@@ -255,6 +270,7 @@ class Dialer {
|
||||
}
|
||||
}
|
||||
this._pendingDials.set(dialTarget.id, pendingDial)
|
||||
|
||||
return pendingDial
|
||||
}
|
||||
|
||||
|
22
src/index.js
22
src/index.js
@@ -48,6 +48,8 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
* @typedef {import('libp2p-interfaces/src/pubsub').PubsubOptions} PubsubOptions
|
||||
* @typedef {import('interface-datastore').Datastore} Datastore
|
||||
* @typedef {import('./pnet')} Protector
|
||||
* @typedef {Object} PersistentPeerStoreOptions
|
||||
* @property {number} [threshold]
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -110,7 +112,7 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
* @property {KeychainOptions & import('./keychain/index').KeychainOptions} [keychain]
|
||||
* @property {MetricsOptions & import('./metrics').MetricsOptions} [metrics]
|
||||
* @property {import('./peer-routing').PeerRoutingOptions} [peerRouting]
|
||||
* @property {PeerStoreOptions & import('./peer-store/persistent').PersistentPeerStoreOptions} [peerStore]
|
||||
* @property {PeerStoreOptions & PersistentPeerStoreOptions} [peerStore]
|
||||
* @property {import('./transport-manager').TransportManagerOptions} [transportManager]
|
||||
* @property {Libp2pConfig} [config]
|
||||
*
|
||||
@@ -161,6 +163,15 @@ class Libp2p extends EventEmitter {
|
||||
this.peerId = this._options.peerId
|
||||
this.datastore = this._options.datastore
|
||||
|
||||
// Create Metrics
|
||||
if (this._options.metrics.enabled) {
|
||||
const metrics = new Metrics({
|
||||
...this._options.metrics
|
||||
})
|
||||
|
||||
this.metrics = metrics
|
||||
}
|
||||
|
||||
this.peerStore = (this.datastore && this._options.peerStore.persistence)
|
||||
? new PersistentPeerStore({
|
||||
peerId: this.peerId,
|
||||
@@ -195,14 +206,6 @@ class Libp2p extends EventEmitter {
|
||||
autoDialInterval: this._options.connectionManager.autoDialInterval
|
||||
})
|
||||
|
||||
// Create Metrics
|
||||
if (this._options.metrics.enabled) {
|
||||
this.metrics = new Metrics({
|
||||
...this._options.metrics,
|
||||
connectionManager: this.connectionManager
|
||||
})
|
||||
}
|
||||
|
||||
// Create keychain
|
||||
if (this._options.keychain && this._options.keychain.datastore) {
|
||||
log('creating keychain')
|
||||
@@ -262,6 +265,7 @@ class Libp2p extends EventEmitter {
|
||||
this.dialer = new Dialer({
|
||||
transportManager: this.transportManager,
|
||||
peerStore: this.peerStore,
|
||||
metrics: this.metrics,
|
||||
...this._options.dialer
|
||||
})
|
||||
|
||||
|
@@ -24,9 +24,6 @@ const directionToEvent = {
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef MetricsProperties
|
||||
* @property {import('../connection-manager')} connectionManager
|
||||
*
|
||||
* @typedef MetricsOptions
|
||||
* @property {number} [computeThrottleMaxQueueSize = defaultOptions.computeThrottleMaxQueueSize]
|
||||
* @property {number} [computeThrottleTimeout = defaultOptions.computeThrottleTimeout]
|
||||
@@ -37,7 +34,7 @@ const directionToEvent = {
|
||||
class Metrics {
|
||||
/**
|
||||
* @class
|
||||
* @param {MetricsProperties & MetricsOptions} options
|
||||
* @param {MetricsOptions} options
|
||||
*/
|
||||
constructor (options) {
|
||||
this._options = mergeOptions(defaultOptions, options)
|
||||
@@ -47,10 +44,7 @@ class Metrics {
|
||||
this._oldPeers = oldPeerLRU(this._options.maxOldPeersRetention)
|
||||
this._running = false
|
||||
this._onMessage = this._onMessage.bind(this)
|
||||
this._connectionManager = options.connectionManager
|
||||
this._connectionManager.on('peer:disconnect', (connection) => {
|
||||
this.onPeerDisconnected(connection.remotePeer)
|
||||
})
|
||||
this._componentMetrics = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +88,22 @@ class Metrics {
|
||||
return Array.from(this._peerStats.keys())
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Map}
|
||||
*/
|
||||
getComponentMetrics () {
|
||||
return this._componentMetrics
|
||||
}
|
||||
|
||||
updateComponentMetric (component, metric, value) {
|
||||
if (!this._componentMetrics.has(component)) {
|
||||
this._componentMetrics.set(component, new Map())
|
||||
}
|
||||
|
||||
const map = this._componentMetrics.get(component)
|
||||
map.set(metric, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the `Stats` object for the given `PeerId` whether it
|
||||
* is a live peer, or in the disconnected peer LRU cache.
|
||||
|
@@ -8,6 +8,7 @@ const retimer = require('retimer')
|
||||
|
||||
/**
|
||||
* @typedef {import('@vascosantos/moving-average').IMovingAverage} IMovingAverage
|
||||
* @typedef {import('bignumber.js').BigNumber} Big
|
||||
*/
|
||||
|
||||
class Stats extends EventEmitter {
|
||||
|
62
src/metrics/tracked-map.js
Normal file
62
src/metrics/tracked-map.js
Normal file
@@ -0,0 +1,62 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @template K
|
||||
* @template V
|
||||
*/
|
||||
class TrackedMap extends Map {
|
||||
/**
|
||||
* @param {string} component
|
||||
* @param {string} name
|
||||
* @param {import('.')} metrics
|
||||
*/
|
||||
constructor (component, name, metrics) {
|
||||
super()
|
||||
|
||||
this._component = component
|
||||
this._name = name
|
||||
this._metrics = metrics
|
||||
|
||||
this._metrics.updateComponentMetric(this._component, this._name, this.size)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} key
|
||||
* @param {V} value
|
||||
*/
|
||||
set (key, value) {
|
||||
super.set(key, value)
|
||||
this._metrics.updateComponentMetric(this._component, this._name, this.size)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {K} key
|
||||
*/
|
||||
delete (key) {
|
||||
const deleted = super.delete(key)
|
||||
this._metrics.updateComponentMetric(this._component, this._name, this.size)
|
||||
return deleted
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template K
|
||||
* @template V
|
||||
* @param {string} component
|
||||
* @param {string} name
|
||||
* @param {import('.')} [metrics]
|
||||
* @returns {Map<K, V>}
|
||||
*/
|
||||
module.exports = (component, name, metrics) => {
|
||||
/** @type {Map<K, V>} */
|
||||
let map
|
||||
|
||||
if (metrics) {
|
||||
map = new TrackedMap(component, name, metrics)
|
||||
} else {
|
||||
map = new Map()
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
@@ -24,6 +24,8 @@ const {
|
||||
// @ts-ignore module with no types
|
||||
} = require('set-delayed-interval')
|
||||
const { DHTPeerRouting } = require('./dht/dht-peer-routing')
|
||||
// @ts-expect-error setMaxListeners is missing from the types
|
||||
const { setMaxListeners } = require('events')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
@@ -149,7 +151,12 @@ class PeerRouting {
|
||||
}
|
||||
|
||||
if (options.timeout) {
|
||||
options.signal = new TimeoutController(options.timeout).signal
|
||||
const controller = new TimeoutController(options.timeout)
|
||||
// this controller will potentially be used while dialing lots of
|
||||
// peers so prevent MaxListenersExceededWarning appearing in the console
|
||||
setMaxListeners && setMaxListeners(Infinity, controller.signal)
|
||||
|
||||
options.signal = controller.signal
|
||||
}
|
||||
|
||||
yield * pipe(
|
||||
|
@@ -3,9 +3,6 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const { randomBytes } = require('libp2p-crypto')
|
||||
const duplexPair = require('it-pair/duplex')
|
||||
const pipe = require('it-pipe')
|
||||
@@ -34,8 +31,7 @@ describe('Metrics', () => {
|
||||
const [local, remote] = duplexPair()
|
||||
const metrics = new Metrics({
|
||||
computeThrottleMaxQueueSize: 1, // compute after every message
|
||||
movingAverageIntervals: [10, 100, 1000],
|
||||
connectionManager: new EventEmitter()
|
||||
movingAverageIntervals: [10, 100, 1000]
|
||||
})
|
||||
|
||||
metrics.trackStream({
|
||||
@@ -70,8 +66,7 @@ describe('Metrics', () => {
|
||||
const [local, remote] = duplexPair()
|
||||
const metrics = new Metrics({
|
||||
computeThrottleMaxQueueSize: 1, // compute after every message
|
||||
movingAverageIntervals: [10, 100, 1000],
|
||||
connectionManager: new EventEmitter()
|
||||
movingAverageIntervals: [10, 100, 1000]
|
||||
})
|
||||
|
||||
metrics.trackStream({
|
||||
@@ -119,8 +114,7 @@ describe('Metrics', () => {
|
||||
const [local2, remote2] = duplexPair()
|
||||
const metrics = new Metrics({
|
||||
computeThrottleMaxQueueSize: 1, // compute after every message
|
||||
movingAverageIntervals: [10, 100, 1000],
|
||||
connectionManager: new EventEmitter()
|
||||
movingAverageIntervals: [10, 100, 1000]
|
||||
})
|
||||
const protocol = '/echo/1.0.0'
|
||||
metrics.start()
|
||||
@@ -175,8 +169,7 @@ describe('Metrics', () => {
|
||||
const [local, remote] = duplexPair()
|
||||
const metrics = new Metrics({
|
||||
computeThrottleMaxQueueSize: 1, // compute after every message
|
||||
movingAverageIntervals: [10, 100, 1000],
|
||||
connectionManager: new EventEmitter()
|
||||
movingAverageIntervals: [10, 100, 1000]
|
||||
})
|
||||
metrics.start()
|
||||
|
||||
@@ -231,8 +224,7 @@ describe('Metrics', () => {
|
||||
}))
|
||||
|
||||
const metrics = new Metrics({
|
||||
maxOldPeersRetention: 5, // Only keep track of 5
|
||||
connectionManager: new EventEmitter()
|
||||
maxOldPeersRetention: 5 // Only keep track of 5
|
||||
})
|
||||
|
||||
// Clone so trackedPeers isn't modified
|
||||
@@ -262,4 +254,22 @@ describe('Metrics', () => {
|
||||
expect(spy).to.have.property('callCount', 1)
|
||||
}
|
||||
})
|
||||
|
||||
it('should allow components to track metrics', () => {
|
||||
const metrics = new Metrics({
|
||||
maxOldPeersRetention: 5 // Only keep track of 5
|
||||
})
|
||||
|
||||
expect(metrics.getComponentMetrics()).to.be.empty()
|
||||
|
||||
const component = 'my-component'
|
||||
const metric = 'some-metric'
|
||||
const value = 1
|
||||
|
||||
metrics.updateComponentMetric(component, metric, value)
|
||||
|
||||
expect(metrics.getComponentMetrics()).to.have.lengthOf(1)
|
||||
expect(metrics.getComponentMetrics().get(component)).to.have.lengthOf(1)
|
||||
expect(metrics.getComponentMetrics().get(component).get(metric)).to.equal(value)
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user