libp2p 0.40.0 → 0.41.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/README.md +21 -2
- package/dist/src/address-manager/index.d.ts.map +1 -1
- package/dist/src/address-manager/index.js +1 -1
- package/dist/src/address-manager/index.js.map +1 -1
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +0 -11
- package/dist/src/config.js.map +1 -1
- package/dist/src/connection/index.d.ts +83 -0
- package/dist/src/connection/index.d.ts.map +1 -0
- package/dist/src/connection/index.js +96 -0
- package/dist/src/connection/index.js.map +1 -0
- package/dist/src/connection-manager/dialer/index.d.ts +13 -14
- package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
- package/dist/src/connection-manager/dialer/index.js +82 -62
- package/dist/src/connection-manager/dialer/index.js.map +1 -1
- package/dist/src/connection-manager/index.d.ts +2 -10
- package/dist/src/connection-manager/index.d.ts.map +1 -1
- package/dist/src/connection-manager/index.js +21 -53
- package/dist/src/connection-manager/index.js.map +1 -1
- package/dist/src/fetch/index.d.ts.map +1 -1
- package/dist/src/fetch/index.js +15 -3
- package/dist/src/fetch/index.js.map +1 -1
- package/dist/src/get-peer.d.ts +2 -2
- package/dist/src/get-peer.d.ts.map +1 -1
- package/dist/src/get-peer.js +2 -5
- package/dist/src/get-peer.js.map +1 -1
- package/dist/src/index.d.ts +10 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/keychain/index.d.ts +1 -1
- package/dist/src/keychain/index.d.ts.map +1 -1
- package/dist/src/libp2p.d.ts +3 -3
- package/dist/src/libp2p.d.ts.map +1 -1
- package/dist/src/libp2p.js +2 -3
- package/dist/src/libp2p.js.map +1 -1
- package/dist/src/registrar.d.ts +5 -0
- package/dist/src/registrar.d.ts.map +1 -1
- package/dist/src/registrar.js +25 -0
- package/dist/src/registrar.js.map +1 -1
- package/dist/src/transport-manager.d.ts.map +1 -1
- package/dist/src/transport-manager.js +1 -2
- package/dist/src/transport-manager.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 +46 -59
- package/dist/src/upgrader.js.map +1 -1
- package/package.json +9 -10
- package/src/address-manager/index.ts +3 -2
- package/src/circuit/README.md +6 -6
- package/src/config.ts +0 -11
- package/src/connection/index.ts +171 -0
- package/src/connection-manager/dialer/index.ts +100 -75
- package/src/connection-manager/index.ts +21 -58
- package/src/fetch/index.ts +16 -3
- package/src/get-peer.ts +3 -7
- package/src/index.ts +15 -7
- package/src/keychain/index.ts +1 -1
- package/src/libp2p.ts +5 -6
- package/src/registrar.ts +29 -2
- package/src/transport-manager.ts +1 -2
- package/src/upgrader.ts +51 -64
- package/src/version.ts +1 -1
- package/dist/src/metrics/index.d.ts +0 -93
- package/dist/src/metrics/index.d.ts.map +0 -1
- package/dist/src/metrics/index.js +0 -234
- package/dist/src/metrics/index.js.map +0 -1
- package/dist/src/metrics/moving-average.d.ts +0 -14
- package/dist/src/metrics/moving-average.d.ts.map +0 -1
- package/dist/src/metrics/moving-average.js +0 -40
- package/dist/src/metrics/moving-average.js.map +0 -1
- package/dist/src/metrics/stats.d.ts +0 -87
- package/dist/src/metrics/stats.d.ts.map +0 -1
- package/dist/src/metrics/stats.js +0 -183
- package/dist/src/metrics/stats.js.map +0 -1
- package/src/metrics/index.ts +0 -311
- package/src/metrics/moving-average.ts +0 -53
- package/src/metrics/stats.ts +0 -238
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from '@libp2p/interfaces/events';
|
|
2
|
-
import type { MovingAverages, Stats, TransferStats } from '@libp2p/interface-metrics';
|
|
3
|
-
export interface StatsEvents {
|
|
4
|
-
'update': CustomEvent<TransferStats>;
|
|
5
|
-
}
|
|
6
|
-
export interface StatsInit {
|
|
7
|
-
enabled: boolean;
|
|
8
|
-
initialCounters: ['dataReceived', 'dataSent'];
|
|
9
|
-
movingAverageIntervals: number[];
|
|
10
|
-
computeThrottleMaxQueueSize: number;
|
|
11
|
-
computeThrottleTimeout: number;
|
|
12
|
-
}
|
|
13
|
-
export declare class DefaultStats extends EventEmitter<StatsEvents> implements Stats {
|
|
14
|
-
private readonly enabled;
|
|
15
|
-
queue: Array<[string, number, number]>;
|
|
16
|
-
private stats;
|
|
17
|
-
private frequencyLastTime;
|
|
18
|
-
private frequencyAccumulators;
|
|
19
|
-
private movingAverages;
|
|
20
|
-
private timeout?;
|
|
21
|
-
private readonly computeThrottleMaxQueueSize;
|
|
22
|
-
private readonly computeThrottleTimeout;
|
|
23
|
-
private readonly movingAverageIntervals;
|
|
24
|
-
/**
|
|
25
|
-
* A queue based manager for stat processing
|
|
26
|
-
*/
|
|
27
|
-
constructor(init: StatsInit);
|
|
28
|
-
/**
|
|
29
|
-
* Initializes the internal timer if there are items in the queue. This
|
|
30
|
-
* should only need to be called if `Stats.stop` was previously called, as
|
|
31
|
-
* `Stats.push` will also start the processing
|
|
32
|
-
*/
|
|
33
|
-
start(): void;
|
|
34
|
-
/**
|
|
35
|
-
* Stops processing and computing of stats by clearing the internal
|
|
36
|
-
* timer
|
|
37
|
-
*/
|
|
38
|
-
stop(): void;
|
|
39
|
-
/**
|
|
40
|
-
* Returns a clone of the current stats.
|
|
41
|
-
*/
|
|
42
|
-
getSnapshot(): TransferStats;
|
|
43
|
-
/**
|
|
44
|
-
* Returns a clone of the internal movingAverages
|
|
45
|
-
*/
|
|
46
|
-
getMovingAverages(): MovingAverages;
|
|
47
|
-
/**
|
|
48
|
-
* Pushes the given operation data to the queue, along with the
|
|
49
|
-
* current Timestamp, then resets the update timer.
|
|
50
|
-
*/
|
|
51
|
-
push(counter: string, inc: number): void;
|
|
52
|
-
/**
|
|
53
|
-
* Resets the timeout for triggering updates.
|
|
54
|
-
*/
|
|
55
|
-
_resetComputeTimeout(): void;
|
|
56
|
-
/**
|
|
57
|
-
* Calculates and returns the timeout for the next update based on
|
|
58
|
-
* the urgency of the update.
|
|
59
|
-
*/
|
|
60
|
-
_nextTimeout(): number;
|
|
61
|
-
/**
|
|
62
|
-
* If there are items in the queue, they will will be processed and
|
|
63
|
-
* the frequency for all items will be updated based on the Timestamp
|
|
64
|
-
* of the last item in the queue. The `update` event will also be emitted
|
|
65
|
-
* with the latest stats.
|
|
66
|
-
*
|
|
67
|
-
* If there are no items in the queue, no action is taken.
|
|
68
|
-
*/
|
|
69
|
-
_update(): void;
|
|
70
|
-
/**
|
|
71
|
-
* For each key in the stats, the frequency and moving averages
|
|
72
|
-
* will be updated via Stats._updateFrequencyFor based on the time
|
|
73
|
-
* difference between calls to this method.
|
|
74
|
-
*/
|
|
75
|
-
_updateFrequency(latestTime: number): void;
|
|
76
|
-
/**
|
|
77
|
-
* Updates the `movingAverages` for the given `key` and also
|
|
78
|
-
* resets the `frequencyAccumulator` for the `key`.
|
|
79
|
-
*/
|
|
80
|
-
_updateFrequencyFor(key: 'dataReceived' | 'dataSent', timeDiffMS: number, latestTime: number): void;
|
|
81
|
-
/**
|
|
82
|
-
* For the given operation, `op`, the stats and `frequencyAccumulator`
|
|
83
|
-
* will be updated or initialized if they don't already exist.
|
|
84
|
-
*/
|
|
85
|
-
_applyOp(op: [string, number, number]): void;
|
|
86
|
-
}
|
|
87
|
-
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/metrics/stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAIrE,OAAO,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAErF,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,WAAW,CAAC,aAAa,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,EAAE,CAAC,cAAc,EAAE,UAAU,CAAC,CAAA;IAC7C,sBAAsB,EAAE,MAAM,EAAE,CAAA;IAChC,2BAA2B,EAAE,MAAM,CAAA;IACnC,sBAAsB,EAAE,MAAM,CAAA;CAC/B;AAED,qBAAa,YAAa,SAAQ,YAAY,CAAC,WAAW,CAAE,YAAW,KAAK;IAC1E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAC1B,KAAK,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC7C,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,OAAO,CAAC,CAAK;IACrB,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAAQ;IACpD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAQ;IAC/C,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAU;IAEjD;;OAEG;gBACU,IAAI,EAAE,SAAS;IAmC5B;;;;OAIG;IACH,KAAK;IAUL;;;OAGG;IACH,IAAI;IAOJ;;OAEG;IACH,WAAW;IAIX;;OAEG;IACH,iBAAiB,IAAK,cAAc;IAIpC;;;OAGG;IACH,IAAI,CAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;IAKlC;;OAEG;IACH,oBAAoB;IAIpB;;;OAGG;IACH,YAAY;IAOZ;;;;;;;OAOG;IACH,OAAO;IAqBP;;;;OAIG;IACH,gBAAgB,CAAE,UAAU,EAAE,MAAM;IASpC;;;OAGG;IACH,mBAAmB,CAAE,GAAG,EAAE,cAAc,GAAG,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAwB7F;;;OAGG;IACH,QAAQ,CAAE,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;CA2BvC"}
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events';
|
|
2
|
-
import { createMovingAverage } from './moving-average.js';
|
|
3
|
-
// @ts-expect-error no types
|
|
4
|
-
import retimer from 'retimer';
|
|
5
|
-
export class DefaultStats extends EventEmitter {
|
|
6
|
-
/**
|
|
7
|
-
* A queue based manager for stat processing
|
|
8
|
-
*/
|
|
9
|
-
constructor(init) {
|
|
10
|
-
super();
|
|
11
|
-
this.enabled = init.enabled;
|
|
12
|
-
this.queue = [];
|
|
13
|
-
this.stats = {
|
|
14
|
-
dataReceived: 0n,
|
|
15
|
-
dataSent: 0n
|
|
16
|
-
};
|
|
17
|
-
this.frequencyLastTime = Date.now();
|
|
18
|
-
this.frequencyAccumulators = {};
|
|
19
|
-
this.movingAverages = {
|
|
20
|
-
dataReceived: [],
|
|
21
|
-
dataSent: []
|
|
22
|
-
};
|
|
23
|
-
this.computeThrottleMaxQueueSize = init.computeThrottleMaxQueueSize;
|
|
24
|
-
this.computeThrottleTimeout = init.computeThrottleTimeout;
|
|
25
|
-
this._update = this._update.bind(this);
|
|
26
|
-
this.movingAverageIntervals = init.movingAverageIntervals;
|
|
27
|
-
for (let i = 0; i < init.initialCounters.length; i++) {
|
|
28
|
-
const key = init.initialCounters[i];
|
|
29
|
-
this.stats[key] = 0n;
|
|
30
|
-
this.movingAverages[key] = [];
|
|
31
|
-
for (let k = 0; k < this.movingAverageIntervals.length; k++) {
|
|
32
|
-
const interval = this.movingAverageIntervals[k];
|
|
33
|
-
const ma = this.movingAverages[key][interval] = createMovingAverage(interval);
|
|
34
|
-
ma.push(this.frequencyLastTime, 0);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Initializes the internal timer if there are items in the queue. This
|
|
40
|
-
* should only need to be called if `Stats.stop` was previously called, as
|
|
41
|
-
* `Stats.push` will also start the processing
|
|
42
|
-
*/
|
|
43
|
-
start() {
|
|
44
|
-
if (!this.enabled) {
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
if (this.queue.length > 0) {
|
|
48
|
-
this._resetComputeTimeout();
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Stops processing and computing of stats by clearing the internal
|
|
53
|
-
* timer
|
|
54
|
-
*/
|
|
55
|
-
stop() {
|
|
56
|
-
if (this.timeout != null) {
|
|
57
|
-
this.timeout.clear();
|
|
58
|
-
this.timeout = null;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Returns a clone of the current stats.
|
|
63
|
-
*/
|
|
64
|
-
getSnapshot() {
|
|
65
|
-
return Object.assign({}, this.stats);
|
|
66
|
-
}
|
|
67
|
-
/**
|
|
68
|
-
* Returns a clone of the internal movingAverages
|
|
69
|
-
*/
|
|
70
|
-
getMovingAverages() {
|
|
71
|
-
return Object.assign({}, this.movingAverages);
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Pushes the given operation data to the queue, along with the
|
|
75
|
-
* current Timestamp, then resets the update timer.
|
|
76
|
-
*/
|
|
77
|
-
push(counter, inc) {
|
|
78
|
-
this.queue.push([counter, inc, Date.now()]);
|
|
79
|
-
this._resetComputeTimeout();
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Resets the timeout for triggering updates.
|
|
83
|
-
*/
|
|
84
|
-
_resetComputeTimeout() {
|
|
85
|
-
this.timeout = retimer(this._update, this._nextTimeout());
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Calculates and returns the timeout for the next update based on
|
|
89
|
-
* the urgency of the update.
|
|
90
|
-
*/
|
|
91
|
-
_nextTimeout() {
|
|
92
|
-
// calculate the need for an update, depending on the queue length
|
|
93
|
-
const urgency = this.queue.length / this.computeThrottleMaxQueueSize;
|
|
94
|
-
const timeout = Math.max(this.computeThrottleTimeout * (1 - urgency), 0);
|
|
95
|
-
return timeout;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* If there are items in the queue, they will will be processed and
|
|
99
|
-
* the frequency for all items will be updated based on the Timestamp
|
|
100
|
-
* of the last item in the queue. The `update` event will also be emitted
|
|
101
|
-
* with the latest stats.
|
|
102
|
-
*
|
|
103
|
-
* If there are no items in the queue, no action is taken.
|
|
104
|
-
*/
|
|
105
|
-
_update() {
|
|
106
|
-
this.timeout = null;
|
|
107
|
-
if (this.queue.length > 0) {
|
|
108
|
-
let last = ['', 0, 0];
|
|
109
|
-
for (last of this.queue) {
|
|
110
|
-
this._applyOp(last);
|
|
111
|
-
}
|
|
112
|
-
this.queue = [];
|
|
113
|
-
if (last.length > 2 && last[0] !== '') {
|
|
114
|
-
this._updateFrequency(last[2]); // contains timestamp of last op
|
|
115
|
-
}
|
|
116
|
-
this.dispatchEvent(new CustomEvent('update', {
|
|
117
|
-
detail: this.stats
|
|
118
|
-
}));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* For each key in the stats, the frequency and moving averages
|
|
123
|
-
* will be updated via Stats._updateFrequencyFor based on the time
|
|
124
|
-
* difference between calls to this method.
|
|
125
|
-
*/
|
|
126
|
-
_updateFrequency(latestTime) {
|
|
127
|
-
const timeDiff = latestTime - this.frequencyLastTime;
|
|
128
|
-
this._updateFrequencyFor('dataReceived', timeDiff, latestTime);
|
|
129
|
-
this._updateFrequencyFor('dataSent', timeDiff, latestTime);
|
|
130
|
-
this.frequencyLastTime = latestTime;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Updates the `movingAverages` for the given `key` and also
|
|
134
|
-
* resets the `frequencyAccumulator` for the `key`.
|
|
135
|
-
*/
|
|
136
|
-
_updateFrequencyFor(key, timeDiffMS, latestTime) {
|
|
137
|
-
const count = this.frequencyAccumulators[key] ?? 0;
|
|
138
|
-
this.frequencyAccumulators[key] = 0;
|
|
139
|
-
// if `timeDiff` is zero, `hz` becomes Infinity, so we fallback to 1ms
|
|
140
|
-
const safeTimeDiff = timeDiffMS ?? 1;
|
|
141
|
-
const hz = (count / safeTimeDiff) * 1000;
|
|
142
|
-
let movingAverages = this.movingAverages[key];
|
|
143
|
-
if (movingAverages == null) {
|
|
144
|
-
movingAverages = this.movingAverages[key] = [];
|
|
145
|
-
}
|
|
146
|
-
const intervals = this.movingAverageIntervals;
|
|
147
|
-
for (let i = 0; i < intervals.length; i++) {
|
|
148
|
-
const movingAverageInterval = intervals[i];
|
|
149
|
-
let movingAverage = movingAverages[movingAverageInterval];
|
|
150
|
-
if (movingAverage == null) {
|
|
151
|
-
movingAverage = movingAverages[movingAverageInterval] = createMovingAverage(movingAverageInterval);
|
|
152
|
-
}
|
|
153
|
-
movingAverage.push(latestTime, hz);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* For the given operation, `op`, the stats and `frequencyAccumulator`
|
|
158
|
-
* will be updated or initialized if they don't already exist.
|
|
159
|
-
*/
|
|
160
|
-
_applyOp(op) {
|
|
161
|
-
const key = op[0];
|
|
162
|
-
const inc = op[1];
|
|
163
|
-
if (typeof inc !== 'number') {
|
|
164
|
-
throw new Error('invalid increment number');
|
|
165
|
-
}
|
|
166
|
-
let n;
|
|
167
|
-
if (!Object.prototype.hasOwnProperty.call(this.stats, key)) {
|
|
168
|
-
// @ts-expect-error cannot index type with key
|
|
169
|
-
n = this.stats[key] = 0n;
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
// @ts-expect-error cannot index type with key
|
|
173
|
-
n = this.stats[key];
|
|
174
|
-
}
|
|
175
|
-
// @ts-expect-error cannot index type with key
|
|
176
|
-
this.stats[key] = n + BigInt(inc);
|
|
177
|
-
if (this.frequencyAccumulators[key] == null) {
|
|
178
|
-
this.frequencyAccumulators[key] = 0;
|
|
179
|
-
}
|
|
180
|
-
this.frequencyAccumulators[key] += inc;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
//# sourceMappingURL=stats.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/metrics/stats.ts"],"names":[],"mappings":"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"}
|
package/src/metrics/index.ts
DELETED
|
@@ -1,311 +0,0 @@
|
|
|
1
|
-
import { pipe } from 'it-pipe'
|
|
2
|
-
import each from 'it-foreach'
|
|
3
|
-
import LRU from 'hashlru'
|
|
4
|
-
import { METRICS as defaultOptions } from '../constants.js'
|
|
5
|
-
import { DefaultStats, StatsInit } from './stats.js'
|
|
6
|
-
import type { ComponentMetricsUpdate, Metrics, Stats, TrackedMetric, TrackStreamOptions } from '@libp2p/interface-metrics'
|
|
7
|
-
import type { PeerId } from '@libp2p/interface-peer-id'
|
|
8
|
-
import type { Startable } from '@libp2p/interfaces/startable'
|
|
9
|
-
|
|
10
|
-
const initialCounters: ['dataReceived', 'dataSent'] = [
|
|
11
|
-
'dataReceived',
|
|
12
|
-
'dataSent'
|
|
13
|
-
]
|
|
14
|
-
|
|
15
|
-
const directionToEvent = {
|
|
16
|
-
in: 'dataReceived',
|
|
17
|
-
out: 'dataSent'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface OnMessageOptions {
|
|
21
|
-
remotePeer: PeerId
|
|
22
|
-
protocol?: string
|
|
23
|
-
direction: 'in' | 'out'
|
|
24
|
-
dataLength: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface MetricsInit {
|
|
28
|
-
enabled: boolean
|
|
29
|
-
computeThrottleMaxQueueSize: number
|
|
30
|
-
computeThrottleTimeout: number
|
|
31
|
-
movingAverageIntervals: number[]
|
|
32
|
-
maxOldPeersRetention: number
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export class DefaultMetrics implements Metrics, Startable {
|
|
36
|
-
public globalStats: DefaultStats
|
|
37
|
-
|
|
38
|
-
private readonly enabled: boolean
|
|
39
|
-
private readonly peerStats: Map<string, DefaultStats>
|
|
40
|
-
private readonly protocolStats: Map<string, DefaultStats>
|
|
41
|
-
private readonly oldPeers: ReturnType<typeof LRU>
|
|
42
|
-
private running: boolean
|
|
43
|
-
private readonly systems: Map<string, Map<string, Map<string, TrackedMetric>>>
|
|
44
|
-
private readonly statsInit: StatsInit
|
|
45
|
-
|
|
46
|
-
constructor (init: MetricsInit) {
|
|
47
|
-
this.enabled = init.enabled
|
|
48
|
-
this.statsInit = {
|
|
49
|
-
...init,
|
|
50
|
-
initialCounters
|
|
51
|
-
}
|
|
52
|
-
this.globalStats = new DefaultStats(this.statsInit)
|
|
53
|
-
this.peerStats = new Map()
|
|
54
|
-
this.protocolStats = new Map()
|
|
55
|
-
this.oldPeers = LRU(init.maxOldPeersRetention ?? defaultOptions.maxOldPeersRetention)
|
|
56
|
-
this.running = false
|
|
57
|
-
this._onMessage = this._onMessage.bind(this)
|
|
58
|
-
this.systems = new Map()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
isStarted () {
|
|
62
|
-
return this.running
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Must be called for stats to saved. Any data pushed for tracking
|
|
67
|
-
* will be ignored.
|
|
68
|
-
*/
|
|
69
|
-
async start () {
|
|
70
|
-
if (!this.enabled) {
|
|
71
|
-
return
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
this.running = true
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Stops all averages timers and prevents new data from being tracked.
|
|
79
|
-
* Once `stop` is called, `start` must be called to resume stats tracking.
|
|
80
|
-
*/
|
|
81
|
-
async stop () {
|
|
82
|
-
if (!this.running) {
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
this.running = false
|
|
87
|
-
this.globalStats.stop()
|
|
88
|
-
|
|
89
|
-
for (const stats of this.peerStats.values()) {
|
|
90
|
-
stats.stop()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
for (const stats of this.protocolStats.values()) {
|
|
94
|
-
stats.stop()
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Gets the global `Stats` object
|
|
100
|
-
*/
|
|
101
|
-
getGlobal () {
|
|
102
|
-
return this.globalStats
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Returns a list of `PeerId` strings currently being tracked
|
|
107
|
-
*/
|
|
108
|
-
getPeers () {
|
|
109
|
-
return Array.from(this.peerStats.keys())
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
getComponentMetrics () {
|
|
113
|
-
return this.systems
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
updateComponentMetric (update: ComponentMetricsUpdate) {
|
|
117
|
-
const { system = 'libp2p', component, metric, value, label, help } = update
|
|
118
|
-
|
|
119
|
-
if (!this.systems.has(system)) {
|
|
120
|
-
this.systems.set(system, new Map())
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const systemMetrics = this.systems.get(system)
|
|
124
|
-
|
|
125
|
-
if (systemMetrics == null) {
|
|
126
|
-
throw new Error('Unknown metric system')
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (!systemMetrics.has(component)) {
|
|
130
|
-
systemMetrics.set(component, new Map())
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const componentMetrics = systemMetrics.get(component)
|
|
134
|
-
|
|
135
|
-
if (componentMetrics == null) {
|
|
136
|
-
throw new Error('Unknown metric component')
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
componentMetrics.set(metric, {
|
|
140
|
-
label,
|
|
141
|
-
help,
|
|
142
|
-
calculate: typeof value !== 'function' ? () => value : value
|
|
143
|
-
})
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Returns the `Stats` object for the given `PeerId` whether it
|
|
148
|
-
* is a live peer, or in the disconnected peer LRU cache.
|
|
149
|
-
*/
|
|
150
|
-
forPeer (peerId: PeerId): Stats | undefined {
|
|
151
|
-
const idString = peerId.toString()
|
|
152
|
-
return this.peerStats.get(idString) ?? this.oldPeers.get(idString)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Returns a list of all protocol strings currently being tracked
|
|
157
|
-
*/
|
|
158
|
-
getProtocols (): string[] {
|
|
159
|
-
return Array.from(this.protocolStats.keys())
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Returns the `Stats` object for the given `protocol`
|
|
164
|
-
*/
|
|
165
|
-
forProtocol (protocol: string): Stats | undefined {
|
|
166
|
-
return this.protocolStats.get(protocol)
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Should be called when all connections to a given peer
|
|
171
|
-
* have closed. The `Stats` collection for the peer will
|
|
172
|
-
* be stopped and moved to an LRU for temporary retention.
|
|
173
|
-
*/
|
|
174
|
-
onPeerDisconnected (peerId: PeerId) {
|
|
175
|
-
const idString = peerId.toString()
|
|
176
|
-
const peerStats = this.peerStats.get(idString)
|
|
177
|
-
|
|
178
|
-
if (peerStats != null) {
|
|
179
|
-
peerStats.stop()
|
|
180
|
-
|
|
181
|
-
this.peerStats.delete(idString)
|
|
182
|
-
this.oldPeers.set(idString, peerStats)
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Takes the metadata for a message and tracks it in the
|
|
188
|
-
* appropriate categories. If the protocol is present, protocol
|
|
189
|
-
* stats will also be tracked.
|
|
190
|
-
*/
|
|
191
|
-
_onMessage (opts: OnMessageOptions) {
|
|
192
|
-
if (!this.running) {
|
|
193
|
-
return
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const { remotePeer, protocol, direction, dataLength } = opts
|
|
197
|
-
|
|
198
|
-
const key = directionToEvent[direction]
|
|
199
|
-
|
|
200
|
-
let peerStats = this.forPeer(remotePeer)
|
|
201
|
-
if (peerStats == null) {
|
|
202
|
-
const stats = new DefaultStats(this.statsInit)
|
|
203
|
-
this.peerStats.set(remotePeer.toString(), stats)
|
|
204
|
-
peerStats = stats
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
// Peer and global stats
|
|
208
|
-
peerStats.push(key, dataLength)
|
|
209
|
-
this.globalStats.push(key, dataLength)
|
|
210
|
-
|
|
211
|
-
// Protocol specific stats
|
|
212
|
-
if (protocol != null) {
|
|
213
|
-
let protocolStats = this.forProtocol(protocol)
|
|
214
|
-
|
|
215
|
-
if (protocolStats == null) {
|
|
216
|
-
const stats = new DefaultStats(this.statsInit)
|
|
217
|
-
this.protocolStats.set(protocol, stats)
|
|
218
|
-
protocolStats = stats
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
protocolStats.push(key, dataLength)
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* Replaces the `PeerId` string with the given `peerId`.
|
|
227
|
-
* If stats are already being tracked for the given `peerId`, the
|
|
228
|
-
* placeholder stats will be merged with the existing stats.
|
|
229
|
-
*
|
|
230
|
-
* @param {PeerId} placeholder - A peerId string
|
|
231
|
-
* @param {PeerId} peerId
|
|
232
|
-
* @returns {void}
|
|
233
|
-
*/
|
|
234
|
-
updatePlaceholder (placeholder: PeerId, peerId: PeerId) {
|
|
235
|
-
if (!this.running) {
|
|
236
|
-
return
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const placeholderString = placeholder.toString()
|
|
240
|
-
const placeholderStats = this.peerStats.get(placeholderString) ?? this.oldPeers.get(placeholderString)
|
|
241
|
-
const peerIdString = peerId.toString()
|
|
242
|
-
const existingStats = this.peerStats.get(peerIdString) ?? this.oldPeers.get(peerIdString)
|
|
243
|
-
let mergedStats = placeholderStats
|
|
244
|
-
|
|
245
|
-
// If we already have stats, merge the two
|
|
246
|
-
if (existingStats != null) {
|
|
247
|
-
// If existing, merge
|
|
248
|
-
mergedStats = mergeStats(existingStats, mergedStats)
|
|
249
|
-
// Attempt to delete from the old peers list just in case it was tracked there
|
|
250
|
-
this.oldPeers.remove(peerIdString)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
this.peerStats.delete(placeholder.toString())
|
|
254
|
-
this.peerStats.set(peerIdString, mergedStats)
|
|
255
|
-
mergedStats.start()
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Tracks data running through a given Duplex Iterable `stream`. If
|
|
260
|
-
* the `peerId` is not provided, a placeholder string will be created and
|
|
261
|
-
* returned. This allows lazy tracking of a peer when the peer is not yet known.
|
|
262
|
-
* When the `PeerId` is known, `Metrics.updatePlaceholder` should be called
|
|
263
|
-
* with the placeholder string returned from here, and the known `PeerId`.
|
|
264
|
-
*/
|
|
265
|
-
trackStream (opts: TrackStreamOptions): void {
|
|
266
|
-
const { stream, remotePeer, protocol } = opts
|
|
267
|
-
|
|
268
|
-
if (!this.running) {
|
|
269
|
-
return
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const source = stream.source
|
|
273
|
-
stream.source = each(source, chunk => this._onMessage({
|
|
274
|
-
remotePeer,
|
|
275
|
-
protocol,
|
|
276
|
-
direction: 'in',
|
|
277
|
-
dataLength: chunk.byteLength
|
|
278
|
-
}))
|
|
279
|
-
|
|
280
|
-
const sink = stream.sink
|
|
281
|
-
stream.sink = async source => {
|
|
282
|
-
return await pipe(
|
|
283
|
-
source,
|
|
284
|
-
(source) => each(source, chunk => {
|
|
285
|
-
this._onMessage({
|
|
286
|
-
remotePeer,
|
|
287
|
-
protocol,
|
|
288
|
-
direction: 'out',
|
|
289
|
-
dataLength: chunk.byteLength
|
|
290
|
-
})
|
|
291
|
-
}),
|
|
292
|
-
sink
|
|
293
|
-
)
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/**
|
|
299
|
-
* Merges `other` into `target`. `target` will be modified
|
|
300
|
-
* and returned
|
|
301
|
-
*/
|
|
302
|
-
function mergeStats (target: DefaultStats, other: DefaultStats) {
|
|
303
|
-
target.stop()
|
|
304
|
-
other.stop()
|
|
305
|
-
|
|
306
|
-
// Merge queues
|
|
307
|
-
target.queue = [...target.queue, ...other.queue]
|
|
308
|
-
|
|
309
|
-
// TODO: how to merge moving averages?
|
|
310
|
-
return target
|
|
311
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import type { MovingAverage } from '@libp2p/interface-metrics'
|
|
2
|
-
|
|
3
|
-
export class DefaultMovingAverage {
|
|
4
|
-
public movingAverage: number
|
|
5
|
-
public variance: number
|
|
6
|
-
public deviation: number
|
|
7
|
-
public forecast: number
|
|
8
|
-
private readonly timespan: number
|
|
9
|
-
private previousTime?: number
|
|
10
|
-
|
|
11
|
-
constructor (timespan: number) {
|
|
12
|
-
if (typeof timespan !== 'number') {
|
|
13
|
-
throw new Error('must provide a timespan to the moving average constructor')
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (timespan <= 0) {
|
|
17
|
-
throw new Error('must provide a timespan > 0 to the moving average constructor')
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
this.timespan = timespan
|
|
21
|
-
this.movingAverage = 0
|
|
22
|
-
this.variance = 0
|
|
23
|
-
this.deviation = 0
|
|
24
|
-
this.forecast = 0
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
alpha (t: number, pt: number) {
|
|
28
|
-
return 1 - (Math.exp(-(t - pt) / this.timespan))
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
push (time: number, value: number) {
|
|
32
|
-
if (this.previousTime != null) {
|
|
33
|
-
// calculate moving average
|
|
34
|
-
const a = this.alpha(time, this.previousTime)
|
|
35
|
-
const diff = value - this.movingAverage
|
|
36
|
-
const incr = a * diff
|
|
37
|
-
this.movingAverage = a * value + (1 - a) * this.movingAverage
|
|
38
|
-
// calculate variance & deviation
|
|
39
|
-
this.variance = (1 - a) * (this.variance + diff * incr)
|
|
40
|
-
this.deviation = Math.sqrt(this.variance)
|
|
41
|
-
// calculate forecast
|
|
42
|
-
this.forecast = this.movingAverage + a * diff
|
|
43
|
-
} else {
|
|
44
|
-
this.movingAverage = value
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
this.previousTime = time
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function createMovingAverage (timespan: number): MovingAverage {
|
|
52
|
-
return new DefaultMovingAverage(timespan)
|
|
53
|
-
}
|