UNPKG

libp2p

Version:

JavaScript implementation of libp2p, a modular peer to peer network stack

97 lines 4.19 kB
import { randomBytes } from '@libp2p/crypto'; import { serviceCapabilities, setMaxListeners } from '@libp2p/interface'; import { AdaptiveTimeout } from '@libp2p/utils/adaptive-timeout'; import { byteStream } from 'it-byte-stream'; const DEFAULT_PING_INTERVAL_MS = 10000; const PROTOCOL_VERSION = '1.0.0'; const PROTOCOL_NAME = 'ping'; const PROTOCOL_PREFIX = 'ipfs'; const PING_LENGTH = 32; const DEFAULT_ABORT_CONNECTION_ON_PING_FAILURE = true; export class ConnectionMonitor { protocol; components; log; heartbeatInterval; pingIntervalMs; abortController; timeout; abortConnectionOnPingFailure; constructor(components, init = {}) { this.components = components; this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}`; this.log = components.logger.forComponent('libp2p:connection-monitor'); this.pingIntervalMs = init.pingInterval ?? DEFAULT_PING_INTERVAL_MS; this.abortConnectionOnPingFailure = init.abortConnectionOnPingFailure ?? DEFAULT_ABORT_CONNECTION_ON_PING_FAILURE; this.timeout = new AdaptiveTimeout({ ...(init.pingTimeout ?? {}), metrics: components.metrics, metricName: 'libp2p_connection_monitor_ping_time_milliseconds' }); } [Symbol.toStringTag] = '@libp2p/connection-monitor'; [serviceCapabilities] = [ '@libp2p/connection-monitor' ]; start() { this.abortController = new AbortController(); setMaxListeners(Infinity, this.abortController.signal); this.heartbeatInterval = setInterval(() => { this.components.connectionManager.getConnections().forEach(conn => { Promise.resolve().then(async () => { let start = Date.now(); try { const signal = this.timeout.getTimeoutSignal({ signal: this.abortController?.signal }); const stream = await conn.newStream(this.protocol, { signal, runOnLimitedConnection: true }); const bs = byteStream(stream); start = Date.now(); await Promise.all([ bs.write(randomBytes(PING_LENGTH), { signal }), bs.read(PING_LENGTH, { signal }) ]); conn.rtt = Date.now() - start; await bs.unwrap().close({ signal }); } catch (err) { if (err.name !== 'UnsupportedProtocolError') { throw err; } // protocol was unsupported, but that's ok as it means the remote // peer was still alive. We ran multistream-select which means two // round trips (e.g. 1x for the mss header, then another for the // protocol) so divide the time it took by two conn.rtt = (Date.now() - start) / 2; } }) .catch(err => { this.log.error('error during heartbeat', err); if (this.abortConnectionOnPingFailure) { this.log.error('aborting connection due to ping failure'); conn.abort(err); } else { this.log('connection ping failed, but not aborting due to abortConnectionOnPingFailure flag'); } }); }); }, this.pingIntervalMs); } stop() { this.abortController?.abort(); if (this.heartbeatInterval != null) { clearInterval(this.heartbeatInterval); } } } //# sourceMappingURL=connection-monitor.js.map