@streamr/trackerless-network 103.3.1 → 103.7.0-rc.2
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.cjs +202 -36
- package/dist/exports.cjs.map +1 -1
- package/dist/exports.d.ts +30 -2
- package/dist/exports.js +202 -38
- package/dist/exports.js.map +1 -1
- package/package.json +5 -5
package/dist/exports.cjs
CHANGED
|
@@ -29,7 +29,7 @@ class ExternalNetworkRpc {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
var version = "103.
|
|
32
|
+
var version = "103.7.0-rc.2";
|
|
33
33
|
|
|
34
34
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
35
35
|
class Any$Type extends runtime.MessageType {
|
|
@@ -1676,6 +1676,18 @@ class PauseNeighborRequest$Type extends runtime.MessageType {
|
|
|
1676
1676
|
*/
|
|
1677
1677
|
const PauseNeighborRequest = new PauseNeighborRequest$Type();
|
|
1678
1678
|
// @generated message type with reflection information, may provide speed optimized methods
|
|
1679
|
+
class PauseNeighborResponse$Type extends runtime.MessageType {
|
|
1680
|
+
constructor() {
|
|
1681
|
+
super("PauseNeighborResponse", [
|
|
1682
|
+
{ no: 1, name: "accepted", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }
|
|
1683
|
+
]);
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
/**
|
|
1687
|
+
* @generated MessageType for protobuf message PauseNeighborResponse
|
|
1688
|
+
*/
|
|
1689
|
+
const PauseNeighborResponse = new PauseNeighborResponse$Type();
|
|
1690
|
+
// @generated message type with reflection information, may provide speed optimized methods
|
|
1679
1691
|
class ResumeNeighborRequest$Type extends runtime.MessageType {
|
|
1680
1692
|
constructor() {
|
|
1681
1693
|
super("ResumeNeighborRequest", [
|
|
@@ -1731,7 +1743,7 @@ const NodeInfoRpc = new runtimeRpc.ServiceType("NodeInfoRpc", [
|
|
|
1731
1743
|
* @generated ServiceType for protobuf service PlumtreeRpc
|
|
1732
1744
|
*/
|
|
1733
1745
|
const PlumtreeRpc = new runtimeRpc.ServiceType("PlumtreeRpc", [
|
|
1734
|
-
{ name: "pauseNeighbor", options: {}, I: PauseNeighborRequest, O:
|
|
1746
|
+
{ name: "pauseNeighbor", options: {}, I: PauseNeighborRequest, O: PauseNeighborResponse },
|
|
1735
1747
|
{ name: "resumeNeighbor", options: {}, I: ResumeNeighborRequest, O: Empty },
|
|
1736
1748
|
{ name: "sendMetadata", options: {}, I: MessageID, O: Empty }
|
|
1737
1749
|
]);
|
|
@@ -2392,12 +2404,72 @@ class NeighborUpdateManager {
|
|
|
2392
2404
|
}
|
|
2393
2405
|
}
|
|
2394
2406
|
|
|
2407
|
+
let enabled = false;
|
|
2408
|
+
function setGapDiagnosticsEnabled(val) {
|
|
2409
|
+
enabled = val;
|
|
2410
|
+
globalThis.__trackerlessGapDiagEnabled = val;
|
|
2411
|
+
}
|
|
2412
|
+
const SUMMARY_INTERVAL_MS = 2000;
|
|
2413
|
+
const accumulators = new Map();
|
|
2414
|
+
function logGapDiagnosticSampled(layer, opts = {}) {
|
|
2415
|
+
if (!enabled)
|
|
2416
|
+
return;
|
|
2417
|
+
const now = performance.now();
|
|
2418
|
+
const threshold = opts.outlierThresholdMs ?? 30;
|
|
2419
|
+
let acc = accumulators.get(layer);
|
|
2420
|
+
if (acc === undefined) {
|
|
2421
|
+
acc = { count: 0, sumDeltaMs: 0, maxDeltaMs: 0, outlierCount: 0, lastReportMs: now, lastEventMs: now };
|
|
2422
|
+
accumulators.set(layer, acc);
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2425
|
+
const deltaMs = now - acc.lastEventMs;
|
|
2426
|
+
acc.lastEventMs = now;
|
|
2427
|
+
acc.count++;
|
|
2428
|
+
if (deltaMs > acc.maxDeltaMs)
|
|
2429
|
+
acc.maxDeltaMs = deltaMs;
|
|
2430
|
+
acc.sumDeltaMs += deltaMs;
|
|
2431
|
+
if (deltaMs > threshold)
|
|
2432
|
+
acc.outlierCount++;
|
|
2433
|
+
if (deltaMs > threshold) {
|
|
2434
|
+
const payload = {
|
|
2435
|
+
layer,
|
|
2436
|
+
timestampMs: now,
|
|
2437
|
+
deltaMs: +deltaMs.toFixed(2),
|
|
2438
|
+
detail: opts.detail,
|
|
2439
|
+
};
|
|
2440
|
+
// eslint-disable-next-line no-console
|
|
2441
|
+
console.log('[gap-diagnostics]', JSON.stringify(payload));
|
|
2442
|
+
}
|
|
2443
|
+
if (now - acc.lastReportMs >= SUMMARY_INTERVAL_MS) {
|
|
2444
|
+
const summaryDetail = {
|
|
2445
|
+
count: acc.count,
|
|
2446
|
+
meanDeltaMs: acc.count > 0 ? +(acc.sumDeltaMs / acc.count).toFixed(2) : 0,
|
|
2447
|
+
maxDeltaMs: +acc.maxDeltaMs.toFixed(2),
|
|
2448
|
+
outlierCount: acc.outlierCount,
|
|
2449
|
+
periodMs: +(now - acc.lastReportMs).toFixed(1),
|
|
2450
|
+
};
|
|
2451
|
+
const summary = {
|
|
2452
|
+
layer: `${layer}.summary`,
|
|
2453
|
+
timestampMs: now,
|
|
2454
|
+
detail: summaryDetail,
|
|
2455
|
+
};
|
|
2456
|
+
// eslint-disable-next-line no-console
|
|
2457
|
+
console.log('[gap-diagnostics]', JSON.stringify(summary));
|
|
2458
|
+
acc.count = 0;
|
|
2459
|
+
acc.sumDeltaMs = 0;
|
|
2460
|
+
acc.maxDeltaMs = 0;
|
|
2461
|
+
acc.outlierCount = 0;
|
|
2462
|
+
acc.lastReportMs = now;
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
|
|
2395
2466
|
class ContentDeliveryRpcLocal {
|
|
2396
2467
|
options;
|
|
2397
2468
|
constructor(options) {
|
|
2398
2469
|
this.options = options;
|
|
2399
2470
|
}
|
|
2400
2471
|
async sendStreamMessage(message, context) {
|
|
2472
|
+
logGapDiagnosticSampled('trackerless.rpcLocal.sendStreamMessage');
|
|
2401
2473
|
const previousNode = context.incomingSourceDescriptor;
|
|
2402
2474
|
const previousNodeId = dht.toNodeId(previousNode);
|
|
2403
2475
|
this.options.markForInspection(previousNodeId, message.messageId);
|
|
@@ -2758,11 +2830,16 @@ class ContentDeliveryLayerNode extends eventemitter3.EventEmitter {
|
|
|
2758
2830
|
this.options.neighborFinder.stop();
|
|
2759
2831
|
this.options.neighborUpdateManager.stop();
|
|
2760
2832
|
this.options.inspector.stop();
|
|
2833
|
+
this.duplicateDetectors.clear();
|
|
2761
2834
|
}
|
|
2762
2835
|
broadcast(msg, previousNode) {
|
|
2763
2836
|
if (!previousNode) {
|
|
2837
|
+
logGapDiagnosticSampled('trackerless.cdNode.broadcastOut');
|
|
2764
2838
|
markAndCheckDuplicate(this.duplicateDetectors, msg.messageId, msg.previousMessageRef);
|
|
2765
2839
|
}
|
|
2840
|
+
else {
|
|
2841
|
+
logGapDiagnosticSampled('trackerless.cdNode.broadcastIn');
|
|
2842
|
+
}
|
|
2766
2843
|
this.emit('message', msg);
|
|
2767
2844
|
const skipBackPropagation = previousNode !== undefined && !this.options.temporaryConnectionRpcLocal.hasNode(previousNode);
|
|
2768
2845
|
this.options.propagation.feedUnseenMessage(msg, this.getPropagationTargets(msg), skipBackPropagation ? previousNode : null);
|
|
@@ -3060,6 +3137,7 @@ class Propagation {
|
|
|
3060
3137
|
}
|
|
3061
3138
|
sendAndAwaitThenMark({ message, source, handledNeighbors }, neighborId) {
|
|
3062
3139
|
if (!handledNeighbors.has(neighborId) && neighborId !== source) {
|
|
3140
|
+
logGapDiagnosticSampled('trackerless.propagation.sendToNeighbor');
|
|
3063
3141
|
(async () => {
|
|
3064
3142
|
try {
|
|
3065
3143
|
await this.sendToNeighbor(neighborId, message);
|
|
@@ -3333,14 +3411,17 @@ class PlumtreeRpcLocal {
|
|
|
3333
3411
|
async pauseNeighbor(request, context) {
|
|
3334
3412
|
const sender = dht.toNodeId(context.incomingSourceDescriptor);
|
|
3335
3413
|
if (this.neighbors.has(sender)) {
|
|
3336
|
-
this.pausedNodes.add(sender, request.messageChainId);
|
|
3414
|
+
const accepted = this.pausedNodes.add(sender, request.messageChainId);
|
|
3415
|
+
return { accepted };
|
|
3337
3416
|
}
|
|
3338
|
-
return
|
|
3417
|
+
return { accepted: false };
|
|
3339
3418
|
}
|
|
3340
3419
|
async resumeNeighbor(request, context) {
|
|
3341
3420
|
const sender = context.incomingSourceDescriptor;
|
|
3342
|
-
this.
|
|
3343
|
-
|
|
3421
|
+
if (this.neighbors.has(dht.toNodeId(sender))) {
|
|
3422
|
+
this.pausedNodes.delete(dht.toNodeId(sender), request.messageChainId);
|
|
3423
|
+
await this.sendBuffer(request.fromTimestamp, request.messageChainId, sender);
|
|
3424
|
+
}
|
|
3344
3425
|
return Empty;
|
|
3345
3426
|
}
|
|
3346
3427
|
}
|
|
@@ -3353,10 +3434,9 @@ class PlumtreeRpcRemote extends dht.RpcRemote {
|
|
|
3353
3434
|
await this.getClient().sendMetadata(msg, options);
|
|
3354
3435
|
}
|
|
3355
3436
|
async pauseNeighbor(messageChainId) {
|
|
3356
|
-
const options = this.formDhtRpcOptions(
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
await this.getClient().pauseNeighbor({ messageChainId }, options);
|
|
3437
|
+
const options = this.formDhtRpcOptions();
|
|
3438
|
+
const response = await this.getClient().pauseNeighbor({ messageChainId }, options);
|
|
3439
|
+
return response.accepted;
|
|
3360
3440
|
}
|
|
3361
3441
|
async resumeNeighbor(fromTimestamp, messageChainId) {
|
|
3362
3442
|
const options = this.formDhtRpcOptions({
|
|
@@ -3378,9 +3458,10 @@ class PausedNeighbors {
|
|
|
3378
3458
|
this.pausedNeighbors.set(msgChainId, new Set());
|
|
3379
3459
|
}
|
|
3380
3460
|
if (this.pausedNeighbors.get(msgChainId).size >= this.limit) {
|
|
3381
|
-
return;
|
|
3461
|
+
return false;
|
|
3382
3462
|
}
|
|
3383
3463
|
this.pausedNeighbors.get(msgChainId).add(node);
|
|
3464
|
+
return true;
|
|
3384
3465
|
}
|
|
3385
3466
|
delete(node, msgChainId) {
|
|
3386
3467
|
this.pausedNeighbors.get(msgChainId)?.delete(node);
|
|
@@ -3413,19 +3494,24 @@ class PausedNeighbors {
|
|
|
3413
3494
|
}
|
|
3414
3495
|
|
|
3415
3496
|
const MAX_PAUSED_NEIGHBORS_DEFAULT = 3;
|
|
3497
|
+
const DEFAULT_RECOVERY_TIMEOUT = 500;
|
|
3498
|
+
const DEFAULT_RECOVERY_CHECK_INTERVAL = 200;
|
|
3499
|
+
const DEFAULT_RECOVERY_COOLDOWN = 2500;
|
|
3416
3500
|
const logger$4 = new utils.Logger('PlumtreeManager');
|
|
3417
3501
|
class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
3418
3502
|
neighbors;
|
|
3419
3503
|
localPeerDescriptor;
|
|
3420
|
-
// We have paused sending real data to these neighbrs and only send metadata
|
|
3421
3504
|
localPausedNeighbors;
|
|
3422
|
-
// We have asked these nodes to pause sending real data to us, used to limit sending of pausing and resuming requests
|
|
3423
3505
|
remotePausedNeighbors;
|
|
3424
3506
|
rpcLocal;
|
|
3425
3507
|
latestMessages = new Map();
|
|
3426
3508
|
rpcCommunicator;
|
|
3427
|
-
metadataTimestampsAheadOfRealData = new Map();
|
|
3428
3509
|
maxPausedNeighbors;
|
|
3510
|
+
recoveryState = new Map();
|
|
3511
|
+
recoveryCooldownUntil = new Map();
|
|
3512
|
+
recoveryTimeout;
|
|
3513
|
+
recoveryCooldown;
|
|
3514
|
+
abortController = new AbortController();
|
|
3429
3515
|
constructor(options) {
|
|
3430
3516
|
super();
|
|
3431
3517
|
this.neighbors = options.neighbors;
|
|
@@ -3433,12 +3519,22 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3433
3519
|
this.localPeerDescriptor = options.localPeerDescriptor;
|
|
3434
3520
|
this.localPausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
|
|
3435
3521
|
this.remotePausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
|
|
3522
|
+
this.recoveryTimeout = options.recoveryTimeout ?? DEFAULT_RECOVERY_TIMEOUT;
|
|
3523
|
+
this.recoveryCooldown = options.recoveryCooldown ?? DEFAULT_RECOVERY_COOLDOWN;
|
|
3436
3524
|
this.rpcLocal = new PlumtreeRpcLocal(this.neighbors, this.localPausedNeighbors, (metadata, previousNode) => this.onMetadata(metadata, previousNode), (fromTimestamp, msgChainId, remotePeerDescriptor) => this.sendBuffer(fromTimestamp, msgChainId, remotePeerDescriptor));
|
|
3437
|
-
this.neighbors.on('nodeRemoved',
|
|
3525
|
+
this.neighbors.on('nodeRemoved', this.onNeighborRemoved);
|
|
3438
3526
|
this.rpcCommunicator = options.rpcCommunicator;
|
|
3439
3527
|
this.rpcCommunicator.registerRpcNotification(MessageID, 'sendMetadata', (msg, context) => this.rpcLocal.sendMetadata(msg, context));
|
|
3440
|
-
this.rpcCommunicator.
|
|
3528
|
+
this.rpcCommunicator.registerRpcMethod(PauseNeighborRequest, PauseNeighborResponse, 'pauseNeighbor', (msg, context) => this.rpcLocal.pauseNeighbor(msg, context));
|
|
3441
3529
|
this.rpcCommunicator.registerRpcNotification(ResumeNeighborRequest, 'resumeNeighbor', (msg, context) => this.rpcLocal.resumeNeighbor(msg, context));
|
|
3530
|
+
utils.setAbortableInterval(() => {
|
|
3531
|
+
const now = performance.now();
|
|
3532
|
+
for (const [chainId, state] of this.recoveryState) {
|
|
3533
|
+
if (now - state.metadataAheadSince >= this.recoveryTimeout && !state.resumeInProgress) {
|
|
3534
|
+
this.attemptRecovery(chainId, state, this.getLatestMessageTimestamp(chainId));
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
}, options.recoveryCheckInterval ?? DEFAULT_RECOVERY_CHECK_INTERVAL, this.abortController.signal);
|
|
3442
3538
|
}
|
|
3443
3539
|
async pauseNeighbor(node, msgChainId) {
|
|
3444
3540
|
if (this.neighbors.has(dht.toNodeId(node))
|
|
@@ -3446,8 +3542,16 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3446
3542
|
&& this.remotePausedNeighbors.size(msgChainId) < this.maxPausedNeighbors) {
|
|
3447
3543
|
logger$4.debug(`Pausing neighbor ${dht.toNodeId(node)}`);
|
|
3448
3544
|
this.remotePausedNeighbors.add(dht.toNodeId(node), msgChainId);
|
|
3449
|
-
|
|
3450
|
-
|
|
3545
|
+
try {
|
|
3546
|
+
const remote = this.createRemote(node);
|
|
3547
|
+
const accepted = await remote.pauseNeighbor(msgChainId);
|
|
3548
|
+
if (!accepted) {
|
|
3549
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(node), msgChainId);
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
catch (_e) {
|
|
3553
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(node), msgChainId);
|
|
3554
|
+
}
|
|
3451
3555
|
}
|
|
3452
3556
|
}
|
|
3453
3557
|
async resumeNeighbor(node, msgChainId, fromTimestamp) {
|
|
@@ -3458,9 +3562,15 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3458
3562
|
await remote.resumeNeighbor(fromTimestamp, msgChainId);
|
|
3459
3563
|
}
|
|
3460
3564
|
}
|
|
3461
|
-
onNeighborRemoved(nodeId) {
|
|
3565
|
+
onNeighborRemoved = (nodeId) => {
|
|
3462
3566
|
this.localPausedNeighbors.deleteAll(nodeId);
|
|
3463
3567
|
this.remotePausedNeighbors.deleteAll(nodeId);
|
|
3568
|
+
for (const [_chainId, state] of this.recoveryState) {
|
|
3569
|
+
state.candidates = state.candidates.filter((c) => dht.toNodeId(c) !== nodeId);
|
|
3570
|
+
if (state.lastAttemptedNode !== null && dht.toNodeId(state.lastAttemptedNode) === nodeId) {
|
|
3571
|
+
state.lastAttemptedNode = null;
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3464
3574
|
if (this.neighbors.size() > 0) {
|
|
3465
3575
|
this.remotePausedNeighbors.forEach((pausedNeighbors, msgChainId) => {
|
|
3466
3576
|
if (pausedNeighbors.size >= this.neighbors.size()) {
|
|
@@ -3470,7 +3580,7 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3470
3580
|
}
|
|
3471
3581
|
});
|
|
3472
3582
|
}
|
|
3473
|
-
}
|
|
3583
|
+
};
|
|
3474
3584
|
getLatestMessageTimestamp(msgChainId) {
|
|
3475
3585
|
if (!this.latestMessages.has(msgChainId) || this.latestMessages.get(msgChainId).length === 0) {
|
|
3476
3586
|
return 0;
|
|
@@ -3480,22 +3590,61 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3480
3590
|
async sendBuffer(fromTimestamp, msgChainId, neighbor) {
|
|
3481
3591
|
const remote = new ContentDeliveryRpcRemote(this.localPeerDescriptor, neighbor, this.rpcCommunicator, ContentDeliveryRpcClient);
|
|
3482
3592
|
const messages = this.latestMessages.get(msgChainId)?.filter((msg) => msg.messageId.timestamp > fromTimestamp) ?? [];
|
|
3483
|
-
|
|
3593
|
+
for (const msg of messages) {
|
|
3594
|
+
await remote.sendStreamMessage(msg);
|
|
3595
|
+
}
|
|
3484
3596
|
}
|
|
3485
3597
|
async onMetadata(msg, previousNode) {
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3598
|
+
const latestTs = this.getLatestMessageTimestamp(msg.messageChainId);
|
|
3599
|
+
if (latestTs >= msg.timestamp) {
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
const chainId = msg.messageChainId;
|
|
3603
|
+
const cooldownUntil = this.recoveryCooldownUntil.get(chainId);
|
|
3604
|
+
if (cooldownUntil !== undefined && performance.now() < cooldownUntil) {
|
|
3605
|
+
return;
|
|
3606
|
+
}
|
|
3607
|
+
let state = this.recoveryState.get(chainId);
|
|
3608
|
+
if (!state) {
|
|
3609
|
+
state = {
|
|
3610
|
+
timestampsAhead: new Set(),
|
|
3611
|
+
metadataAheadSince: performance.now(),
|
|
3612
|
+
candidates: [],
|
|
3613
|
+
lastAttemptedNode: null,
|
|
3614
|
+
resumeInProgress: false
|
|
3615
|
+
};
|
|
3616
|
+
this.recoveryState.set(chainId, state);
|
|
3617
|
+
}
|
|
3618
|
+
state.timestampsAhead.add(msg.timestamp);
|
|
3619
|
+
const nodeId = dht.toNodeId(previousNode);
|
|
3620
|
+
const isLastAttempted = state.lastAttemptedNode !== null && dht.toNodeId(state.lastAttemptedNode) === nodeId;
|
|
3621
|
+
if (!isLastAttempted && !state.candidates.some((c) => dht.toNodeId(c) === nodeId)) {
|
|
3622
|
+
state.candidates.push(previousNode);
|
|
3623
|
+
}
|
|
3624
|
+
if (state.timestampsAhead.size > 1 && !state.resumeInProgress) {
|
|
3625
|
+
await this.attemptRecovery(chainId, state, latestTs);
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
async attemptRecovery(chainId, state, latestTs) {
|
|
3629
|
+
const candidate = state.candidates.shift();
|
|
3630
|
+
if (!candidate) {
|
|
3631
|
+
state.metadataAheadSince = performance.now();
|
|
3632
|
+
return;
|
|
3633
|
+
}
|
|
3634
|
+
state.resumeInProgress = true;
|
|
3635
|
+
state.lastAttemptedNode = candidate;
|
|
3636
|
+
state.candidates = [];
|
|
3637
|
+
state.timestampsAhead.clear();
|
|
3638
|
+
state.metadataAheadSince = performance.now();
|
|
3639
|
+
try {
|
|
3640
|
+
const remote = this.createRemote(candidate);
|
|
3641
|
+
await remote.resumeNeighbor(latestTs, chainId);
|
|
3642
|
+
}
|
|
3643
|
+
catch (_e) {
|
|
3644
|
+
logger$4.debug('Recovery resume failed, will retry with next candidate');
|
|
3645
|
+
}
|
|
3646
|
+
finally {
|
|
3647
|
+
state.resumeInProgress = false;
|
|
3499
3648
|
}
|
|
3500
3649
|
}
|
|
3501
3650
|
createRemote(neighbor) {
|
|
@@ -3513,8 +3662,13 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3513
3662
|
this.latestMessages.get(messageChainId).shift();
|
|
3514
3663
|
this.latestMessages.get(messageChainId).push(msg);
|
|
3515
3664
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3665
|
+
const state = this.recoveryState.get(messageChainId);
|
|
3666
|
+
if (state) {
|
|
3667
|
+
if (state.lastAttemptedNode) {
|
|
3668
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(state.lastAttemptedNode), messageChainId);
|
|
3669
|
+
}
|
|
3670
|
+
this.recoveryState.delete(messageChainId);
|
|
3671
|
+
this.recoveryCooldownUntil.set(messageChainId, performance.now() + this.recoveryCooldown);
|
|
3518
3672
|
}
|
|
3519
3673
|
this.emit('message', msg);
|
|
3520
3674
|
const neighbors = this.neighbors.getAll().filter((neighbor) => dht.toNodeId(neighbor.getPeerDescriptor()) !== previousNode);
|
|
@@ -3532,8 +3686,18 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3532
3686
|
return this.localPausedNeighbors.isPaused(dht.toNodeId(node), msgChainId)
|
|
3533
3687
|
|| this.remotePausedNeighbors.isPaused(dht.toNodeId(node), msgChainId);
|
|
3534
3688
|
}
|
|
3689
|
+
getLocalPausedNeighbors() {
|
|
3690
|
+
return this.localPausedNeighbors;
|
|
3691
|
+
}
|
|
3692
|
+
getRemotePausedNeighbors() {
|
|
3693
|
+
return this.remotePausedNeighbors;
|
|
3694
|
+
}
|
|
3535
3695
|
stop() {
|
|
3696
|
+
this.abortController.abort();
|
|
3536
3697
|
this.neighbors.off('nodeRemoved', this.onNeighborRemoved);
|
|
3698
|
+
this.latestMessages.clear();
|
|
3699
|
+
this.recoveryState.clear();
|
|
3700
|
+
this.recoveryCooldownUntil.clear();
|
|
3537
3701
|
}
|
|
3538
3702
|
}
|
|
3539
3703
|
|
|
@@ -4485,5 +4649,7 @@ exports.NetworkNode = NetworkNode;
|
|
|
4485
4649
|
exports.NetworkStack = NetworkStack;
|
|
4486
4650
|
exports.StreamMessage = StreamMessage;
|
|
4487
4651
|
exports.createNetworkNode = createNetworkNode;
|
|
4652
|
+
exports.logGapDiagnosticSampled = logGapDiagnosticSampled;
|
|
4653
|
+
exports.setTrackerlessGapDiagnosticsEnabled = setGapDiagnosticsEnabled;
|
|
4488
4654
|
exports.streamPartIdToDataKey = streamPartIdToDataKey;
|
|
4489
4655
|
//# sourceMappingURL=exports.cjs.map
|