@streamr/dht 103.7.0-rc.2 → 103.8.0-rc.3
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/dist/exports-browser.cjs +141 -3
- package/dist/exports-browser.cjs.map +1 -1
- package/dist/exports-browser.js +141 -3
- package/dist/exports-browser.js.map +1 -1
- package/dist/exports-nodejs.cjs +3 -3
- package/dist/exports-nodejs.cjs.map +1 -1
- package/dist/exports-nodejs.js +3 -3
- package/dist/exports-nodejs.js.map +1 -1
- package/package.json +7 -7
package/dist/exports-browser.cjs
CHANGED
|
@@ -261,15 +261,18 @@ class SendFailed extends Err {
|
|
|
261
261
|
constructor(message, originalError) { super(ErrorCode.SEND_FAILED, message, originalError); }
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
let enabled =
|
|
264
|
+
let enabled = true;
|
|
265
265
|
function setGapDiagnosticsEnabled(val) {
|
|
266
266
|
enabled = val;
|
|
267
267
|
globalThis.__dhtGapDiagEnabled = val;
|
|
268
268
|
}
|
|
269
|
+
function isGapDiagnosticsEnabled() {
|
|
270
|
+
return enabled;
|
|
271
|
+
}
|
|
269
272
|
const SUMMARY_INTERVAL_MS = 2000;
|
|
270
273
|
const accumulators = new Map();
|
|
271
274
|
function logGapDiagnosticSampled(layer, opts = {}) {
|
|
272
|
-
if (!enabled)
|
|
275
|
+
if (!enabled && !globalThis.__dhtGapDiagEnabled)
|
|
273
276
|
return;
|
|
274
277
|
const now = performance.now();
|
|
275
278
|
const threshold = opts.outlierThresholdMs ?? 30;
|
|
@@ -2884,7 +2887,7 @@ const parseVersion = (version) => {
|
|
|
2884
2887
|
}
|
|
2885
2888
|
};
|
|
2886
2889
|
|
|
2887
|
-
var version = "103.
|
|
2890
|
+
var version = "103.8.0-rc.3";
|
|
2888
2891
|
|
|
2889
2892
|
const logger$y = new utils.Logger('Handshaker');
|
|
2890
2893
|
// Optimally the Outgoing and Incoming Handshakers could be their own separate classes
|
|
@@ -3586,6 +3589,69 @@ function installWebrtcBridge(worker) {
|
|
|
3586
3589
|
* onbufferedamountlow) fire in the worker's event loop. The main thread
|
|
3587
3590
|
* is never involved in the data path.
|
|
3588
3591
|
*/
|
|
3592
|
+
// ── agent log: layer0-vs-layer2 contention probe ────────────────────
|
|
3593
|
+
// Every DHT connection's datachannel `onmessage` runs in THIS one worker, and
|
|
3594
|
+
// `emit('data')` synchronously drives the downstream routing / RPC dispatch.
|
|
3595
|
+
// So timing each emit captures the per-message synchronous processing cost —
|
|
3596
|
+
// and aggregating across ALL connections tells us how much of the worker's
|
|
3597
|
+
// event loop is consumed servicing GLOBAL-DHT layer0 traffic (routing for the
|
|
3598
|
+
// hundreds of nodes we forward for) vs our handful of media messages. If a
|
|
3599
|
+
// media arrival gap coincides with a window of high non-media processing, that
|
|
3600
|
+
// is layer0 starving layer2. Emitted in the same `[gap-diagnostics]` line
|
|
3601
|
+
// shape the analyzer already parses.
|
|
3602
|
+
let dcWinStart = performance.now();
|
|
3603
|
+
let dcWinCount = 0;
|
|
3604
|
+
let dcWinBusyMs = 0;
|
|
3605
|
+
let dcWinMaxMs = 0;
|
|
3606
|
+
function recordDcProcessing(procMs) {
|
|
3607
|
+
if (!isGapDiagnosticsEnabled() && !globalThis.__dhtGapDiagEnabled) {
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3610
|
+
dcWinCount++;
|
|
3611
|
+
dcWinBusyMs += procMs;
|
|
3612
|
+
if (procMs > dcWinMaxMs)
|
|
3613
|
+
dcWinMaxMs = procMs;
|
|
3614
|
+
// Individual event for a single message whose inline processing blocked the
|
|
3615
|
+
// loop unusually long (one expensive routing/RPC dispatch).
|
|
3616
|
+
if (procMs > 15) {
|
|
3617
|
+
try {
|
|
3618
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3619
|
+
layer: 'dht.dc.processing.slow',
|
|
3620
|
+
timestampMs: performance.now(),
|
|
3621
|
+
deltaMs: +procMs.toFixed(2),
|
|
3622
|
+
}));
|
|
3623
|
+
}
|
|
3624
|
+
catch {
|
|
3625
|
+
/* ignore */
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
const now = performance.now();
|
|
3629
|
+
const winElapsed = now - dcWinStart;
|
|
3630
|
+
if (winElapsed >= 1000) {
|
|
3631
|
+
try {
|
|
3632
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3633
|
+
layer: 'dht.dc.processing.window',
|
|
3634
|
+
timestampMs: now,
|
|
3635
|
+
detail: {
|
|
3636
|
+
windowMs: +winElapsed.toFixed(0),
|
|
3637
|
+
count: dcWinCount,
|
|
3638
|
+
msgPerSec: +((dcWinCount / winElapsed) * 1000).toFixed(0),
|
|
3639
|
+
busyMs: +dcWinBusyMs.toFixed(1),
|
|
3640
|
+
occupancyPct: +((dcWinBusyMs / winElapsed) *
|
|
3641
|
+
100).toFixed(1),
|
|
3642
|
+
maxMs: +dcWinMaxMs.toFixed(1),
|
|
3643
|
+
},
|
|
3644
|
+
}));
|
|
3645
|
+
}
|
|
3646
|
+
catch {
|
|
3647
|
+
/* ignore */
|
|
3648
|
+
}
|
|
3649
|
+
dcWinStart = now;
|
|
3650
|
+
dcWinCount = 0;
|
|
3651
|
+
dcWinBusyMs = 0;
|
|
3652
|
+
dcWinMaxMs = 0;
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3589
3655
|
// ── Module-level bridge client (initialized once per worker) ────────
|
|
3590
3656
|
let resolveBridgeProxy;
|
|
3591
3657
|
const bridgeProxyPromise = new Promise((resolve) => {
|
|
@@ -3628,6 +3694,19 @@ class WorkerWebrtcConnection extends eventemitter3.EventEmitter {
|
|
|
3628
3694
|
earlyTimeout;
|
|
3629
3695
|
messageQueue = [];
|
|
3630
3696
|
startPromise;
|
|
3697
|
+
// agent log: PER-CONNECTION datachannel receive cadence. The global
|
|
3698
|
+
// `dht.dc.onmessage` accumulator can't isolate one stream; this tracks
|
|
3699
|
+
// inter-message arrival on THIS connection so we can pick the connection
|
|
3700
|
+
// carrying the composite media (highest count/bytes) and compare its
|
|
3701
|
+
// datachannel-level gaps against messageArrival (post-routing) and
|
|
3702
|
+
// videoFrameArrival (post-decrypt) — i.e. localize WHERE the gap is born.
|
|
3703
|
+
lastRecvMs;
|
|
3704
|
+
recvWinStart = 0;
|
|
3705
|
+
recvCount = 0;
|
|
3706
|
+
recvSumDelta = 0;
|
|
3707
|
+
recvMaxDelta = 0;
|
|
3708
|
+
recvBytes = 0;
|
|
3709
|
+
recvMaxBytes = 0;
|
|
3631
3710
|
constructor(params) {
|
|
3632
3711
|
super();
|
|
3633
3712
|
this.connectionId = createRandomConnectionId();
|
|
@@ -3743,6 +3822,62 @@ class WorkerWebrtcConnection extends eventemitter3.EventEmitter {
|
|
|
3743
3822
|
}
|
|
3744
3823
|
}
|
|
3745
3824
|
// ── DataChannel handling (runs entirely in the worker) ──────
|
|
3825
|
+
recordRecv(bytes) {
|
|
3826
|
+
if (!isGapDiagnosticsEnabled() && !globalThis.__dhtGapDiagEnabled) {
|
|
3827
|
+
return;
|
|
3828
|
+
}
|
|
3829
|
+
const now = performance.now();
|
|
3830
|
+
const conn = String(this.connectionId).slice(0, 8);
|
|
3831
|
+
if (this.lastRecvMs !== undefined) {
|
|
3832
|
+
const delta = now - this.lastRecvMs;
|
|
3833
|
+
this.recvSumDelta += delta;
|
|
3834
|
+
if (delta > this.recvMaxDelta)
|
|
3835
|
+
this.recvMaxDelta = delta;
|
|
3836
|
+
if (delta > 60) {
|
|
3837
|
+
try {
|
|
3838
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3839
|
+
layer: 'dht.dc.recvGap',
|
|
3840
|
+
timestampMs: now,
|
|
3841
|
+
deltaMs: +delta.toFixed(1),
|
|
3842
|
+
detail: { conn, bytes },
|
|
3843
|
+
}));
|
|
3844
|
+
}
|
|
3845
|
+
catch (_e) { /* ignore */ }
|
|
3846
|
+
}
|
|
3847
|
+
}
|
|
3848
|
+
this.lastRecvMs = now;
|
|
3849
|
+
this.recvCount++;
|
|
3850
|
+
this.recvBytes += bytes;
|
|
3851
|
+
if (bytes > this.recvMaxBytes)
|
|
3852
|
+
this.recvMaxBytes = bytes;
|
|
3853
|
+
if (this.recvWinStart === 0)
|
|
3854
|
+
this.recvWinStart = now;
|
|
3855
|
+
const elapsed = now - this.recvWinStart;
|
|
3856
|
+
if (elapsed >= 1000) {
|
|
3857
|
+
try {
|
|
3858
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3859
|
+
layer: 'dht.dc.recv',
|
|
3860
|
+
timestampMs: now,
|
|
3861
|
+
detail: {
|
|
3862
|
+
conn,
|
|
3863
|
+
count: this.recvCount,
|
|
3864
|
+
perSec: Math.round((this.recvCount / elapsed) * 1000),
|
|
3865
|
+
meanMs: +(this.recvSumDelta / Math.max(1, this.recvCount)).toFixed(1),
|
|
3866
|
+
maxMs: +this.recvMaxDelta.toFixed(1),
|
|
3867
|
+
bytesPerSec: Math.round((this.recvBytes / elapsed) * 1000),
|
|
3868
|
+
maxBytes: this.recvMaxBytes,
|
|
3869
|
+
},
|
|
3870
|
+
}));
|
|
3871
|
+
}
|
|
3872
|
+
catch (_e) { /* ignore */ }
|
|
3873
|
+
this.recvWinStart = now;
|
|
3874
|
+
this.recvCount = 0;
|
|
3875
|
+
this.recvSumDelta = 0;
|
|
3876
|
+
this.recvMaxDelta = 0;
|
|
3877
|
+
this.recvBytes = 0;
|
|
3878
|
+
this.recvMaxBytes = 0;
|
|
3879
|
+
}
|
|
3880
|
+
}
|
|
3746
3881
|
setupDataChannel(dataChannel) {
|
|
3747
3882
|
this.dataChannel = dataChannel;
|
|
3748
3883
|
this.dataChannel.binaryType = 'arraybuffer';
|
|
@@ -3761,7 +3896,10 @@ class WorkerWebrtcConnection extends eventemitter3.EventEmitter {
|
|
|
3761
3896
|
dataChannel.onmessage = (msg) => {
|
|
3762
3897
|
logger$u.trace('dc.onmessage (worker)');
|
|
3763
3898
|
logGapDiagnosticSampled('dht.dc.onmessage');
|
|
3899
|
+
this.recordRecv(msg.data instanceof ArrayBuffer ? msg.data.byteLength : 0);
|
|
3900
|
+
const t0 = performance.now();
|
|
3764
3901
|
this.emit('data', new Uint8Array(msg.data));
|
|
3902
|
+
recordDcProcessing(performance.now() - t0);
|
|
3765
3903
|
};
|
|
3766
3904
|
dataChannel.onbufferedamountlow = () => {
|
|
3767
3905
|
logger$u.trace('dc.onBufferedAmountLow (worker)');
|