@streamr/trackerless-network 103.3.1 → 103.6.0-rc.0
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 +131 -36
- package/dist/exports.cjs.map +1 -1
- package/dist/exports.d.ts +23 -1
- package/dist/exports.js +132 -37
- 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.6.0-rc.0";
|
|
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
|
]);
|
|
@@ -3333,14 +3345,17 @@ class PlumtreeRpcLocal {
|
|
|
3333
3345
|
async pauseNeighbor(request, context) {
|
|
3334
3346
|
const sender = dht.toNodeId(context.incomingSourceDescriptor);
|
|
3335
3347
|
if (this.neighbors.has(sender)) {
|
|
3336
|
-
this.pausedNodes.add(sender, request.messageChainId);
|
|
3348
|
+
const accepted = this.pausedNodes.add(sender, request.messageChainId);
|
|
3349
|
+
return { accepted };
|
|
3337
3350
|
}
|
|
3338
|
-
return
|
|
3351
|
+
return { accepted: false };
|
|
3339
3352
|
}
|
|
3340
3353
|
async resumeNeighbor(request, context) {
|
|
3341
3354
|
const sender = context.incomingSourceDescriptor;
|
|
3342
|
-
this.
|
|
3343
|
-
|
|
3355
|
+
if (this.neighbors.has(dht.toNodeId(sender))) {
|
|
3356
|
+
this.pausedNodes.delete(dht.toNodeId(sender), request.messageChainId);
|
|
3357
|
+
await this.sendBuffer(request.fromTimestamp, request.messageChainId, sender);
|
|
3358
|
+
}
|
|
3344
3359
|
return Empty;
|
|
3345
3360
|
}
|
|
3346
3361
|
}
|
|
@@ -3353,10 +3368,9 @@ class PlumtreeRpcRemote extends dht.RpcRemote {
|
|
|
3353
3368
|
await this.getClient().sendMetadata(msg, options);
|
|
3354
3369
|
}
|
|
3355
3370
|
async pauseNeighbor(messageChainId) {
|
|
3356
|
-
const options = this.formDhtRpcOptions(
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
await this.getClient().pauseNeighbor({ messageChainId }, options);
|
|
3371
|
+
const options = this.formDhtRpcOptions();
|
|
3372
|
+
const response = await this.getClient().pauseNeighbor({ messageChainId }, options);
|
|
3373
|
+
return response.accepted;
|
|
3360
3374
|
}
|
|
3361
3375
|
async resumeNeighbor(fromTimestamp, messageChainId) {
|
|
3362
3376
|
const options = this.formDhtRpcOptions({
|
|
@@ -3378,9 +3392,10 @@ class PausedNeighbors {
|
|
|
3378
3392
|
this.pausedNeighbors.set(msgChainId, new Set());
|
|
3379
3393
|
}
|
|
3380
3394
|
if (this.pausedNeighbors.get(msgChainId).size >= this.limit) {
|
|
3381
|
-
return;
|
|
3395
|
+
return false;
|
|
3382
3396
|
}
|
|
3383
3397
|
this.pausedNeighbors.get(msgChainId).add(node);
|
|
3398
|
+
return true;
|
|
3384
3399
|
}
|
|
3385
3400
|
delete(node, msgChainId) {
|
|
3386
3401
|
this.pausedNeighbors.get(msgChainId)?.delete(node);
|
|
@@ -3413,19 +3428,24 @@ class PausedNeighbors {
|
|
|
3413
3428
|
}
|
|
3414
3429
|
|
|
3415
3430
|
const MAX_PAUSED_NEIGHBORS_DEFAULT = 3;
|
|
3431
|
+
const DEFAULT_RECOVERY_TIMEOUT = 500;
|
|
3432
|
+
const DEFAULT_RECOVERY_CHECK_INTERVAL = 200;
|
|
3433
|
+
const DEFAULT_RECOVERY_COOLDOWN = 2500;
|
|
3416
3434
|
const logger$4 = new utils.Logger('PlumtreeManager');
|
|
3417
3435
|
class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
3418
3436
|
neighbors;
|
|
3419
3437
|
localPeerDescriptor;
|
|
3420
|
-
// We have paused sending real data to these neighbrs and only send metadata
|
|
3421
3438
|
localPausedNeighbors;
|
|
3422
|
-
// We have asked these nodes to pause sending real data to us, used to limit sending of pausing and resuming requests
|
|
3423
3439
|
remotePausedNeighbors;
|
|
3424
3440
|
rpcLocal;
|
|
3425
3441
|
latestMessages = new Map();
|
|
3426
3442
|
rpcCommunicator;
|
|
3427
|
-
metadataTimestampsAheadOfRealData = new Map();
|
|
3428
3443
|
maxPausedNeighbors;
|
|
3444
|
+
recoveryState = new Map();
|
|
3445
|
+
recoveryCooldownUntil = new Map();
|
|
3446
|
+
recoveryTimeout;
|
|
3447
|
+
recoveryCooldown;
|
|
3448
|
+
abortController = new AbortController();
|
|
3429
3449
|
constructor(options) {
|
|
3430
3450
|
super();
|
|
3431
3451
|
this.neighbors = options.neighbors;
|
|
@@ -3433,12 +3453,22 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3433
3453
|
this.localPeerDescriptor = options.localPeerDescriptor;
|
|
3434
3454
|
this.localPausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
|
|
3435
3455
|
this.remotePausedNeighbors = new PausedNeighbors(options.maxPausedNeighbors ?? MAX_PAUSED_NEIGHBORS_DEFAULT);
|
|
3456
|
+
this.recoveryTimeout = options.recoveryTimeout ?? DEFAULT_RECOVERY_TIMEOUT;
|
|
3457
|
+
this.recoveryCooldown = options.recoveryCooldown ?? DEFAULT_RECOVERY_COOLDOWN;
|
|
3436
3458
|
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',
|
|
3459
|
+
this.neighbors.on('nodeRemoved', this.onNeighborRemoved);
|
|
3438
3460
|
this.rpcCommunicator = options.rpcCommunicator;
|
|
3439
3461
|
this.rpcCommunicator.registerRpcNotification(MessageID, 'sendMetadata', (msg, context) => this.rpcLocal.sendMetadata(msg, context));
|
|
3440
|
-
this.rpcCommunicator.
|
|
3462
|
+
this.rpcCommunicator.registerRpcMethod(PauseNeighborRequest, PauseNeighborResponse, 'pauseNeighbor', (msg, context) => this.rpcLocal.pauseNeighbor(msg, context));
|
|
3441
3463
|
this.rpcCommunicator.registerRpcNotification(ResumeNeighborRequest, 'resumeNeighbor', (msg, context) => this.rpcLocal.resumeNeighbor(msg, context));
|
|
3464
|
+
utils.setAbortableInterval(() => {
|
|
3465
|
+
const now = performance.now();
|
|
3466
|
+
for (const [chainId, state] of this.recoveryState) {
|
|
3467
|
+
if (now - state.metadataAheadSince >= this.recoveryTimeout && !state.resumeInProgress) {
|
|
3468
|
+
this.attemptRecovery(chainId, state, this.getLatestMessageTimestamp(chainId));
|
|
3469
|
+
}
|
|
3470
|
+
}
|
|
3471
|
+
}, options.recoveryCheckInterval ?? DEFAULT_RECOVERY_CHECK_INTERVAL, this.abortController.signal);
|
|
3442
3472
|
}
|
|
3443
3473
|
async pauseNeighbor(node, msgChainId) {
|
|
3444
3474
|
if (this.neighbors.has(dht.toNodeId(node))
|
|
@@ -3446,8 +3476,16 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3446
3476
|
&& this.remotePausedNeighbors.size(msgChainId) < this.maxPausedNeighbors) {
|
|
3447
3477
|
logger$4.debug(`Pausing neighbor ${dht.toNodeId(node)}`);
|
|
3448
3478
|
this.remotePausedNeighbors.add(dht.toNodeId(node), msgChainId);
|
|
3449
|
-
|
|
3450
|
-
|
|
3479
|
+
try {
|
|
3480
|
+
const remote = this.createRemote(node);
|
|
3481
|
+
const accepted = await remote.pauseNeighbor(msgChainId);
|
|
3482
|
+
if (!accepted) {
|
|
3483
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(node), msgChainId);
|
|
3484
|
+
}
|
|
3485
|
+
}
|
|
3486
|
+
catch (_e) {
|
|
3487
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(node), msgChainId);
|
|
3488
|
+
}
|
|
3451
3489
|
}
|
|
3452
3490
|
}
|
|
3453
3491
|
async resumeNeighbor(node, msgChainId, fromTimestamp) {
|
|
@@ -3458,9 +3496,15 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3458
3496
|
await remote.resumeNeighbor(fromTimestamp, msgChainId);
|
|
3459
3497
|
}
|
|
3460
3498
|
}
|
|
3461
|
-
onNeighborRemoved(nodeId) {
|
|
3499
|
+
onNeighborRemoved = (nodeId) => {
|
|
3462
3500
|
this.localPausedNeighbors.deleteAll(nodeId);
|
|
3463
3501
|
this.remotePausedNeighbors.deleteAll(nodeId);
|
|
3502
|
+
for (const [_chainId, state] of this.recoveryState) {
|
|
3503
|
+
state.candidates = state.candidates.filter((c) => dht.toNodeId(c) !== nodeId);
|
|
3504
|
+
if (state.lastAttemptedNode !== null && dht.toNodeId(state.lastAttemptedNode) === nodeId) {
|
|
3505
|
+
state.lastAttemptedNode = null;
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3464
3508
|
if (this.neighbors.size() > 0) {
|
|
3465
3509
|
this.remotePausedNeighbors.forEach((pausedNeighbors, msgChainId) => {
|
|
3466
3510
|
if (pausedNeighbors.size >= this.neighbors.size()) {
|
|
@@ -3470,7 +3514,7 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3470
3514
|
}
|
|
3471
3515
|
});
|
|
3472
3516
|
}
|
|
3473
|
-
}
|
|
3517
|
+
};
|
|
3474
3518
|
getLatestMessageTimestamp(msgChainId) {
|
|
3475
3519
|
if (!this.latestMessages.has(msgChainId) || this.latestMessages.get(msgChainId).length === 0) {
|
|
3476
3520
|
return 0;
|
|
@@ -3480,22 +3524,61 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3480
3524
|
async sendBuffer(fromTimestamp, msgChainId, neighbor) {
|
|
3481
3525
|
const remote = new ContentDeliveryRpcRemote(this.localPeerDescriptor, neighbor, this.rpcCommunicator, ContentDeliveryRpcClient);
|
|
3482
3526
|
const messages = this.latestMessages.get(msgChainId)?.filter((msg) => msg.messageId.timestamp > fromTimestamp) ?? [];
|
|
3483
|
-
|
|
3527
|
+
for (const msg of messages) {
|
|
3528
|
+
await remote.sendStreamMessage(msg);
|
|
3529
|
+
}
|
|
3484
3530
|
}
|
|
3485
3531
|
async onMetadata(msg, previousNode) {
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3532
|
+
const latestTs = this.getLatestMessageTimestamp(msg.messageChainId);
|
|
3533
|
+
if (latestTs >= msg.timestamp) {
|
|
3534
|
+
return;
|
|
3535
|
+
}
|
|
3536
|
+
const chainId = msg.messageChainId;
|
|
3537
|
+
const cooldownUntil = this.recoveryCooldownUntil.get(chainId);
|
|
3538
|
+
if (cooldownUntil !== undefined && performance.now() < cooldownUntil) {
|
|
3539
|
+
return;
|
|
3540
|
+
}
|
|
3541
|
+
let state = this.recoveryState.get(chainId);
|
|
3542
|
+
if (!state) {
|
|
3543
|
+
state = {
|
|
3544
|
+
timestampsAhead: new Set(),
|
|
3545
|
+
metadataAheadSince: performance.now(),
|
|
3546
|
+
candidates: [],
|
|
3547
|
+
lastAttemptedNode: null,
|
|
3548
|
+
resumeInProgress: false
|
|
3549
|
+
};
|
|
3550
|
+
this.recoveryState.set(chainId, state);
|
|
3551
|
+
}
|
|
3552
|
+
state.timestampsAhead.add(msg.timestamp);
|
|
3553
|
+
const nodeId = dht.toNodeId(previousNode);
|
|
3554
|
+
const isLastAttempted = state.lastAttemptedNode !== null && dht.toNodeId(state.lastAttemptedNode) === nodeId;
|
|
3555
|
+
if (!isLastAttempted && !state.candidates.some((c) => dht.toNodeId(c) === nodeId)) {
|
|
3556
|
+
state.candidates.push(previousNode);
|
|
3557
|
+
}
|
|
3558
|
+
if (state.timestampsAhead.size > 1 && !state.resumeInProgress) {
|
|
3559
|
+
await this.attemptRecovery(chainId, state, latestTs);
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
async attemptRecovery(chainId, state, latestTs) {
|
|
3563
|
+
const candidate = state.candidates.shift();
|
|
3564
|
+
if (!candidate) {
|
|
3565
|
+
state.metadataAheadSince = performance.now();
|
|
3566
|
+
return;
|
|
3567
|
+
}
|
|
3568
|
+
state.resumeInProgress = true;
|
|
3569
|
+
state.lastAttemptedNode = candidate;
|
|
3570
|
+
state.candidates = [];
|
|
3571
|
+
state.timestampsAhead.clear();
|
|
3572
|
+
state.metadataAheadSince = performance.now();
|
|
3573
|
+
try {
|
|
3574
|
+
const remote = this.createRemote(candidate);
|
|
3575
|
+
await remote.resumeNeighbor(latestTs, chainId);
|
|
3576
|
+
}
|
|
3577
|
+
catch (_e) {
|
|
3578
|
+
logger$4.debug('Recovery resume failed, will retry with next candidate');
|
|
3579
|
+
}
|
|
3580
|
+
finally {
|
|
3581
|
+
state.resumeInProgress = false;
|
|
3499
3582
|
}
|
|
3500
3583
|
}
|
|
3501
3584
|
createRemote(neighbor) {
|
|
@@ -3513,8 +3596,13 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3513
3596
|
this.latestMessages.get(messageChainId).shift();
|
|
3514
3597
|
this.latestMessages.get(messageChainId).push(msg);
|
|
3515
3598
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3599
|
+
const state = this.recoveryState.get(messageChainId);
|
|
3600
|
+
if (state) {
|
|
3601
|
+
if (state.lastAttemptedNode) {
|
|
3602
|
+
this.remotePausedNeighbors.delete(dht.toNodeId(state.lastAttemptedNode), messageChainId);
|
|
3603
|
+
}
|
|
3604
|
+
this.recoveryState.delete(messageChainId);
|
|
3605
|
+
this.recoveryCooldownUntil.set(messageChainId, performance.now() + this.recoveryCooldown);
|
|
3518
3606
|
}
|
|
3519
3607
|
this.emit('message', msg);
|
|
3520
3608
|
const neighbors = this.neighbors.getAll().filter((neighbor) => dht.toNodeId(neighbor.getPeerDescriptor()) !== previousNode);
|
|
@@ -3532,7 +3620,14 @@ class PlumtreeManager extends eventemitter3.EventEmitter {
|
|
|
3532
3620
|
return this.localPausedNeighbors.isPaused(dht.toNodeId(node), msgChainId)
|
|
3533
3621
|
|| this.remotePausedNeighbors.isPaused(dht.toNodeId(node), msgChainId);
|
|
3534
3622
|
}
|
|
3623
|
+
getLocalPausedNeighbors() {
|
|
3624
|
+
return this.localPausedNeighbors;
|
|
3625
|
+
}
|
|
3626
|
+
getRemotePausedNeighbors() {
|
|
3627
|
+
return this.remotePausedNeighbors;
|
|
3628
|
+
}
|
|
3535
3629
|
stop() {
|
|
3630
|
+
this.abortController.abort();
|
|
3536
3631
|
this.neighbors.off('nodeRemoved', this.onNeighborRemoved);
|
|
3537
3632
|
}
|
|
3538
3633
|
}
|