@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.js
CHANGED
|
@@ -240,15 +240,18 @@ class SendFailed extends Err {
|
|
|
240
240
|
constructor(message, originalError) { super(ErrorCode.SEND_FAILED, message, originalError); }
|
|
241
241
|
}
|
|
242
242
|
|
|
243
|
-
let enabled =
|
|
243
|
+
let enabled = true;
|
|
244
244
|
function setGapDiagnosticsEnabled(val) {
|
|
245
245
|
enabled = val;
|
|
246
246
|
globalThis.__dhtGapDiagEnabled = val;
|
|
247
247
|
}
|
|
248
|
+
function isGapDiagnosticsEnabled() {
|
|
249
|
+
return enabled;
|
|
250
|
+
}
|
|
248
251
|
const SUMMARY_INTERVAL_MS = 2000;
|
|
249
252
|
const accumulators = new Map();
|
|
250
253
|
function logGapDiagnosticSampled(layer, opts = {}) {
|
|
251
|
-
if (!enabled)
|
|
254
|
+
if (!enabled && !globalThis.__dhtGapDiagEnabled)
|
|
252
255
|
return;
|
|
253
256
|
const now = performance.now();
|
|
254
257
|
const threshold = opts.outlierThresholdMs ?? 30;
|
|
@@ -2863,7 +2866,7 @@ const parseVersion = (version) => {
|
|
|
2863
2866
|
}
|
|
2864
2867
|
};
|
|
2865
2868
|
|
|
2866
|
-
var version = "103.
|
|
2869
|
+
var version = "103.8.0-rc.3";
|
|
2867
2870
|
|
|
2868
2871
|
const logger$y = new Logger('Handshaker');
|
|
2869
2872
|
// Optimally the Outgoing and Incoming Handshakers could be their own separate classes
|
|
@@ -3565,6 +3568,69 @@ function installWebrtcBridge(worker) {
|
|
|
3565
3568
|
* onbufferedamountlow) fire in the worker's event loop. The main thread
|
|
3566
3569
|
* is never involved in the data path.
|
|
3567
3570
|
*/
|
|
3571
|
+
// ── agent log: layer0-vs-layer2 contention probe ────────────────────
|
|
3572
|
+
// Every DHT connection's datachannel `onmessage` runs in THIS one worker, and
|
|
3573
|
+
// `emit('data')` synchronously drives the downstream routing / RPC dispatch.
|
|
3574
|
+
// So timing each emit captures the per-message synchronous processing cost —
|
|
3575
|
+
// and aggregating across ALL connections tells us how much of the worker's
|
|
3576
|
+
// event loop is consumed servicing GLOBAL-DHT layer0 traffic (routing for the
|
|
3577
|
+
// hundreds of nodes we forward for) vs our handful of media messages. If a
|
|
3578
|
+
// media arrival gap coincides with a window of high non-media processing, that
|
|
3579
|
+
// is layer0 starving layer2. Emitted in the same `[gap-diagnostics]` line
|
|
3580
|
+
// shape the analyzer already parses.
|
|
3581
|
+
let dcWinStart = performance.now();
|
|
3582
|
+
let dcWinCount = 0;
|
|
3583
|
+
let dcWinBusyMs = 0;
|
|
3584
|
+
let dcWinMaxMs = 0;
|
|
3585
|
+
function recordDcProcessing(procMs) {
|
|
3586
|
+
if (!isGapDiagnosticsEnabled() && !globalThis.__dhtGapDiagEnabled) {
|
|
3587
|
+
return;
|
|
3588
|
+
}
|
|
3589
|
+
dcWinCount++;
|
|
3590
|
+
dcWinBusyMs += procMs;
|
|
3591
|
+
if (procMs > dcWinMaxMs)
|
|
3592
|
+
dcWinMaxMs = procMs;
|
|
3593
|
+
// Individual event for a single message whose inline processing blocked the
|
|
3594
|
+
// loop unusually long (one expensive routing/RPC dispatch).
|
|
3595
|
+
if (procMs > 15) {
|
|
3596
|
+
try {
|
|
3597
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3598
|
+
layer: 'dht.dc.processing.slow',
|
|
3599
|
+
timestampMs: performance.now(),
|
|
3600
|
+
deltaMs: +procMs.toFixed(2),
|
|
3601
|
+
}));
|
|
3602
|
+
}
|
|
3603
|
+
catch {
|
|
3604
|
+
/* ignore */
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
const now = performance.now();
|
|
3608
|
+
const winElapsed = now - dcWinStart;
|
|
3609
|
+
if (winElapsed >= 1000) {
|
|
3610
|
+
try {
|
|
3611
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3612
|
+
layer: 'dht.dc.processing.window',
|
|
3613
|
+
timestampMs: now,
|
|
3614
|
+
detail: {
|
|
3615
|
+
windowMs: +winElapsed.toFixed(0),
|
|
3616
|
+
count: dcWinCount,
|
|
3617
|
+
msgPerSec: +((dcWinCount / winElapsed) * 1000).toFixed(0),
|
|
3618
|
+
busyMs: +dcWinBusyMs.toFixed(1),
|
|
3619
|
+
occupancyPct: +((dcWinBusyMs / winElapsed) *
|
|
3620
|
+
100).toFixed(1),
|
|
3621
|
+
maxMs: +dcWinMaxMs.toFixed(1),
|
|
3622
|
+
},
|
|
3623
|
+
}));
|
|
3624
|
+
}
|
|
3625
|
+
catch {
|
|
3626
|
+
/* ignore */
|
|
3627
|
+
}
|
|
3628
|
+
dcWinStart = now;
|
|
3629
|
+
dcWinCount = 0;
|
|
3630
|
+
dcWinBusyMs = 0;
|
|
3631
|
+
dcWinMaxMs = 0;
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3568
3634
|
// ── Module-level bridge client (initialized once per worker) ────────
|
|
3569
3635
|
let resolveBridgeProxy;
|
|
3570
3636
|
const bridgeProxyPromise = new Promise((resolve) => {
|
|
@@ -3607,6 +3673,19 @@ class WorkerWebrtcConnection extends EventEmitter {
|
|
|
3607
3673
|
earlyTimeout;
|
|
3608
3674
|
messageQueue = [];
|
|
3609
3675
|
startPromise;
|
|
3676
|
+
// agent log: PER-CONNECTION datachannel receive cadence. The global
|
|
3677
|
+
// `dht.dc.onmessage` accumulator can't isolate one stream; this tracks
|
|
3678
|
+
// inter-message arrival on THIS connection so we can pick the connection
|
|
3679
|
+
// carrying the composite media (highest count/bytes) and compare its
|
|
3680
|
+
// datachannel-level gaps against messageArrival (post-routing) and
|
|
3681
|
+
// videoFrameArrival (post-decrypt) — i.e. localize WHERE the gap is born.
|
|
3682
|
+
lastRecvMs;
|
|
3683
|
+
recvWinStart = 0;
|
|
3684
|
+
recvCount = 0;
|
|
3685
|
+
recvSumDelta = 0;
|
|
3686
|
+
recvMaxDelta = 0;
|
|
3687
|
+
recvBytes = 0;
|
|
3688
|
+
recvMaxBytes = 0;
|
|
3610
3689
|
constructor(params) {
|
|
3611
3690
|
super();
|
|
3612
3691
|
this.connectionId = createRandomConnectionId();
|
|
@@ -3722,6 +3801,62 @@ class WorkerWebrtcConnection extends EventEmitter {
|
|
|
3722
3801
|
}
|
|
3723
3802
|
}
|
|
3724
3803
|
// ── DataChannel handling (runs entirely in the worker) ──────
|
|
3804
|
+
recordRecv(bytes) {
|
|
3805
|
+
if (!isGapDiagnosticsEnabled() && !globalThis.__dhtGapDiagEnabled) {
|
|
3806
|
+
return;
|
|
3807
|
+
}
|
|
3808
|
+
const now = performance.now();
|
|
3809
|
+
const conn = String(this.connectionId).slice(0, 8);
|
|
3810
|
+
if (this.lastRecvMs !== undefined) {
|
|
3811
|
+
const delta = now - this.lastRecvMs;
|
|
3812
|
+
this.recvSumDelta += delta;
|
|
3813
|
+
if (delta > this.recvMaxDelta)
|
|
3814
|
+
this.recvMaxDelta = delta;
|
|
3815
|
+
if (delta > 60) {
|
|
3816
|
+
try {
|
|
3817
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3818
|
+
layer: 'dht.dc.recvGap',
|
|
3819
|
+
timestampMs: now,
|
|
3820
|
+
deltaMs: +delta.toFixed(1),
|
|
3821
|
+
detail: { conn, bytes },
|
|
3822
|
+
}));
|
|
3823
|
+
}
|
|
3824
|
+
catch (_e) { /* ignore */ }
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
this.lastRecvMs = now;
|
|
3828
|
+
this.recvCount++;
|
|
3829
|
+
this.recvBytes += bytes;
|
|
3830
|
+
if (bytes > this.recvMaxBytes)
|
|
3831
|
+
this.recvMaxBytes = bytes;
|
|
3832
|
+
if (this.recvWinStart === 0)
|
|
3833
|
+
this.recvWinStart = now;
|
|
3834
|
+
const elapsed = now - this.recvWinStart;
|
|
3835
|
+
if (elapsed >= 1000) {
|
|
3836
|
+
try {
|
|
3837
|
+
console.log('[gap-diagnostics]', JSON.stringify({
|
|
3838
|
+
layer: 'dht.dc.recv',
|
|
3839
|
+
timestampMs: now,
|
|
3840
|
+
detail: {
|
|
3841
|
+
conn,
|
|
3842
|
+
count: this.recvCount,
|
|
3843
|
+
perSec: Math.round((this.recvCount / elapsed) * 1000),
|
|
3844
|
+
meanMs: +(this.recvSumDelta / Math.max(1, this.recvCount)).toFixed(1),
|
|
3845
|
+
maxMs: +this.recvMaxDelta.toFixed(1),
|
|
3846
|
+
bytesPerSec: Math.round((this.recvBytes / elapsed) * 1000),
|
|
3847
|
+
maxBytes: this.recvMaxBytes,
|
|
3848
|
+
},
|
|
3849
|
+
}));
|
|
3850
|
+
}
|
|
3851
|
+
catch (_e) { /* ignore */ }
|
|
3852
|
+
this.recvWinStart = now;
|
|
3853
|
+
this.recvCount = 0;
|
|
3854
|
+
this.recvSumDelta = 0;
|
|
3855
|
+
this.recvMaxDelta = 0;
|
|
3856
|
+
this.recvBytes = 0;
|
|
3857
|
+
this.recvMaxBytes = 0;
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3725
3860
|
setupDataChannel(dataChannel) {
|
|
3726
3861
|
this.dataChannel = dataChannel;
|
|
3727
3862
|
this.dataChannel.binaryType = 'arraybuffer';
|
|
@@ -3740,7 +3875,10 @@ class WorkerWebrtcConnection extends EventEmitter {
|
|
|
3740
3875
|
dataChannel.onmessage = (msg) => {
|
|
3741
3876
|
logger$u.trace('dc.onmessage (worker)');
|
|
3742
3877
|
logGapDiagnosticSampled('dht.dc.onmessage');
|
|
3878
|
+
this.recordRecv(msg.data instanceof ArrayBuffer ? msg.data.byteLength : 0);
|
|
3879
|
+
const t0 = performance.now();
|
|
3743
3880
|
this.emit('data', new Uint8Array(msg.data));
|
|
3881
|
+
recordDcProcessing(performance.now() - t0);
|
|
3744
3882
|
};
|
|
3745
3883
|
dataChannel.onbufferedamountlow = () => {
|
|
3746
3884
|
logger$u.trace('dc.onBufferedAmountLow (worker)');
|