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.
Files changed (78) hide show
  1. package/README.md +21 -2
  2. package/dist/src/address-manager/index.d.ts.map +1 -1
  3. package/dist/src/address-manager/index.js +1 -1
  4. package/dist/src/address-manager/index.js.map +1 -1
  5. package/dist/src/config.d.ts.map +1 -1
  6. package/dist/src/config.js +0 -11
  7. package/dist/src/config.js.map +1 -1
  8. package/dist/src/connection/index.d.ts +83 -0
  9. package/dist/src/connection/index.d.ts.map +1 -0
  10. package/dist/src/connection/index.js +96 -0
  11. package/dist/src/connection/index.js.map +1 -0
  12. package/dist/src/connection-manager/dialer/index.d.ts +13 -14
  13. package/dist/src/connection-manager/dialer/index.d.ts.map +1 -1
  14. package/dist/src/connection-manager/dialer/index.js +82 -62
  15. package/dist/src/connection-manager/dialer/index.js.map +1 -1
  16. package/dist/src/connection-manager/index.d.ts +2 -10
  17. package/dist/src/connection-manager/index.d.ts.map +1 -1
  18. package/dist/src/connection-manager/index.js +21 -53
  19. package/dist/src/connection-manager/index.js.map +1 -1
  20. package/dist/src/fetch/index.d.ts.map +1 -1
  21. package/dist/src/fetch/index.js +15 -3
  22. package/dist/src/fetch/index.js.map +1 -1
  23. package/dist/src/get-peer.d.ts +2 -2
  24. package/dist/src/get-peer.d.ts.map +1 -1
  25. package/dist/src/get-peer.js +2 -5
  26. package/dist/src/get-peer.js.map +1 -1
  27. package/dist/src/index.d.ts +10 -6
  28. package/dist/src/index.d.ts.map +1 -1
  29. package/dist/src/index.js +7 -1
  30. package/dist/src/index.js.map +1 -1
  31. package/dist/src/keychain/index.d.ts +1 -1
  32. package/dist/src/keychain/index.d.ts.map +1 -1
  33. package/dist/src/libp2p.d.ts +3 -3
  34. package/dist/src/libp2p.d.ts.map +1 -1
  35. package/dist/src/libp2p.js +2 -3
  36. package/dist/src/libp2p.js.map +1 -1
  37. package/dist/src/registrar.d.ts +5 -0
  38. package/dist/src/registrar.d.ts.map +1 -1
  39. package/dist/src/registrar.js +25 -0
  40. package/dist/src/registrar.js.map +1 -1
  41. package/dist/src/transport-manager.d.ts.map +1 -1
  42. package/dist/src/transport-manager.js +1 -2
  43. package/dist/src/transport-manager.js.map +1 -1
  44. package/dist/src/upgrader.d.ts +1 -1
  45. package/dist/src/upgrader.d.ts.map +1 -1
  46. package/dist/src/upgrader.js +46 -59
  47. package/dist/src/upgrader.js.map +1 -1
  48. package/package.json +9 -10
  49. package/src/address-manager/index.ts +3 -2
  50. package/src/circuit/README.md +6 -6
  51. package/src/config.ts +0 -11
  52. package/src/connection/index.ts +171 -0
  53. package/src/connection-manager/dialer/index.ts +100 -75
  54. package/src/connection-manager/index.ts +21 -58
  55. package/src/fetch/index.ts +16 -3
  56. package/src/get-peer.ts +3 -7
  57. package/src/index.ts +15 -7
  58. package/src/keychain/index.ts +1 -1
  59. package/src/libp2p.ts +5 -6
  60. package/src/registrar.ts +29 -2
  61. package/src/transport-manager.ts +1 -2
  62. package/src/upgrader.ts +51 -64
  63. package/src/version.ts +1 -1
  64. package/dist/src/metrics/index.d.ts +0 -93
  65. package/dist/src/metrics/index.d.ts.map +0 -1
  66. package/dist/src/metrics/index.js +0 -234
  67. package/dist/src/metrics/index.js.map +0 -1
  68. package/dist/src/metrics/moving-average.d.ts +0 -14
  69. package/dist/src/metrics/moving-average.d.ts.map +0 -1
  70. package/dist/src/metrics/moving-average.js +0 -40
  71. package/dist/src/metrics/moving-average.js.map +0 -1
  72. package/dist/src/metrics/stats.d.ts +0 -87
  73. package/dist/src/metrics/stats.d.ts.map +0 -1
  74. package/dist/src/metrics/stats.js +0 -183
  75. package/dist/src/metrics/stats.js.map +0 -1
  76. package/src/metrics/index.ts +0 -311
  77. package/src/metrics/moving-average.ts +0 -53
  78. package/src/metrics/stats.ts +0 -238
