@peerbit/pubsub 5.4.6 → 5.4.8
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/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +131 -30
- package/dist/src/index.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +165 -36
package/src/index.ts
CHANGED
|
@@ -397,6 +397,7 @@ export class TopicControlPlane
|
|
|
397
397
|
{
|
|
398
398
|
targets: Set<string>;
|
|
399
399
|
topics: Set<string>;
|
|
400
|
+
isCurrent: () => boolean;
|
|
400
401
|
timer: ReturnType<typeof setTimeout>;
|
|
401
402
|
}
|
|
402
403
|
> = new Map();
|
|
@@ -416,8 +417,9 @@ export class TopicControlPlane
|
|
|
416
417
|
// default) leaves every code path as-is.
|
|
417
418
|
private readonly nativeTopicControl?: RustTopicControl;
|
|
418
419
|
|
|
419
|
-
private debounceSubscribeAggregator
|
|
420
|
-
private debounceUnsubscribeAggregator
|
|
420
|
+
private debounceSubscribeAggregator!: DebouncedAccumulatorCounterMap;
|
|
421
|
+
private debounceUnsubscribeAggregator!: DebouncedAccumulatorCounterMap;
|
|
422
|
+
private readonly subscriptionDebounceDelay: number;
|
|
421
423
|
|
|
422
424
|
private readonly shardCount: number;
|
|
423
425
|
private readonly shardTopicPrefix: string;
|
|
@@ -636,17 +638,23 @@ export class TopicControlPlane
|
|
|
636
638
|
Math.max(1, Math.floor(requestedSubscriberCacheMaxEntries)),
|
|
637
639
|
);
|
|
638
640
|
|
|
641
|
+
this.subscriptionDebounceDelay = props?.subscriptionDebounceDelay ?? 50;
|
|
642
|
+
this.createSubscriptionAggregators();
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private createSubscriptionAggregators(): void {
|
|
646
|
+
const lifecycleRevision = this.topicControlPlaneLifecycleRevision;
|
|
639
647
|
this.debounceSubscribeAggregator = debouncedAccumulatorSetCounter(
|
|
640
|
-
(set) => this._subscribe([...set.values()]),
|
|
641
|
-
|
|
648
|
+
(set) => this._subscribe([...set.values()], lifecycleRevision),
|
|
649
|
+
this.subscriptionDebounceDelay,
|
|
642
650
|
(error) =>
|
|
643
651
|
logger.error(`Debounced subscribe failed: ${error?.message ?? error}`),
|
|
644
652
|
);
|
|
645
653
|
// NOTE: Unsubscribe should update local state immediately and batch only the
|
|
646
654
|
// best-effort network announcements to avoid teardown stalls (program close).
|
|
647
655
|
this.debounceUnsubscribeAggregator = debouncedAccumulatorSetCounter(
|
|
648
|
-
(set) => this._announceUnsubscribe([...set.values()]),
|
|
649
|
-
|
|
656
|
+
(set) => this._announceUnsubscribe([...set.values()], lifecycleRevision),
|
|
657
|
+
this.subscriptionDebounceDelay,
|
|
650
658
|
(error) =>
|
|
651
659
|
logger.error(
|
|
652
660
|
`Debounced unsubscribe announce failed: ${error?.message ?? error}`,
|
|
@@ -712,6 +720,9 @@ export class TopicControlPlane
|
|
|
712
720
|
// candidates. In particular, a repeated start must not restore unsigned
|
|
713
721
|
// self while a signed-protocol peer is connected.
|
|
714
722
|
if (this.started) return;
|
|
723
|
+
// close() is terminal. Only a completed stop/start gets a fresh pair;
|
|
724
|
+
// repeated start() must preserve the active pair's queued reference counts.
|
|
725
|
+
if (this.topicControlPlaneStopping) this.createSubscriptionAggregators();
|
|
715
726
|
this.topicControlPlaneStopping = false;
|
|
716
727
|
if (
|
|
717
728
|
this.autoTopicRootCandidates &&
|
|
@@ -764,6 +775,8 @@ export class TopicControlPlane
|
|
|
764
775
|
this.clearAutoTopicRootCandidateUpdateSchedule();
|
|
765
776
|
this.clearSignedTopicRootCandidateState();
|
|
766
777
|
this.topicControlPlaneLifecycleRevision += 1;
|
|
778
|
+
this.debounceSubscribeAggregator.close();
|
|
779
|
+
this.debounceUnsubscribeAggregator.close();
|
|
767
780
|
this.reconcileShardOverlaysDirty = false;
|
|
768
781
|
for (const opening of this.ensureFanoutChannelInFlight.values()) {
|
|
769
782
|
opening.abortController.abort(
|
|
@@ -822,8 +835,6 @@ export class TopicControlPlane
|
|
|
822
835
|
}
|
|
823
836
|
this.pendingTopicRootQueries.clear();
|
|
824
837
|
|
|
825
|
-
this.debounceSubscribeAggregator.close();
|
|
826
|
-
this.debounceUnsubscribeAggregator.close();
|
|
827
838
|
await super.stop();
|
|
828
839
|
this.reconcileShardOverlaysDirty = false;
|
|
829
840
|
}
|
|
@@ -2062,17 +2073,32 @@ export class TopicControlPlane
|
|
|
2062
2073
|
]);
|
|
2063
2074
|
}
|
|
2064
2075
|
|
|
2076
|
+
private isTopicControlPlaneActive(lifecycleRevision: number): boolean {
|
|
2077
|
+
return (
|
|
2078
|
+
lifecycleRevision === this.topicControlPlaneLifecycleRevision &&
|
|
2079
|
+
this.started &&
|
|
2080
|
+
!this.stopping &&
|
|
2081
|
+
!this.topicControlPlaneStopping
|
|
2082
|
+
);
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2065
2085
|
private assertTopicControlPlaneActive(lifecycleRevision: number): void {
|
|
2066
|
-
if (
|
|
2067
|
-
lifecycleRevision !== this.topicControlPlaneLifecycleRevision ||
|
|
2068
|
-
!this.started ||
|
|
2069
|
-
this.stopping ||
|
|
2070
|
-
this.topicControlPlaneStopping
|
|
2071
|
-
) {
|
|
2086
|
+
if (!this.isTopicControlPlaneActive(lifecycleRevision)) {
|
|
2072
2087
|
throw new NotStartedError();
|
|
2073
2088
|
}
|
|
2074
2089
|
}
|
|
2075
2090
|
|
|
2091
|
+
private isFanoutChannelCurrent(
|
|
2092
|
+
shardTopic: string,
|
|
2093
|
+
channel: FanoutChannel,
|
|
2094
|
+
lifecycleRevision: number,
|
|
2095
|
+
): boolean {
|
|
2096
|
+
return (
|
|
2097
|
+
this.isTopicControlPlaneActive(lifecycleRevision) &&
|
|
2098
|
+
this.fanoutChannels.get(shardTopic)?.channel === channel
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2076
2102
|
private syncTopicRootCandidateResolutionSignal(
|
|
2077
2103
|
candidateGeneration = this.getTopicRootCandidateGeneration(),
|
|
2078
2104
|
): AbortSignal {
|
|
@@ -2851,8 +2877,11 @@ export class TopicControlPlane
|
|
|
2851
2877
|
return;
|
|
2852
2878
|
}
|
|
2853
2879
|
const channel = new FanoutChannel(this.fanout, { topic: t, root });
|
|
2880
|
+
const isCurrent = () =>
|
|
2881
|
+
this.isFanoutChannelCurrent(t, channel, lifecycleRevision);
|
|
2854
2882
|
|
|
2855
2883
|
const onPayload = (payload: Uint8Array) => {
|
|
2884
|
+
if (!isCurrent()) return;
|
|
2856
2885
|
let dm: DataMessage;
|
|
2857
2886
|
try {
|
|
2858
2887
|
dm = DataMessage.from(new Uint8ArrayList(payload));
|
|
@@ -2912,24 +2941,38 @@ export class TopicControlPlane
|
|
|
2912
2941
|
|
|
2913
2942
|
void (async () => {
|
|
2914
2943
|
const msgId = await getMsgId(payload);
|
|
2915
|
-
|
|
2916
|
-
this.seenCache.
|
|
2917
|
-
if (
|
|
2944
|
+
if (!isCurrent()) return;
|
|
2945
|
+
const previouslySeen = this.seenCache.get(msgId);
|
|
2946
|
+
if (previouslySeen) {
|
|
2947
|
+
this.seenCache.add(msgId, previouslySeen + 1);
|
|
2948
|
+
return;
|
|
2949
|
+
}
|
|
2918
2950
|
|
|
2919
2951
|
// fanout-delivered frames bypass the inbound stream decode, so
|
|
2920
2952
|
// the nested envelope is verified natively here when possible
|
|
2921
2953
|
this.seedNativeWireVerification(dm, payload);
|
|
2922
|
-
if ((await this.verifyAndProcess(dm)) === false) {
|
|
2954
|
+
if ((await this.verifyAndProcess(dm, isCurrent)) === false) {
|
|
2923
2955
|
return;
|
|
2924
2956
|
}
|
|
2957
|
+
if (!isCurrent()) return;
|
|
2958
|
+
// Only a verified frame owned by this exact channel may consume the
|
|
2959
|
+
// shared dedupe slot. A stale verifier cannot suppress its replacement's
|
|
2960
|
+
// copy. Concurrent verifiers recheck here before dispatching once.
|
|
2961
|
+
const seen = this.seenCache.get(msgId);
|
|
2962
|
+
this.seenCache.add(msgId, seen ? seen + 1 : 1);
|
|
2963
|
+
if (seen) return;
|
|
2925
2964
|
const sender = dm.header.signatures!.signatures[0]!.publicKey!;
|
|
2926
2965
|
await this.processShardPubSubMessage({
|
|
2927
2966
|
pubsubMessage,
|
|
2928
2967
|
message: dm,
|
|
2929
2968
|
from: sender,
|
|
2930
2969
|
shardTopic: t,
|
|
2970
|
+
isCurrent,
|
|
2931
2971
|
});
|
|
2932
|
-
})()
|
|
2972
|
+
})().catch((error) => {
|
|
2973
|
+
if (error instanceof NotStartedError && !isCurrent()) return;
|
|
2974
|
+
logError(error);
|
|
2975
|
+
});
|
|
2933
2976
|
};
|
|
2934
2977
|
|
|
2935
2978
|
const onData = (ev?: CustomEvent<FanoutTreeDataEvent>) => {
|
|
@@ -3035,6 +3078,11 @@ export class TopicControlPlane
|
|
|
3035
3078
|
if (!st) return;
|
|
3036
3079
|
this.fanoutChannels.delete(t);
|
|
3037
3080
|
this.clearFanoutIdleClose(st);
|
|
3081
|
+
const pendingResponse = this.pendingSubscriberResponses.get(t);
|
|
3082
|
+
if (pendingResponse) {
|
|
3083
|
+
clearTimeout(pendingResponse.timer);
|
|
3084
|
+
this.pendingSubscriberResponses.delete(t);
|
|
3085
|
+
}
|
|
3038
3086
|
try {
|
|
3039
3087
|
st.channel.removeEventListener("data", st.onData as any);
|
|
3040
3088
|
} catch {
|
|
@@ -3149,8 +3197,12 @@ export class TopicControlPlane
|
|
|
3149
3197
|
return this.debounceSubscribeAggregator.add({ key: topic });
|
|
3150
3198
|
}
|
|
3151
3199
|
|
|
3152
|
-
private async _subscribe(
|
|
3200
|
+
private async _subscribe(
|
|
3201
|
+
topics: { key: string; counter: number }[],
|
|
3202
|
+
lifecycleRevision = this.topicControlPlaneLifecycleRevision,
|
|
3203
|
+
) {
|
|
3153
3204
|
if (!this.started) throw new NotStartedError();
|
|
3205
|
+
if (!this.isTopicControlPlaneActive(lifecycleRevision)) return;
|
|
3154
3206
|
if (topics.length === 0) return;
|
|
3155
3207
|
|
|
3156
3208
|
const byShard = new Map<string, string[]>();
|
|
@@ -3176,11 +3228,15 @@ export class TopicControlPlane
|
|
|
3176
3228
|
}
|
|
3177
3229
|
|
|
3178
3230
|
await Promise.all(joins);
|
|
3231
|
+
if (!this.isTopicControlPlaneActive(lifecycleRevision)) return;
|
|
3179
3232
|
|
|
3180
3233
|
// Announce subscriptions per shard overlay.
|
|
3181
3234
|
await Promise.all(
|
|
3182
3235
|
[...byShard.entries()].map(async ([shardTopic, userTopics]) => {
|
|
3183
3236
|
if (userTopics.length === 0) return;
|
|
3237
|
+
const st = this.fanoutChannels.get(shardTopic);
|
|
3238
|
+
if (!st)
|
|
3239
|
+
throw new Error(`Fanout channel missing for shard: ${shardTopic}`);
|
|
3184
3240
|
const msg = new Subscribe({
|
|
3185
3241
|
topics: userTopics,
|
|
3186
3242
|
requestSubscribers: true,
|
|
@@ -3193,11 +3249,19 @@ export class TopicControlPlane
|
|
|
3193
3249
|
skipRecipientValidation: true,
|
|
3194
3250
|
} as any,
|
|
3195
3251
|
);
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3252
|
+
if (
|
|
3253
|
+
!this.isFanoutChannelCurrent(
|
|
3254
|
+
shardTopic,
|
|
3255
|
+
st.channel,
|
|
3256
|
+
lifecycleRevision,
|
|
3257
|
+
)
|
|
3258
|
+
)
|
|
3259
|
+
return;
|
|
3199
3260
|
await st.channel.publish(toUint8Array(embedded.bytes()));
|
|
3200
|
-
|
|
3261
|
+
if (
|
|
3262
|
+
this.isFanoutChannelCurrent(shardTopic, st.channel, lifecycleRevision)
|
|
3263
|
+
)
|
|
3264
|
+
this.touchFanoutChannel(shardTopic);
|
|
3201
3265
|
}),
|
|
3202
3266
|
);
|
|
3203
3267
|
}
|
|
@@ -3253,8 +3317,10 @@ export class TopicControlPlane
|
|
|
3253
3317
|
|
|
3254
3318
|
private async _announceUnsubscribe(
|
|
3255
3319
|
topics: { key: string; counter: number }[],
|
|
3320
|
+
lifecycleRevision = this.topicControlPlaneLifecycleRevision,
|
|
3256
3321
|
) {
|
|
3257
3322
|
if (!this.started) throw new NotStartedError();
|
|
3323
|
+
if (!this.isTopicControlPlaneActive(lifecycleRevision)) return;
|
|
3258
3324
|
|
|
3259
3325
|
const byShard = new Map<string, string[]>();
|
|
3260
3326
|
for (const { key: topic } of topics) {
|
|
@@ -3267,6 +3333,8 @@ export class TopicControlPlane
|
|
|
3267
3333
|
await Promise.all(
|
|
3268
3334
|
[...byShard.entries()].map(async ([shardTopic, userTopics]) => {
|
|
3269
3335
|
if (userTopics.length === 0) return;
|
|
3336
|
+
const st = this.fanoutChannels.get(shardTopic);
|
|
3337
|
+
if (!st) return;
|
|
3270
3338
|
|
|
3271
3339
|
// Announce first.
|
|
3272
3340
|
try {
|
|
@@ -3279,20 +3347,39 @@ export class TopicControlPlane
|
|
|
3279
3347
|
skipRecipientValidation: true,
|
|
3280
3348
|
} as any,
|
|
3281
3349
|
);
|
|
3282
|
-
|
|
3283
|
-
|
|
3350
|
+
if (
|
|
3351
|
+
this.isFanoutChannelCurrent(
|
|
3352
|
+
shardTopic,
|
|
3353
|
+
st.channel,
|
|
3354
|
+
lifecycleRevision,
|
|
3355
|
+
)
|
|
3356
|
+
) {
|
|
3284
3357
|
// Best-effort: do not let a stuck proxy publish stall teardown.
|
|
3285
3358
|
void st.channel
|
|
3286
3359
|
.publish(toUint8Array(embedded.bytes()))
|
|
3287
3360
|
.catch(() => {});
|
|
3288
|
-
|
|
3361
|
+
if (
|
|
3362
|
+
this.isFanoutChannelCurrent(
|
|
3363
|
+
shardTopic,
|
|
3364
|
+
st.channel,
|
|
3365
|
+
lifecycleRevision,
|
|
3366
|
+
)
|
|
3367
|
+
)
|
|
3368
|
+
this.touchFanoutChannel(shardTopic);
|
|
3289
3369
|
}
|
|
3290
3370
|
} catch {
|
|
3291
3371
|
// best-effort
|
|
3292
3372
|
}
|
|
3293
3373
|
|
|
3294
3374
|
// Close shard overlay if no local topics remain.
|
|
3295
|
-
if (
|
|
3375
|
+
if (
|
|
3376
|
+
this.isFanoutChannelCurrent(
|
|
3377
|
+
shardTopic,
|
|
3378
|
+
st.channel,
|
|
3379
|
+
lifecycleRevision,
|
|
3380
|
+
) &&
|
|
3381
|
+
(this.shardRefCounts.get(shardTopic) ?? 0) <= 0
|
|
3382
|
+
) {
|
|
3296
3383
|
try {
|
|
3297
3384
|
// Shutdown should be bounded and not depend on network I/O.
|
|
3298
3385
|
await this.closeFanoutChannel(shardTopic);
|
|
@@ -3955,17 +4042,36 @@ export class TopicControlPlane
|
|
|
3955
4042
|
targetHash: string,
|
|
3956
4043
|
topics: string[],
|
|
3957
4044
|
) {
|
|
4045
|
+
const lifecycleRevision = this.topicControlPlaneLifecycleRevision;
|
|
4046
|
+
const st = this.fanoutChannels.get(shardTopic);
|
|
4047
|
+
if (!st) return;
|
|
4048
|
+
const isCurrent = () =>
|
|
4049
|
+
this.isFanoutChannelCurrent(shardTopic, st.channel, lifecycleRevision);
|
|
4050
|
+
if (!isCurrent()) return;
|
|
4051
|
+
const onError = (error: Error) => {
|
|
4052
|
+
if (error instanceof NotStartedError && !isCurrent()) return;
|
|
4053
|
+
logError(error);
|
|
4054
|
+
};
|
|
3958
4055
|
let entry = this.pendingSubscriberResponses.get(shardTopic);
|
|
4056
|
+
if (entry && !entry.isCurrent()) {
|
|
4057
|
+
clearTimeout(entry.timer);
|
|
4058
|
+
this.pendingSubscriberResponses.delete(shardTopic);
|
|
4059
|
+
entry = undefined;
|
|
4060
|
+
}
|
|
3959
4061
|
if (!entry) {
|
|
3960
4062
|
const created = {
|
|
3961
4063
|
targets: new Set<string>(),
|
|
3962
4064
|
topics: new Set<string>(),
|
|
4065
|
+
isCurrent,
|
|
3963
4066
|
timer: setTimeout(
|
|
3964
4067
|
() => {
|
|
4068
|
+
if (this.pendingSubscriberResponses.get(shardTopic) !== created) {
|
|
4069
|
+
return;
|
|
4070
|
+
}
|
|
3965
4071
|
this.pendingSubscriberResponses.delete(shardTopic);
|
|
3966
|
-
if (created.targets.size === 0) return;
|
|
4072
|
+
if (!isCurrent() || created.targets.size === 0) return;
|
|
3967
4073
|
void this.flushSubscriberResponses(shardTopic, created).catch(
|
|
3968
|
-
|
|
4074
|
+
onError,
|
|
3969
4075
|
);
|
|
3970
4076
|
},
|
|
3971
4077
|
150 + Math.floor(Math.random() * 150),
|
|
@@ -3976,7 +4082,8 @@ export class TopicControlPlane
|
|
|
3976
4082
|
void this.flushSubscriberResponses(shardTopic, {
|
|
3977
4083
|
targets: new Set([targetHash]),
|
|
3978
4084
|
topics: new Set(topics),
|
|
3979
|
-
|
|
4085
|
+
isCurrent,
|
|
4086
|
+
}).catch(onError);
|
|
3980
4087
|
return;
|
|
3981
4088
|
}
|
|
3982
4089
|
entry.targets.add(targetHash);
|
|
@@ -3985,9 +4092,13 @@ export class TopicControlPlane
|
|
|
3985
4092
|
|
|
3986
4093
|
private async flushSubscriberResponses(
|
|
3987
4094
|
shardTopic: string,
|
|
3988
|
-
entry: {
|
|
4095
|
+
entry: {
|
|
4096
|
+
targets: Set<string>;
|
|
4097
|
+
topics: Set<string>;
|
|
4098
|
+
isCurrent: () => boolean;
|
|
4099
|
+
},
|
|
3989
4100
|
) {
|
|
3990
|
-
if (!
|
|
4101
|
+
if (!entry.isCurrent()) return;
|
|
3991
4102
|
// Re-filter: our subscriptions may have changed within the window.
|
|
3992
4103
|
const topics = this.getSubscriptionOverlap([...entry.topics]);
|
|
3993
4104
|
if (topics.length === 0) return;
|
|
@@ -4003,6 +4114,7 @@ export class TopicControlPlane
|
|
|
4003
4114
|
skipRecipientValidation: true,
|
|
4004
4115
|
} as any,
|
|
4005
4116
|
);
|
|
4117
|
+
if (!entry.isCurrent()) return;
|
|
4006
4118
|
const payload = toUint8Array(embedded.bytes());
|
|
4007
4119
|
const [firstTarget] = entry.targets;
|
|
4008
4120
|
if (entry.targets.size === 1 && firstTarget) {
|
|
@@ -4019,8 +4131,12 @@ export class TopicControlPlane
|
|
|
4019
4131
|
targetHash: string,
|
|
4020
4132
|
payload: Uint8Array,
|
|
4021
4133
|
) {
|
|
4134
|
+
const lifecycleRevision = this.topicControlPlaneLifecycleRevision;
|
|
4022
4135
|
const st = this.fanoutChannels.get(shardTopic);
|
|
4023
4136
|
if (!st) return;
|
|
4137
|
+
const isCurrent = () =>
|
|
4138
|
+
this.isFanoutChannelCurrent(shardTopic, st.channel, lifecycleRevision);
|
|
4139
|
+
if (!isCurrent()) return;
|
|
4024
4140
|
const hints = this.getUnifiedRouteHints(shardTopic, targetHash);
|
|
4025
4141
|
const fanoutHint = hints.find(
|
|
4026
4142
|
(hint): hint is Extract<RouteHint, { kind: "fanout-token" }> =>
|
|
@@ -4032,16 +4148,25 @@ export class TopicControlPlane
|
|
|
4032
4148
|
timeoutMs: 5_000,
|
|
4033
4149
|
});
|
|
4034
4150
|
return;
|
|
4035
|
-
} catch {
|
|
4151
|
+
} catch (error) {
|
|
4152
|
+
if (!isCurrent()) {
|
|
4153
|
+
if (error instanceof NotStartedError) return;
|
|
4154
|
+
throw error;
|
|
4155
|
+
}
|
|
4036
4156
|
// ignore and fall back
|
|
4037
4157
|
}
|
|
4038
4158
|
}
|
|
4039
4159
|
try {
|
|
4040
4160
|
await st.channel.unicastToAck(targetHash, payload, { timeoutMs: 5_000 });
|
|
4041
4161
|
return;
|
|
4042
|
-
} catch {
|
|
4162
|
+
} catch (error) {
|
|
4163
|
+
if (!isCurrent()) {
|
|
4164
|
+
if (error instanceof NotStartedError) return;
|
|
4165
|
+
throw error;
|
|
4166
|
+
}
|
|
4043
4167
|
// ignore and fall back
|
|
4044
4168
|
}
|
|
4169
|
+
if (!isCurrent()) return;
|
|
4045
4170
|
await st.channel.publishMaybe(payload);
|
|
4046
4171
|
}
|
|
4047
4172
|
|
|
@@ -4227,8 +4352,10 @@ export class TopicControlPlane
|
|
|
4227
4352
|
message: DataMessage;
|
|
4228
4353
|
from: PublicSignKey;
|
|
4229
4354
|
shardTopic: string;
|
|
4355
|
+
isCurrent?: () => boolean;
|
|
4230
4356
|
}): Promise<void> {
|
|
4231
|
-
const { pubsubMessage, message, from, shardTopic } = input;
|
|
4357
|
+
const { pubsubMessage, message, from, shardTopic, isCurrent } = input;
|
|
4358
|
+
if (isCurrent?.() === false) return;
|
|
4232
4359
|
|
|
4233
4360
|
if (pubsubMessage instanceof PubSubData) {
|
|
4234
4361
|
this.dispatchEvent(
|
|
@@ -4295,6 +4422,7 @@ export class TopicControlPlane
|
|
|
4295
4422
|
}
|
|
4296
4423
|
}
|
|
4297
4424
|
|
|
4425
|
+
if (isCurrent?.() === false) return;
|
|
4298
4426
|
if (pubsubMessage.requestSubscribers) {
|
|
4299
4427
|
const overlap = this.getSubscriptionOverlap(pubsubMessage.topics);
|
|
4300
4428
|
if (overlap.length > 0) {
|
|
@@ -4425,6 +4553,7 @@ export class TopicControlPlane
|
|
|
4425
4553
|
} as any,
|
|
4426
4554
|
);
|
|
4427
4555
|
const payload = toUint8Array(embedded.bytes());
|
|
4556
|
+
if (isCurrent?.() === false) return;
|
|
4428
4557
|
await this.sendFanoutUnicastOrBroadcast(shardTopic, senderKey, payload);
|
|
4429
4558
|
return;
|
|
4430
4559
|
}
|