/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
lib/internal/quic/stats.js
1 116 строк
31 KB
Jungwon Sohn
quic: fix coverage comment typo
01 авг 2026, 05:41
Не верифицирован
01 авг 2026, 05:41
a6a1bd4
Код
Авторство
О чём код?
'use strict'; // TODO(@jasnell) Temporarily ignoring c8 coverage for this file while tests // are still being developed. /* c8 ignore start */ const { BigUint64Array, JSONStringify, Symbol, TypedArrayPrototypeSubarray, } = primordials; const { getOptionValue, } = require('internal/options'); if (!process.features.quic || !getOptionValue('--experimental-quic')) { return; } const { isArrayBuffer, } = require('util/types'); const { codes: { ERR_ILLEGAL_CONSTRUCTOR, ERR_INVALID_ARG_TYPE, ERR_INVALID_THIS, }, } = require('internal/errors'); const { inspect } = require('internal/util/inspect'); const assert = require('internal/assert'); const { kFinishClose, kInspect, kPrivateConstructor, } = require('internal/quic/symbols'); // This file defines the helper objects for accessing statistics collected // by various QUIC objects. Each of these wraps a BigUint64Array. Every // stats object is read-only via the API, and the underlying buffer is // only updated by the QUIC internals. When the stats object is no longer // needed, it is closed to prevent further updates to the buffer. const { // All of the IDX_STATS_* constants are the index positions of the stats // fields in the relevant BigUint64Array's that underlie the *Stats objects. // These are not exposed to end users. IDX_STATS_ENDPOINT_CREATED_AT, IDX_STATS_ENDPOINT_DESTROYED_AT, IDX_STATS_ENDPOINT_BYTES_RECEIVED, IDX_STATS_ENDPOINT_BYTES_SENT, IDX_STATS_ENDPOINT_PACKETS_RECEIVED, IDX_STATS_ENDPOINT_PACKETS_SENT, IDX_STATS_ENDPOINT_SERVER_SESSIONS, IDX_STATS_ENDPOINT_CLIENT_SESSIONS, IDX_STATS_ENDPOINT_SERVER_BUSY_COUNT, IDX_STATS_ENDPOINT_RETRY_COUNT, IDX_STATS_ENDPOINT_RETRY_RATE_LIMITED, IDX_STATS_ENDPOINT_VERSION_NEGOTIATION_COUNT, IDX_STATS_ENDPOINT_VERSION_NEGOTIATION_RATE_LIMITED, IDX_STATS_ENDPOINT_STATELESS_RESET_COUNT, IDX_STATS_ENDPOINT_STATELESS_RESET_RATE_LIMITED, IDX_STATS_ENDPOINT_IMMEDIATE_CLOSE_COUNT, IDX_STATS_ENDPOINT_IMMEDIATE_CLOSE_RATE_LIMITED, IDX_STATS_ENDPOINT_SESSION_CREATION_RATE_LIMITED, IDX_STATS_ENDPOINT_PACKETS_BLOCKED, IDX_STATS_SESSION_CREATED_AT, IDX_STATS_SESSION_DESTROYED_AT, IDX_STATS_SESSION_CLOSING_AT, IDX_STATS_SESSION_HANDSHAKE_COMPLETED_AT, IDX_STATS_SESSION_HANDSHAKE_CONFIRMED_AT, IDX_STATS_SESSION_BYTES_RECEIVED, IDX_STATS_SESSION_BIDI_IN_STREAM_COUNT, IDX_STATS_SESSION_BIDI_OUT_STREAM_COUNT, IDX_STATS_SESSION_UNI_IN_STREAM_COUNT, IDX_STATS_SESSION_UNI_OUT_STREAM_COUNT, IDX_STATS_SESSION_MAX_BYTES_IN_FLIGHT, IDX_STATS_SESSION_BYTES_IN_FLIGHT, IDX_STATS_SESSION_BLOCK_COUNT, IDX_STATS_SESSION_CWND, IDX_STATS_SESSION_LATEST_RTT, IDX_STATS_SESSION_MIN_RTT, IDX_STATS_SESSION_RTTVAR, IDX_STATS_SESSION_SMOOTHED_RTT, IDX_STATS_SESSION_SSTHRESH, IDX_STATS_SESSION_PKT_SENT, IDX_STATS_SESSION_BYTES_SENT, IDX_STATS_SESSION_PKT_RECV, IDX_STATS_SESSION_BYTES_RECV, IDX_STATS_SESSION_PKT_LOST, IDX_STATS_SESSION_BYTES_LOST, IDX_STATS_SESSION_PING_RECV, IDX_STATS_SESSION_PKT_DISCARDED, IDX_STATS_SESSION_DATAGRAMS_RECEIVED, IDX_STATS_SESSION_DATAGRAMS_SENT, IDX_STATS_SESSION_DATAGRAMS_ACKNOWLEDGED, IDX_STATS_SESSION_DATAGRAMS_LOST, IDX_STATS_SESSION_STREAMS_IDLE_TIMED_OUT, IDX_STATS_SESSION_COUNT, IDX_STATS_STREAM_CREATED_AT, IDX_STATS_STREAM_OPENED_AT, IDX_STATS_STREAM_RECEIVED_AT, IDX_STATS_STREAM_ACKED_AT, IDX_STATS_STREAM_DESTROYED_AT, IDX_STATS_STREAM_BYTES_RECEIVED, IDX_STATS_STREAM_BYTES_SENT, IDX_STATS_STREAM_MAX_OFFSET, IDX_STATS_STREAM_MAX_OFFSET_ACK, IDX_STATS_STREAM_MAX_OFFSET_RECV, IDX_STATS_STREAM_FINAL_SIZE, IDX_STATS_STREAM_BYTES_ACCUMULATED, IDX_STATS_STREAM_MAX_BYTES_ACCUMULATED, IDX_STATS_STREAM_COUNT, } = internalBinding('quic'); assert(IDX_STATS_ENDPOINT_CREATED_AT !== undefined); assert(IDX_STATS_ENDPOINT_DESTROYED_AT !== undefined); assert(IDX_STATS_ENDPOINT_BYTES_RECEIVED !== undefined); assert(IDX_STATS_ENDPOINT_BYTES_SENT !== undefined); assert(IDX_STATS_ENDPOINT_PACKETS_RECEIVED !== undefined); assert(IDX_STATS_ENDPOINT_PACKETS_SENT !== undefined); assert(IDX_STATS_ENDPOINT_SERVER_SESSIONS !== undefined); assert(IDX_STATS_ENDPOINT_CLIENT_SESSIONS !== undefined); assert(IDX_STATS_ENDPOINT_SERVER_BUSY_COUNT !== undefined); assert(IDX_STATS_ENDPOINT_RETRY_COUNT !== undefined); assert(IDX_STATS_ENDPOINT_RETRY_RATE_LIMITED !== undefined); assert(IDX_STATS_ENDPOINT_VERSION_NEGOTIATION_COUNT !== undefined); assert(IDX_STATS_ENDPOINT_VERSION_NEGOTIATION_RATE_LIMITED !== undefined); assert(IDX_STATS_ENDPOINT_STATELESS_RESET_COUNT !== undefined); assert(IDX_STATS_ENDPOINT_STATELESS_RESET_RATE_LIMITED !== undefined); assert(IDX_STATS_ENDPOINT_IMMEDIATE_CLOSE_COUNT !== undefined); assert(IDX_STATS_ENDPOINT_IMMEDIATE_CLOSE_RATE_LIMITED !== undefined); assert(IDX_STATS_ENDPOINT_SESSION_CREATION_RATE_LIMITED !== undefined); assert(IDX_STATS_ENDPOINT_PACKETS_BLOCKED !== undefined); assert(IDX_STATS_SESSION_CREATED_AT !== undefined); assert(IDX_STATS_SESSION_DESTROYED_AT !== undefined); assert(IDX_STATS_SESSION_CLOSING_AT !== undefined); assert(IDX_STATS_SESSION_HANDSHAKE_COMPLETED_AT !== undefined); assert(IDX_STATS_SESSION_HANDSHAKE_CONFIRMED_AT !== undefined); assert(IDX_STATS_SESSION_BYTES_RECEIVED !== undefined); assert(IDX_STATS_SESSION_BIDI_IN_STREAM_COUNT !== undefined); assert(IDX_STATS_SESSION_BIDI_OUT_STREAM_COUNT !== undefined); assert(IDX_STATS_SESSION_UNI_IN_STREAM_COUNT !== undefined); assert(IDX_STATS_SESSION_UNI_OUT_STREAM_COUNT !== undefined); assert(IDX_STATS_SESSION_MAX_BYTES_IN_FLIGHT !== undefined); assert(IDX_STATS_SESSION_BYTES_IN_FLIGHT !== undefined); assert(IDX_STATS_SESSION_BLOCK_COUNT !== undefined); assert(IDX_STATS_SESSION_CWND !== undefined); assert(IDX_STATS_SESSION_LATEST_RTT !== undefined); assert(IDX_STATS_SESSION_MIN_RTT !== undefined); assert(IDX_STATS_SESSION_RTTVAR !== undefined); assert(IDX_STATS_SESSION_SMOOTHED_RTT !== undefined); assert(IDX_STATS_SESSION_SSTHRESH !== undefined); assert(IDX_STATS_SESSION_PKT_SENT !== undefined); assert(IDX_STATS_SESSION_BYTES_SENT !== undefined); assert(IDX_STATS_SESSION_PKT_RECV !== undefined); assert(IDX_STATS_SESSION_BYTES_RECV !== undefined); assert(IDX_STATS_SESSION_PKT_LOST !== undefined); assert(IDX_STATS_SESSION_BYTES_LOST !== undefined); assert(IDX_STATS_SESSION_PING_RECV !== undefined); assert(IDX_STATS_SESSION_PKT_DISCARDED !== undefined); assert(IDX_STATS_SESSION_DATAGRAMS_RECEIVED !== undefined); assert(IDX_STATS_SESSION_DATAGRAMS_SENT !== undefined); assert(IDX_STATS_SESSION_DATAGRAMS_ACKNOWLEDGED !== undefined); assert(IDX_STATS_SESSION_DATAGRAMS_LOST !== undefined); assert(IDX_STATS_SESSION_STREAMS_IDLE_TIMED_OUT !== undefined); assert(IDX_STATS_STREAM_CREATED_AT !== undefined); assert(IDX_STATS_STREAM_OPENED_AT !== undefined); assert(IDX_STATS_STREAM_RECEIVED_AT !== undefined); assert(IDX_STATS_STREAM_ACKED_AT !== undefined); assert(IDX_STATS_STREAM_DESTROYED_AT !== undefined); assert(IDX_STATS_STREAM_BYTES_RECEIVED !== undefined); assert(IDX_STATS_STREAM_BYTES_SENT !== undefined); assert(IDX_STATS_STREAM_MAX_OFFSET !== undefined); assert(IDX_STATS_STREAM_MAX_OFFSET_ACK !== undefined); assert(IDX_STATS_STREAM_MAX_OFFSET_RECV !== undefined); assert(IDX_STATS_STREAM_FINAL_SIZE !== undefined); assert(IDX_STATS_STREAM_BYTES_ACCUMULATED !== undefined); assert(IDX_STATS_STREAM_MAX_BYTES_ACCUMULATED !== undefined); assert(IDX_STATS_STREAM_COUNT !== undefined); assert(IDX_STATS_SESSION_COUNT !== undefined); const kCreateDisconnected = Symbol('kCreateDisconnected'); let assertIsQuicEndpointStats; let assertIsQuicSessionStats; let assertIsQuicStreamStats; let isQuicEndpointStats; let isQuicSessionStats; let isQuicStreamStats; function assertIsPrivateConstructor(privateSymbol) { if (privateSymbol !== kPrivateConstructor) { throw new ERR_ILLEGAL_CONSTRUCTOR(); } } class QuicEndpointStats { /** @type {BigUint64Array} */ #handle; /** @type {boolean} */ #disconnected = false; static { isQuicEndpointStats = function(val) { return val != null && typeof val === 'object' && #handle in val; }; assertIsQuicEndpointStats = function(val) { if (!isQuicEndpointStats(val)) { throw new ERR_INVALID_THIS('QuicEndpointStats'); } }; } /** * @param {symbol} privateSymbol * @param {ArrayBuffer} buffer */ constructor(privateSymbol, buffer) { // We use the kPrivateConstructor symbol to restrict the ability to // create new instances of QuicEndpointStats to internal code. assertIsPrivateConstructor(privateSymbol); if (!isArrayBuffer(buffer)) { throw new ERR_INVALID_ARG_TYPE('buffer', ['ArrayBuffer'], buffer); } this.#handle = new BigUint64Array(buffer); } /** @type {bigint} */ get createdAt() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_CREATED_AT]; } /** @type {bigint} */ get destroyedAt() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_DESTROYED_AT]; } /** @type {bigint} */ get bytesReceived() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_BYTES_RECEIVED]; } /** @type {bigint} */ get bytesSent() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_BYTES_SENT]; } /** @type {bigint} */ get packetsReceived() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_PACKETS_RECEIVED]; } /** @type {bigint} */ get packetsSent() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_PACKETS_SENT]; } /** @type {bigint} */ get serverSessions() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_SERVER_SESSIONS]; } /** @type {bigint} */ get clientSessions() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_CLIENT_SESSIONS]; } /** @type {bigint} */ get serverBusyCount() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_SERVER_BUSY_COUNT]; } /** @type {bigint} */ get retryCount() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_RETRY_COUNT]; } /** @type {bigint} */ get retryRateLimited() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_RETRY_RATE_LIMITED]; } /** @type {bigint} */ get versionNegotiationCount() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_VERSION_NEGOTIATION_COUNT]; } /** @type {bigint} */ get versionNegotiationRateLimited() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_VERSION_NEGOTIATION_RATE_LIMITED]; } /** @type {bigint} */ get statelessResetCount() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_STATELESS_RESET_COUNT]; } /** @type {bigint} */ get statelessResetRateLimited() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_STATELESS_RESET_RATE_LIMITED]; } /** @type {bigint} */ get immediateCloseCount() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_IMMEDIATE_CLOSE_COUNT]; } /** @type {bigint} */ get immediateCloseRateLimited() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_IMMEDIATE_CLOSE_RATE_LIMITED]; } /** @type {bigint} */ get sessionCreationRateLimited() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_SESSION_CREATION_RATE_LIMITED]; } /** @type {bigint} */ get packetsBlocked() { assertIsQuicEndpointStats(this); return this.#handle[IDX_STATS_ENDPOINT_PACKETS_BLOCKED]; } toString() { return JSONStringify(this.toJSON()); } toJSON() { assertIsQuicEndpointStats(this); const { createdAt, destroyedAt, bytesReceived, bytesSent, packetsReceived, packetsSent, serverSessions, clientSessions, serverBusyCount, retryCount, retryRateLimited, versionNegotiationCount, versionNegotiationRateLimited, statelessResetCount, statelessResetRateLimited, immediateCloseCount, immediateCloseRateLimited, sessionCreationRateLimited, packetsBlocked, } = this; return { __proto__: null, connected: this.isConnected, // We need to convert the values to strings because JSON does not // support BigInts. createdAt: `${createdAt}`, destroyedAt: `${destroyedAt}`, bytesReceived: `${bytesReceived}`, bytesSent: `${bytesSent}`, packetsReceived: `${packetsReceived}`, packetsSent: `${packetsSent}`, serverSessions: `${serverSessions}`, clientSessions: `${clientSessions}`, serverBusyCount: `${serverBusyCount}`, retryCount: `${retryCount}`, retryRateLimited: `${retryRateLimited}`, versionNegotiationCount: `${versionNegotiationCount}`, versionNegotiationRateLimited: `${versionNegotiationRateLimited}`, statelessResetCount: `${statelessResetCount}`, statelessResetRateLimited: `${statelessResetRateLimited}`, immediateCloseCount: `${immediateCloseCount}`, immediateCloseRateLimited: `${immediateCloseRateLimited}`, sessionCreationRateLimited: `${sessionCreationRateLimited}`, packetsBlocked: `${packetsBlocked}`, }; } [kInspect](depth, options) { assertIsQuicEndpointStats(this); if (depth < 0) { return 'QuicEndpointStats { }'; } const opts = { __proto__: null, ...options, depth: options.depth == null ? null : options.depth - 1, }; const { createdAt, destroyedAt, bytesReceived, bytesSent, packetsReceived, packetsSent, serverSessions, clientSessions, serverBusyCount, retryCount, retryRateLimited, versionNegotiationCount, versionNegotiationRateLimited, statelessResetCount, statelessResetRateLimited, immediateCloseCount, immediateCloseRateLimited, sessionCreationRateLimited, packetsBlocked, } = this; return `QuicEndpointStats ${inspect({ connected: this.isConnected, createdAt, destroyedAt, bytesReceived, bytesSent, packetsReceived, packetsSent, serverSessions, clientSessions, serverBusyCount, retryCount, retryRateLimited, versionNegotiationCount, versionNegotiationRateLimited, statelessResetCount, statelessResetRateLimited, immediateCloseCount, immediateCloseRateLimited, sessionCreationRateLimited, packetsBlocked, }, opts)}`; } /** * True if this QuicEndpointStats object is still connected to the underlying * Endpoint stats source. If this returns false, then the stats object is * no longer being updated and should be considered stale. * @type {boolean} */ get isConnected() { assertIsQuicEndpointStats(this); return !this.#disconnected; } [kFinishClose]() { this.#handle = new BigUint64Array(this.#handle); this.#disconnected = true; } } class QuicSessionStats { /** @type {BigUint64Array} */ #handle; #disconnected = false; #offset = 0; static { isQuicSessionStats = function(val) { return val != null && typeof val === 'object' && #handle in val; }; assertIsQuicSessionStats = function(val) { if (!isQuicSessionStats(val)) { throw new ERR_INVALID_THIS('QuicSessionStats'); } }; } /** * @param {symbol} privateSymbol * @param {ArrayBuffer} view * @param {number} [byteOffset] */ constructor(privateSymbol, view, byteOffset = 0) { // We use the kPrivateConstructor symbol to restrict the ability to // create new instances of QuicSessionStats to internal code. assertIsPrivateConstructor(privateSymbol); if (isArrayBuffer(view)) { this.#handle = new BigUint64Array(view); } else { this.#handle = view; } this.#offset = byteOffset / 8; } /** @type {bigint} */ get createdAt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_CREATED_AT]; } /** @type {bigint} */ get destroyedAt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_DESTROYED_AT]; } /** @type {bigint} */ get closingAt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_CLOSING_AT]; } /** @type {bigint} */ get handshakeCompletedAt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_HANDSHAKE_COMPLETED_AT]; } /** @type {bigint} */ get handshakeConfirmedAt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_HANDSHAKE_CONFIRMED_AT]; } /** @type {bigint} */ get bytesReceived() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_RECEIVED]; } /** @type {bigint} */ get bidiInStreamCount() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BIDI_IN_STREAM_COUNT]; } /** @type {bigint} */ get bidiOutStreamCount() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BIDI_OUT_STREAM_COUNT]; } /** @type {bigint} */ get uniInStreamCount() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_UNI_IN_STREAM_COUNT]; } /** @type {bigint} */ get uniOutStreamCount() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_UNI_OUT_STREAM_COUNT]; } /** @type {bigint} */ get maxBytesInFlight() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_MAX_BYTES_IN_FLIGHT]; } /** @type {bigint} */ get bytesInFlight() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_IN_FLIGHT]; } /** @type {bigint} */ get blockCount() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BLOCK_COUNT]; } /** @type {bigint} */ get cwnd() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_CWND]; } /** @type {bigint} */ get latestRtt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_LATEST_RTT]; } /** @type {bigint} */ get minRtt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_MIN_RTT]; } /** @type {bigint} */ get rttVar() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_RTTVAR]; } /** @type {bigint} */ get smoothedRtt() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_SMOOTHED_RTT]; } /** @type {bigint} */ get ssthresh() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_SSTHRESH]; } get pktSent() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_SENT]; } get bytesSent() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_SENT]; } get pktRecv() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_RECV]; } get bytesRecv() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_RECV]; } get pktLost() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_LOST]; } get bytesLost() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_BYTES_LOST]; } get pingRecv() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_PING_RECV]; } get pktDiscarded() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_PKT_DISCARDED]; } /** @type {bigint} */ get datagramsReceived() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_RECEIVED]; } /** @type {bigint} */ get datagramsSent() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_SENT]; } /** @type {bigint} */ get datagramsAcknowledged() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_ACKNOWLEDGED]; } /** @type {bigint} */ get datagramsLost() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_DATAGRAMS_LOST]; } /** @type {bigint} */ get streamsIdleTimedOut() { assertIsQuicSessionStats(this); return this.#handle[this.#offset + IDX_STATS_SESSION_STREAMS_IDLE_TIMED_OUT]; } toString() { return JSONStringify(this.toJSON()); } toJSON() { assertIsQuicSessionStats(this); const { createdAt, closingAt, handshakeCompletedAt, handshakeConfirmedAt, bytesReceived, bidiInStreamCount, bidiOutStreamCount, uniInStreamCount, uniOutStreamCount, maxBytesInFlight, bytesInFlight, blockCount, cwnd, latestRtt, minRtt, rttVar, smoothedRtt, ssthresh, pktSent, bytesSent, pktRecv, bytesRecv, pktLost, bytesLost, pingRecv, pktDiscarded, datagramsReceived, datagramsSent, datagramsAcknowledged, datagramsLost, streamsIdleTimedOut, } = this; return { __proto__: null, connected: this.isConnected, // We need to convert the values to strings because JSON does not // support BigInts. createdAt: `${createdAt}`, closingAt: `${closingAt}`, handshakeCompletedAt: `${handshakeCompletedAt}`, handshakeConfirmedAt: `${handshakeConfirmedAt}`, bytesReceived: `${bytesReceived}`, bidiInStreamCount: `${bidiInStreamCount}`, bidiOutStreamCount: `${bidiOutStreamCount}`, uniInStreamCount: `${uniInStreamCount}`, uniOutStreamCount: `${uniOutStreamCount}`, maxBytesInFlight: `${maxBytesInFlight}`, bytesInFlight: `${bytesInFlight}`, blockCount: `${blockCount}`, cwnd: `${cwnd}`, latestRtt: `${latestRtt}`, minRtt: `${minRtt}`, rttVar: `${rttVar}`, smoothedRtt: `${smoothedRtt}`, ssthresh: `${ssthresh}`, pktSent: `${pktSent}`, bytesSent: `${bytesSent}`, pktRecv: `${pktRecv}`, bytesRecv: `${bytesRecv}`, pktLost: `${pktLost}`, bytesLost: `${bytesLost}`, pingRecv: `${pingRecv}`, pktDiscarded: `${pktDiscarded}`, datagramsReceived: `${datagramsReceived}`, datagramsSent: `${datagramsSent}`, datagramsAcknowledged: `${datagramsAcknowledged}`, datagramsLost: `${datagramsLost}`, streamsIdleTimedOut: `${streamsIdleTimedOut}`, }; } [kInspect](depth, options) { if (depth < 0) { return 'QuicSessionStats { }'; } const opts = { __proto__: null, ...options, depth: options.depth == null ? null : options.depth - 1, }; const { createdAt, closingAt, handshakeCompletedAt, handshakeConfirmedAt, bytesReceived, bidiInStreamCount, bidiOutStreamCount, uniInStreamCount, uniOutStreamCount, maxBytesInFlight, bytesInFlight, blockCount, cwnd, latestRtt, minRtt, rttVar, smoothedRtt, ssthresh, pktSent, bytesSent, pktRecv, bytesRecv, pktLost, bytesLost, pingRecv, pktDiscarded, datagramsReceived, datagramsSent, datagramsAcknowledged, datagramsLost, streamsIdleTimedOut, } = this; return `QuicSessionStats ${inspect({ connected: this.isConnected, createdAt, closingAt, handshakeCompletedAt, handshakeConfirmedAt, bytesReceived, bidiInStreamCount, bidiOutStreamCount, uniInStreamCount, uniOutStreamCount, maxBytesInFlight, bytesInFlight, blockCount, cwnd, latestRtt, minRtt, rttVar, smoothedRtt, ssthresh, pktSent, bytesSent, pktRecv, bytesRecv, pktLost, bytesLost, pingRecv, pktDiscarded, datagramsReceived, datagramsSent, datagramsAcknowledged, datagramsLost, streamsIdleTimedOut, }, opts)}`; } /** * True if this QuicSessionStats object is still connected to the underlying * Session stats source. If this returns false, then the stats object is * no longer being updated and should be considered stale. * @type {boolean} */ get isConnected() { return !this.#disconnected; } [kFinishClose]() { const view = TypedArrayPrototypeSubarray(this.#handle, this.#offset, this.#offset + IDX_STATS_SESSION_COUNT); this.#handle = new BigUint64Array(view); this.#offset = 0; this.#disconnected = true; } } class QuicStreamStats { /** @type {BigUint64Array} */ #handle; #offset = 0; #disconnected = false; static { isQuicStreamStats = function(val) { return val != null && typeof val === 'object' && #handle in val; }; assertIsQuicStreamStats = function(val) { if (!isQuicStreamStats(val)) { throw new ERR_INVALID_THIS('QuicStreamStats'); } }; } /** * @param {symbol} privateSymbol * @param {BigUint64Array|ArrayBuffer} view * @param {number} [byteOffset] - byte offset into the shared page view */ constructor(privateSymbol, view, byteOffset = 0) { // We use the kPrivateConstructor symbol to restrict the ability to // create new instances of QuicStreamStats to internal code. assertIsPrivateConstructor(privateSymbol); if (isArrayBuffer(view)) { this.#handle = new BigUint64Array(view); } else { this.#handle = view; } this.#offset = byteOffset / 8; } /** @type {bigint} */ get createdAt() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_CREATED_AT]; } /** @type {bigint} */ get openedAt() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_OPENED_AT]; } /** @type {bigint} */ get receivedAt() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_RECEIVED_AT]; } /** @type {bigint} */ get ackedAt() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_ACKED_AT]; } /** @type {bigint} */ get destroyedAt() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_DESTROYED_AT]; } /** @type {bigint} */ get bytesReceived() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_BYTES_RECEIVED]; } /** @type {bigint} */ get bytesSent() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_BYTES_SENT]; } /** @type {bigint} */ get maxOffset() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_OFFSET]; } /** @type {bigint} */ get maxOffsetAcknowledged() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_OFFSET_ACK]; } /** @type {bigint} */ get maxOffsetReceived() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_OFFSET_RECV]; } /** @type {bigint} */ get finalSize() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_FINAL_SIZE]; } /** @type {bigint} Current bytes in the receive accumulation buffer. */ get bytesAccumulated() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_BYTES_ACCUMULATED]; } /** @type {bigint} Peak bytes accumulated over the stream's lifetime. */ get maxBytesAccumulated() { assertIsQuicStreamStats(this); return this.#handle[this.#offset + IDX_STATS_STREAM_MAX_BYTES_ACCUMULATED]; } toString() { return JSONStringify(this.toJSON()); } toJSON() { assertIsQuicStreamStats(this); const { createdAt, openedAt, receivedAt, ackedAt, destroyedAt, bytesReceived, bytesSent, maxOffset, maxOffsetAcknowledged, maxOffsetReceived, finalSize, bytesAccumulated, maxBytesAccumulated, } = this; return { __proto__: null, connected: this.isConnected, // We need to convert the values to strings because JSON does not // support BigInts. createdAt: `${createdAt}`, openedAt: `${openedAt}`, receivedAt: `${receivedAt}`, ackedAt: `${ackedAt}`, destroyedAt: `${destroyedAt}`, bytesReceived: `${bytesReceived}`, bytesSent: `${bytesSent}`, maxOffset: `${maxOffset}`, maxOffsetAcknowledged: `${maxOffsetAcknowledged}`, maxOffsetReceived: `${maxOffsetReceived}`, finalSize: `${finalSize}`, bytesAccumulated: `${bytesAccumulated}`, maxBytesAccumulated: `${maxBytesAccumulated}`, }; } [kInspect](depth, options) { if (depth < 0) { return 'QuicStreamStats { }'; } const opts = { __proto__: null, ...options, depth: options.depth == null ? null : options.depth - 1, }; const { createdAt, openedAt, receivedAt, ackedAt, destroyedAt, bytesReceived, bytesSent, maxOffset, maxOffsetAcknowledged, maxOffsetReceived, finalSize, bytesAccumulated, maxBytesAccumulated, } = this; return `QuicStreamStats ${inspect({ connected: this.isConnected, createdAt, openedAt, receivedAt, ackedAt, destroyedAt, bytesReceived, bytesSent, maxOffset, maxOffsetAcknowledged, maxOffsetReceived, finalSize, bytesAccumulated, maxBytesAccumulated, }, opts)}`; } /** * True if this QuicStreamStats object is still connected to the underlying * Stream stats source. If this returns false, then the stats object is * no longer being updated and should be considered stale. * @type {boolean} */ get isConnected() { return !this.#disconnected; } [kFinishClose]() { const view = TypedArrayPrototypeSubarray(this.#handle, this.#offset, this.#offset + IDX_STATS_STREAM_COUNT); this.#handle = new BigUint64Array(view); this.#offset = 0; this.#disconnected = true; } // Creates an immediately disconnected QuicStreamStats object. Used when // lazily creating stats for a stream that has already been destroyed. static [kCreateDisconnected]() { const count = IDX_STATS_STREAM_COUNT; const stats = new QuicStreamStats(kPrivateConstructor, new BigUint64Array(count), 0); stats.#disconnected = true; return stats; } } module.exports = { QuicEndpointStats, QuicSessionStats, QuicStreamStats, kCreateDisconnected, }; /* c8 ignore stop */