package/src/upgrader.ts CHANGED
@@ -1,11 +1,8 @@
1
1
  import { logger } from '@libp2p/logger'
2
2
  import errCode from 'err-code'
3
3
  import * as mss from '@libp2p/multistream-select'
4
- import { pipe } from 'it-pipe'
5
- // @ts-expect-error mutable-proxy does not export types
6
- import mutableProxy from 'mutable-proxy'
7
4
  import { codes } from './errors.js'
8
- import { createConnection } from '@libp2p/connection'
5
+ import { createConnection } from './connection/index.js'
9
6
  import { CustomEvent, EventEmitter } from '@libp2p/interfaces/events'
10
7
  import { peerIdFromString } from '@libp2p/peer-id'
11
8
  import type { MultiaddrConnection, Connection, Stream, ConnectionGater, ConnectionProtector } from '@libp2p/interface-connection'
@@ -134,7 +131,7 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
134
131
  /**
135
132
  * Upgrades an inbound connection
136
133
  */
137
- async upgradeInbound (maConn: MultiaddrConnection): Promise<Connection> {
134
+ async upgradeInbound (maConn: MultiaddrConnection, opts?: UpgraderOptions): Promise<Connection> {
138
135
  const accept = await this.components.connectionManager.acceptIncomingConnection(maConn)
139
136
 
140
137
  if (!accept) {
@@ -146,9 +143,6 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
146
143
  let upgradedConn: Duplex<Uint8Array>
147
144
  let muxerFactory: StreamMuxerFactory | undefined
148
145
  let cryptoProtocol
149
- let setPeer
150
- let proxyPeer
151
- const metrics = this.components.metrics
152
146
 
153
147
  const timeoutController = new TimeoutController(this.inboundUpgradeTimeout)
154
148
 
@@ -166,49 +160,62 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
166
160
  throw errCode(new Error('The multiaddr connection is blocked by gater.acceptConnection'), codes.ERR_CONNECTION_INTERCEPTED)
167
161
  }
168
162
 
169
- if (metrics != null) {
170
- ({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
171
- const idString = `${(Math.random() * 1e9).toString(36)}${Date.now()}`
172
- setPeer({ toString: () => idString })
173
- metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
174
- }
163
+ this.components.metrics?.trackMultiaddrConnection(maConn)
175
164
 
176
165
  log('starting the inbound connection upgrade')
177
166
 
178
167
  // Protect
179
168
  let protectedConn = maConn
180
- const protector = this.components.connectionProtector
181
169
 
182
- if (protector != null) {
183
- log('protecting the inbound connection')
184
- protectedConn = await protector.protect(maConn)
170
+ if (opts?.skipProtection !== true) {
171
+ const protector = this.components.connectionProtector
172
+
173
+ if (protector != null) {
174
+ log('protecting the inbound connection')
175
+ protectedConn = await protector.protect(maConn)
176
+ }
185
177
  }
186
178
 
187
179
  try {
188
180
  // Encrypt the connection
189
- ({
190
- conn: encryptedConn,
191
- remotePeer,
192
- protocol: cryptoProtocol
193
- } = await this._encryptInbound(protectedConn))
181
+ encryptedConn = protectedConn
182
+ if (opts?.skipEncryption !== true) {
183
+ ({
184
+ conn: encryptedConn,
185
+ remotePeer,
186
+ protocol: cryptoProtocol
187
+ } = await this._encryptInbound(protectedConn))
188
+
189
+ if (await this.components.connectionGater.denyInboundEncryptedConnection(remotePeer, {
190
+ ...protectedConn,
191
+ ...encryptedConn
192
+ })) {
193
+ throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
194
+ }
195
+ } else {
196
+ const idStr = maConn.remoteAddr.getPeerId()
194
197
 
195
- if (await this.components.connectionGater.denyInboundEncryptedConnection(remotePeer, {
196
- ...protectedConn,
197
- ...encryptedConn
198
- })) {
199
- throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
198
+ if (idStr == null) {
199
+ throw errCode(new Error('inbound connection that skipped encryption must have a peer id'), codes.ERR_INVALID_MULTIADDR)
200
+ }
201
+
202
+ const remotePeerId = peerIdFromString(idStr)
203
+
204
+ cryptoProtocol = 'native'
205
+ remotePeer = remotePeerId
200
206
  }
201
207
 
202
- // Multiplex the connection
203
- if (this.muxers.size > 0) {
208
+ upgradedConn = encryptedConn
209
+ if (opts?.muxerFactory != null) {
210
+ muxerFactory = opts.muxerFactory
211
+ } else if (this.muxers.size > 0) {
212
+ // Multiplex the connection
204
213
  const multiplexed = await this._multiplexInbound({
205
214
  ...protectedConn,
206
215
  ...encryptedConn
207
216
  }, this.muxers)
208
217
  muxerFactory = multiplexed.muxerFactory
209
218
  upgradedConn = multiplexed.stream
210
- } else {
211
- upgradedConn = encryptedConn
212
219
  }
213
220
  } catch (err: any) {
214
221
  log.error('Failed to upgrade inbound connection', err)
@@ -222,11 +229,6 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
222
229
  throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
223
230
  }
224
231
 
225
- if (metrics != null) {
226
- metrics.updatePlaceholder(proxyPeer, remotePeer)
227
- setPeer(remotePeer)
228
- }
229
-
230
232
  log('Successfully upgraded inbound connection')
231
233
 
232
234
  return this._createConnection({
@@ -263,16 +265,8 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
263
265
  let upgradedConn
264
266
  let cryptoProtocol
265
267
  let muxerFactory
266
- let setPeer
267
- let proxyPeer
268
- const metrics = this.components.metrics
269
-
270
- if (metrics != null) {
271
- ({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
272
- const idString = `${(Math.random() * 1e9).toString(36)}${Date.now()}`
273
- setPeer({ toB58String: () => idString })
274
- metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
275
- }
268
+
269
+ this.components.metrics?.trackMultiaddrConnection(maConn)
276
270
 
277
271
  log('Starting the outbound connection upgrade')
278
272
 
@@ -335,11 +329,6 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
335
329
  throw errCode(new Error('The multiaddr connection is blocked by gater.acceptEncryptedConnection'), codes.ERR_CONNECTION_INTERCEPTED)
336
330
  }
337
331
 
338
- if (metrics != null) {
339
- metrics.updatePlaceholder(proxyPeer, remotePeer)
340
- setPeer(remotePeer)
341
- }
342
-
343
332
  log('Successfully upgraded outbound connection')
344
333
 
345
334
  return this._createConnection({
@@ -385,12 +374,6 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
385
374
  const { stream, protocol } = await mss.handle(muxedStream, protocols)
386
375
  log('%s: incoming stream opened on %s', direction, protocol)
387
376
 
388
- const metrics = this.components.metrics
389
-
390
- if (metrics != null) {
391
- metrics.trackStream({ stream, remotePeer, protocol })
392
- }
393
-
394
377
  if (connection == null) {
395
378
  return
396
379
  }
@@ -415,6 +398,8 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
415
398
  this.components.peerStore.protoBook.add(remotePeer, [protocol]).catch(err => log.error(err))
416
399
 
417
400
  connection.addStream(muxedStream)
401
+ this.components.metrics?.trackProtocolStream(muxedStream, connection)
402
+
418
403
  this._onStream({ connection, stream: muxedStream, protocol })
419
404
  })
420
405
  .catch(err => {
@@ -438,7 +423,6 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
438
423
 
439
424
  log('%s: starting new stream on %s', direction, protocols)
440
425
  const muxedStream = await muxer.newStream()
441
- const metrics = this.components.metrics
442
426
  let controller: TimeoutController | undefined
443
427
 
444
428
  try {
@@ -456,10 +440,6 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
456
440
 
457
441
  const { stream, protocol } = await mss.select(muxedStream, protocols, options)
458
442
 
459
- if (metrics != null) {
460
- metrics.trackStream({ stream, remotePeer, protocol })
461
- }
462
-
463
443
  const outgoingLimit = findOutgoingStreamLimit(protocol, this.components.registrar)
464
444
  const streamCount = countStreams(protocol, 'outbound', connection)
465
445
 
@@ -480,6 +460,8 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
480
460
  muxedStream.sink = stream.sink
481
461
  muxedStream.stat.protocol = protocol
482
462
 
463
+ this.components.metrics?.trackProtocolStream(muxedStream, connection)
464
+
483
465
  return muxedStream
484
466
  } catch (err: any) {
485
467
  log.error('could not create new stream', err)
@@ -501,7 +483,12 @@ export class DefaultUpgrader extends EventEmitter<UpgraderEvents> implements Upg
501
483
  }
502
484
 
503
485
  // Pipe all data through the muxer
504
- pipe(upgradedConn, muxer, upgradedConn).catch(log.error)
486
+ void Promise.all([
487
+ muxer.sink(upgradedConn.source),
488
+ upgradedConn.sink(muxer.source)
489
+ ]).catch(err => {
490
+ log.error(err)
491
+ })
505
492
  }
506
493
 
507
494
  const _timeline = maConn.timeline
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '0.40.0'
1
+ export const version = '0.41.0'
2
2
  export const name = 'libp2p'
@@ -1,93 +0,0 @@
1
- import { DefaultStats } from './stats.js';
2
- import type { ComponentMetricsUpdate, Metrics, Stats, TrackedMetric, TrackStreamOptions } from '@libp2p/interface-metrics';
3
- import type { PeerId } from '@libp2p/interface-peer-id';
4
- import type { Startable } from '@libp2p/interfaces/startable';
5
- export interface OnMessageOptions {
6
- remotePeer: PeerId;
7
- protocol?: string;
8
- direction: 'in' | 'out';
9
- dataLength: number;
10
- }
11
- export interface MetricsInit {
12
- enabled: boolean;
13
- computeThrottleMaxQueueSize: number;
14
- computeThrottleTimeout: number;
15
- movingAverageIntervals: number[];
16
- maxOldPeersRetention: number;
17
- }
18
- export declare class DefaultMetrics implements Metrics, Startable {
19
- globalStats: DefaultStats;
20
- private readonly enabled;
21
- private readonly peerStats;
22
- private readonly protocolStats;
23
- private readonly oldPeers;
24
- private running;
25
- private readonly systems;
26
- private readonly statsInit;
27
- constructor(init: MetricsInit);
28
- isStarted(): boolean;
29
- /**
30
- * Must be called for stats to saved. Any data pushed for tracking
31
- * will be ignored.
32
- */
33
- start(): Promise<void>;
34
- /**
35
- * Stops all averages timers and prevents new data from being tracked.
36
- * Once `stop` is called, `start` must be called to resume stats tracking.
37
- */
38
- stop(): Promise<void>;
39
- /**
40
- * Gets the global `Stats` object
41
- */
42
- getGlobal(): DefaultStats;
43
- /**
44
- * Returns a list of `PeerId` strings currently being tracked
45
- */
46
- getPeers(): string[];
47
- getComponentMetrics(): Map<string, Map<string, Map<string, TrackedMetric>>>;
48
- updateComponentMetric(update: ComponentMetricsUpdate): void;
49
- /**
50
- * Returns the `Stats` object for the given `PeerId` whether it
51
- * is a live peer, or in the disconnected peer LRU cache.
52
- */
53
- forPeer(peerId: PeerId): Stats | undefined;
54
- /**
55
- * Returns a list of all protocol strings currently being tracked
56
- */
57
- getProtocols(): string[];
58
- /**
59
- * Returns the `Stats` object for the given `protocol`
60
- */
61
- forProtocol(protocol: string): Stats | undefined;
62
- /**
63
- * Should be called when all connections to a given peer
64
- * have closed. The `Stats` collection for the peer will
65
- * be stopped and moved to an LRU for temporary retention.
66
- */
67
- onPeerDisconnected(peerId: PeerId): void;
68
- /**
69
- * Takes the metadata for a message and tracks it in the
70
- * appropriate categories. If the protocol is present, protocol
71
- * stats will also be tracked.
72
- */
73
- _onMessage(opts: OnMessageOptions): void;
74
- /**
75
- * Replaces the `PeerId` string with the given `peerId`.
76
- * If stats are already being tracked for the given `peerId`, the
77
- * placeholder stats will be merged with the existing stats.
78
- *
79
- * @param {PeerId} placeholder - A peerId string
80
- * @param {PeerId} peerId
81
- * @returns {void}
82
- */
83
- updatePlaceholder(placeholder: PeerId, peerId: PeerId): void;
84
- /**
85
- * Tracks data running through a given Duplex Iterable `stream`. If
86
- * the `peerId` is not provided, a placeholder string will be created and
87
- * returned. This allows lazy tracking of a peer when the peer is not yet known.
88
- * When the `PeerId` is known, `Metrics.updatePlaceholder` should be called
89
- * with the placeholder string returned from here, and the known `PeerId`.
90
- */
91
- trackStream(opts: TrackStreamOptions): void;
92
- }
93
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/metrics/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAa,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC1H,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAY7D,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,IAAI,GAAG,KAAK,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,2BAA2B,EAAE,MAAM,CAAA;IACnC,sBAAsB,EAAE,MAAM,CAAA;IAC9B,sBAAsB,EAAE,MAAM,EAAE,CAAA;IAChC,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAED,qBAAa,cAAe,YAAW,OAAO,EAAE,SAAS;IAChD,WAAW,EAAE,YAAY,CAAA;IAEhC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2B;IACrD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA2B;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;IACjD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsD;IAC9E,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAW;gBAExB,IAAI,EAAE,WAAW;IAe9B,SAAS;IAIT;;;OAGG;IACG,KAAK;IAQX;;;OAGG;IACG,IAAI;IAiBV;;OAEG;IACH,SAAS;IAIT;;OAEG;IACH,QAAQ;IAIR,mBAAmB;IAInB,qBAAqB,CAAE,MAAM,EAAE,sBAAsB;IA8BrD;;;OAGG;IACH,OAAO,CAAE,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAK3C;;OAEG;IACH,YAAY,IAAK,MAAM,EAAE;IAIzB;;OAEG;IACH,WAAW,CAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIjD;;;;OAIG;IACH,kBAAkB,CAAE,MAAM,EAAE,MAAM;IAYlC;;;;OAIG;IACH,UAAU,CAAE,IAAI,EAAE,gBAAgB;IAkClC;;;;;;;;OAQG;IACH,iBAAiB,CAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAwBtD;;;;;;OAMG;IACH,WAAW,CAAE,IAAI,EAAE,kBAAkB,GAAG,IAAI;CA+B7C"}
@@ -1,234 +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 } from './stats.js';
6
- const initialCounters = [
7
- 'dataReceived',
8
- 'dataSent'
9
- ];
10
- const directionToEvent = {
11
- in: 'dataReceived',
12
- out: 'dataSent'
13
- };
14
- export class DefaultMetrics {
15
- constructor(init) {
16
- this.enabled = init.enabled;
17
- this.statsInit = {
18
- ...init,
19
- initialCounters
20
- };
21
- this.globalStats = new DefaultStats(this.statsInit);
22
- this.peerStats = new Map();
23
- this.protocolStats = new Map();
24
- this.oldPeers = LRU(init.maxOldPeersRetention ?? defaultOptions.maxOldPeersRetention);
25
- this.running = false;
26
- this._onMessage = this._onMessage.bind(this);
27
- this.systems = new Map();
28
- }
29
- isStarted() {
30
- return this.running;
31
- }
32
- /**
33
- * Must be called for stats to saved. Any data pushed for tracking
34
- * will be ignored.
35
- */
36
- async start() {
37
- if (!this.enabled) {
38
- return;
39
- }
40
- this.running = true;
41
- }
42
- /**
43
- * Stops all averages timers and prevents new data from being tracked.
44
- * Once `stop` is called, `start` must be called to resume stats tracking.
45
- */
46
- async stop() {
47
- if (!this.running) {
48
- return;
49
- }
50
- this.running = false;
51
- this.globalStats.stop();
52
- for (const stats of this.peerStats.values()) {
53
- stats.stop();
54
- }
55
- for (const stats of this.protocolStats.values()) {
56
- stats.stop();
57
- }
58
- }
59
- /**
60
- * Gets the global `Stats` object
61
- */
62
- getGlobal() {
63
- return this.globalStats;
64
- }
65
- /**
66
- * Returns a list of `PeerId` strings currently being tracked
67
- */
68
- getPeers() {
69
- return Array.from(this.peerStats.keys());
70
- }
71
- getComponentMetrics() {
72
- return this.systems;
73
- }
74
- updateComponentMetric(update) {
75
- const { system = 'libp2p', component, metric, value, label, help } = update;
76
- if (!this.systems.has(system)) {
77
- this.systems.set(system, new Map());
78
- }
79
- const systemMetrics = this.systems.get(system);
80
- if (systemMetrics == null) {
81
- throw new Error('Unknown metric system');
82
- }
83
- if (!systemMetrics.has(component)) {
84
- systemMetrics.set(component, new Map());
85
- }
86
- const componentMetrics = systemMetrics.get(component);
87
- if (componentMetrics == null) {
88
- throw new Error('Unknown metric component');
89
- }
90
- componentMetrics.set(metric, {
91
- label,
92
- help,
93
- calculate: typeof value !== 'function' ? () => value : value
94
- });
95
- }
96
- /**
97
- * Returns the `Stats` object for the given `PeerId` whether it
98
- * is a live peer, or in the disconnected peer LRU cache.
99
- */
100
- forPeer(peerId) {
101
- const idString = peerId.toString();
102
- return this.peerStats.get(idString) ?? this.oldPeers.get(idString);
103
- }
104
- /**
105
- * Returns a list of all protocol strings currently being tracked
106
- */
107
- getProtocols() {
108
- return Array.from(this.protocolStats.keys());
109
- }
110
- /**
111
- * Returns the `Stats` object for the given `protocol`
112
- */
113
- forProtocol(protocol) {
114
- return this.protocolStats.get(protocol);
115
- }
116
- /**
117
- * Should be called when all connections to a given peer
118
- * have closed. The `Stats` collection for the peer will
119
- * be stopped and moved to an LRU for temporary retention.
120
- */
121
- onPeerDisconnected(peerId) {
122
- const idString = peerId.toString();
123
- const peerStats = this.peerStats.get(idString);
124
- if (peerStats != null) {
125
- peerStats.stop();
126
- this.peerStats.delete(idString);
127
- this.oldPeers.set(idString, peerStats);
128
- }
129
- }
130
- /**
131
- * Takes the metadata for a message and tracks it in the
132
- * appropriate categories. If the protocol is present, protocol
133
- * stats will also be tracked.
134
- */
135
- _onMessage(opts) {
136
- if (!this.running) {
137
- return;
138
- }
139
- const { remotePeer, protocol, direction, dataLength } = opts;
140
- const key = directionToEvent[direction];
141
- let peerStats = this.forPeer(remotePeer);
142
- if (peerStats == null) {
143
- const stats = new DefaultStats(this.statsInit);
144
- this.peerStats.set(remotePeer.toString(), stats);
145
- peerStats = stats;
146
- }
147
- // Peer and global stats
148
- peerStats.push(key, dataLength);
149
- this.globalStats.push(key, dataLength);
150
- // Protocol specific stats
151
- if (protocol != null) {
152
- let protocolStats = this.forProtocol(protocol);
153
- if (protocolStats == null) {
154
- const stats = new DefaultStats(this.statsInit);
155
- this.protocolStats.set(protocol, stats);
156
- protocolStats = stats;
157
- }
158
- protocolStats.push(key, dataLength);
159
- }
160
- }
161
- /**
162
- * Replaces the `PeerId` string with the given `peerId`.
163
- * If stats are already being tracked for the given `peerId`, the
164
- * placeholder stats will be merged with the existing stats.
165
- *
166
- * @param {PeerId} placeholder - A peerId string
167
- * @param {PeerId} peerId
168
- * @returns {void}
169
- */
170
- updatePlaceholder(placeholder, peerId) {
171
- if (!this.running) {
172
- return;
173
- }
174
- const placeholderString = placeholder.toString();
175
- const placeholderStats = this.peerStats.get(placeholderString) ?? this.oldPeers.get(placeholderString);
176
- const peerIdString = peerId.toString();
177
- const existingStats = this.peerStats.get(peerIdString) ?? this.oldPeers.get(peerIdString);
178
- let mergedStats = placeholderStats;
179
- // If we already have stats, merge the two
180
- if (existingStats != null) {
181
- // If existing, merge
182
- mergedStats = mergeStats(existingStats, mergedStats);
183
- // Attempt to delete from the old peers list just in case it was tracked there
184
- this.oldPeers.remove(peerIdString);
185
- }
186
- this.peerStats.delete(placeholder.toString());
187
- this.peerStats.set(peerIdString, mergedStats);
188
- mergedStats.start();
189
- }
190
- /**
191
- * Tracks data running through a given Duplex Iterable `stream`. If
192
- * the `peerId` is not provided, a placeholder string will be created and
193
- * returned. This allows lazy tracking of a peer when the peer is not yet known.
194
- * When the `PeerId` is known, `Metrics.updatePlaceholder` should be called
195
- * with the placeholder string returned from here, and the known `PeerId`.
196
- */
197
- trackStream(opts) {
198
- const { stream, remotePeer, protocol } = opts;
199
- if (!this.running) {
200
- return;
201
- }
202
- const source = stream.source;
203
- stream.source = each(source, chunk => this._onMessage({
204
- remotePeer,
205
- protocol,
206
- direction: 'in',
207
- dataLength: chunk.byteLength
208
- }));
209
- const sink = stream.sink;
210
- stream.sink = async (source) => {
211
- return await pipe(source, (source) => each(source, chunk => {
212
- this._onMessage({
213
- remotePeer,
214
- protocol,
215
- direction: 'out',
216
- dataLength: chunk.byteLength
217
- });
218
- }), sink);
219
- };
220
- }
221
- }
222
- /**
223
- * Merges `other` into `target`. `target` will be modified
224
- * and returned
225
- */
226
- function mergeStats(target, other) {
227
- target.stop();
228
- other.stop();
229
- // Merge queues
230
- target.queue = [...target.queue, ...other.queue];
231
- // TODO: how to merge moving averages?
232
- return target;
233
- }
234
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/metrics/index.ts"],"names":[],"mappings":"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"}
@@ -1,14 +0,0 @@
1
- import type { MovingAverage } from '@libp2p/interface-metrics';
2
- export declare class DefaultMovingAverage {
3
- movingAverage: number;
4
- variance: number;
5
- deviation: number;
6
- forecast: number;
7
- private readonly timespan;
8
- private previousTime?;
9
- constructor(timespan: number);
10
- alpha(t: number, pt: number): number;
11
- push(time: number, value: number): void;
12
- }
13
- export declare function createMovingAverage(timespan: number): MovingAverage;
14
- //# sourceMappingURL=moving-average.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"moving-average.d.ts","sourceRoot":"","sources":["../../../src/metrics/moving-average.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAE9D,qBAAa,oBAAoB;IACxB,aAAa,EAAE,MAAM,CAAA;IACrB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IACvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,YAAY,CAAC,CAAQ;gBAEhB,QAAQ,EAAE,MAAM;IAgB7B,KAAK,CAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;IAI5B,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAkBlC;AAED,wBAAgB,mBAAmB,CAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAEpE"}
@@ -1,40 +0,0 @@
1
- export class DefaultMovingAverage {
2
- constructor(timespan) {
3
- if (typeof timespan !== 'number') {
4
- throw new Error('must provide a timespan to the moving average constructor');
5
- }
6
- if (timespan <= 0) {
7
- throw new Error('must provide a timespan > 0 to the moving average constructor');
8
- }
9
- this.timespan = timespan;
10
- this.movingAverage = 0;
11
- this.variance = 0;
12
- this.deviation = 0;
13
- this.forecast = 0;
14
- }
15
- alpha(t, pt) {
16
- return 1 - (Math.exp(-(t - pt) / this.timespan));
17
- }
18
- push(time, value) {
19
- if (this.previousTime != null) {
20
- // calculate moving average
21
- const a = this.alpha(time, this.previousTime);
22
- const diff = value - this.movingAverage;
23
- const incr = a * diff;
24
- this.movingAverage = a * value + (1 - a) * this.movingAverage;
25
- // calculate variance & deviation
26
- this.variance = (1 - a) * (this.variance + diff * incr);
27
- this.deviation = Math.sqrt(this.variance);
28
- // calculate forecast
29
- this.forecast = this.movingAverage + a * diff;
30
- }
31
- else {
32
- this.movingAverage = value;
33
- }
34
- this.previousTime = time;
35
- }
36
- }
37
- export function createMovingAverage(timespan) {
38
- return new DefaultMovingAverage(timespan);
39
- }
40
- //# sourceMappingURL=moving-average.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"moving-average.js","sourceRoot":"","sources":["../../../src/metrics/moving-average.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,oBAAoB;IAQ/B,YAAa,QAAgB;QAC3B,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE;YAChC,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAA;SAC7E;QAED,IAAI,QAAQ,IAAI,CAAC,EAAE;YACjB,MAAM,IAAI,KAAK,CAAC,+DAA+D,CAAC,CAAA;SACjF;QAED,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAA;QACxB,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;QACtB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;QACjB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAA;QAClB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAA;IACnB,CAAC;IAED,KAAK,CAAE,CAAS,EAAE,EAAU;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAA;IAClD,CAAC;IAED,IAAI,CAAE,IAAY,EAAE,KAAa;QAC/B,IAAI,IAAI,CAAC,YAAY,IAAI,IAAI,EAAE;YAC7B,2BAA2B;YAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,CAAA;YAC7C,MAAM,IAAI,GAAG,KAAK,GAAG,IAAI,CAAC,aAAa,CAAA;YACvC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,CAAA;YACrB,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,aAAa,CAAA;YAC7D,iCAAiC;YACjC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,CAAA;YACvD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACzC,qBAAqB;YACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAA;SAC9C;aAAM;YACL,IAAI,CAAC,aAAa,GAAG,KAAK,CAAA;SAC3B;QAED,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;IAC1B,CAAC;CACF;AAED,MAAM,UAAU,mBAAmB,CAAE,QAAgB;IACnD,OAAO,IAAI,oBAAoB,CAAC,QAAQ,CAAC,CAAA;AAC3C,CAAC"}