@agentunion/fastaun 0.5.9 → 0.5.10
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/CHANGELOG.md +32 -0
- package/_packed_docs/CHANGELOG.md +32 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +6 -5
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +43 -8
- package/_packed_docs/sdk/09-group-rpc-manual.md +18 -3
- package/_packed_docs/sdk/09-message-rpc-manual.md +34 -10
- package/dist/agent-md.js +5 -1
- package/dist/agent-md.js.map +1 -1
- package/dist/auth.d.ts +2 -1
- package/dist/auth.js +30 -44
- package/dist/auth.js.map +1 -1
- package/dist/client/delivery.d.ts +21 -5
- package/dist/client/delivery.js +236 -52
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +6 -6
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.js +5 -14
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +4 -0
- package/dist/client/rpc-pipeline.js +33 -1
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -0
- package/dist/client/v2-e2ee.js +43 -17
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.js +21 -27
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +23 -8
- package/dist/events.js +120 -26
- package/dist/events.js.map +1 -1
- package/dist/register-flow.js +15 -111
- package/dist/register-flow.js.map +1 -1
- package/dist/transport.d.ts +32 -3
- package/dist/transport.js +758 -33
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
package/dist/client/delivery.js
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
import { slotIsolationKey } from '../config.js';
|
|
2
2
|
import { ConnectionState, isJsonObject } from '../types.js';
|
|
3
|
+
import { validateGroupAIDFormat } from '../validators.js';
|
|
3
4
|
import { hasGroupMentionModeField, normalizeGroupMentionMode } from './mention-mode.js';
|
|
4
5
|
const PUSHED_SEQS_LIMIT = 50_000;
|
|
5
6
|
const PENDING_ORDERED_LIMIT = 50_000;
|
|
6
7
|
const MESSAGE_RECALL_SEEN_LIMIT = 10_000;
|
|
7
8
|
const GROUP_RECALL_SEEN_LIMIT = 10_000;
|
|
8
9
|
const SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS = 200;
|
|
10
|
+
const DELIVERY_CHANGED_MESSAGE_EVENTS = new Set([
|
|
11
|
+
'message.received',
|
|
12
|
+
'group.message_created',
|
|
13
|
+
]);
|
|
9
14
|
const MAX_INLINE_PENDING_ACK_NAMESPACES = 4096;
|
|
10
15
|
const APP_MESSAGE_ENVELOPE_KEYS = [
|
|
11
16
|
'module_id', 'message_type', 'type', 'kind', 'version',
|
|
@@ -73,6 +78,8 @@ export class MessageDeliveryEngine {
|
|
|
73
78
|
pendingGroupInlineAcks = null;
|
|
74
79
|
pendingGroupInlineAckNamespaces = null;
|
|
75
80
|
inlineAckGeneration = 0;
|
|
81
|
+
pendingDeliveryChanges = null;
|
|
82
|
+
deliveryChangedGeneration = 0;
|
|
76
83
|
// 同一实例的 tracker 写入必须串行,避免旧的延迟 flush 覆盖新的 Forward 提交。
|
|
77
84
|
seqTrackerWriteChain = Promise.resolve();
|
|
78
85
|
constructor(runtime) {
|
|
@@ -207,7 +214,7 @@ export class MessageDeliveryEngine {
|
|
|
207
214
|
}
|
|
208
215
|
if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore) {
|
|
209
216
|
this.ensurePullOperationCurrent();
|
|
210
|
-
await this.drainOrderedMessages(ns, undefined, false, false);
|
|
217
|
+
await this.drainOrderedMessages(ns, undefined, false, false, 'pull');
|
|
211
218
|
this.ensurePullOperationCurrent();
|
|
212
219
|
await client._commitSeqTrackerState(ns);
|
|
213
220
|
}
|
|
@@ -257,6 +264,8 @@ export class MessageDeliveryEngine {
|
|
|
257
264
|
return { rawCount: messages.length, publishedCount };
|
|
258
265
|
}
|
|
259
266
|
resetInlineAckState() {
|
|
267
|
+
this.deliveryChangedGeneration += 1;
|
|
268
|
+
this.pendingDeliveryChanges = null;
|
|
260
269
|
this.inlineAckGeneration += 1;
|
|
261
270
|
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
262
271
|
this.pendingP2PInlineAcks = null;
|
|
@@ -268,6 +277,113 @@ export class MessageDeliveryEngine {
|
|
|
268
277
|
this.onlineUnreadHintTasks = null;
|
|
269
278
|
this.realtimeTailHeads = null;
|
|
270
279
|
}
|
|
280
|
+
deliveryChangedNamespace(event, payload) {
|
|
281
|
+
if (event === 'group.message_created' && isJsonObject(payload)) {
|
|
282
|
+
const aid = String(this.runtime.client._aid ?? '').trim();
|
|
283
|
+
const dot = aid.indexOf('.');
|
|
284
|
+
try {
|
|
285
|
+
const groupAid = validateGroupAIDFormat(payload.group_aid ?? payload.group_id, { localIssuer: dot >= 0 ? aid.slice(dot + 1) : '' });
|
|
286
|
+
return groupAid.includes('.') ? `group:${groupAid}` : '';
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return '';
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return 'p2p';
|
|
293
|
+
}
|
|
294
|
+
isDeliveryChangedMessage(event, payload) {
|
|
295
|
+
if (!DELIVERY_CHANGED_MESSAGE_EVENTS.has(event)
|
|
296
|
+
|| !isJsonObject(payload))
|
|
297
|
+
return false;
|
|
298
|
+
const messageId = payload.message_id;
|
|
299
|
+
const seq = payload.seq;
|
|
300
|
+
return (typeof messageId === 'string' && messageId.trim().length > 0)
|
|
301
|
+
|| (typeof seq === 'number' && Number.isSafeInteger(seq) && seq > 0);
|
|
302
|
+
}
|
|
303
|
+
deliveryChangedTrigger(source) {
|
|
304
|
+
if (source === 'inline-push')
|
|
305
|
+
return 'inline_push';
|
|
306
|
+
if (source === 'pull' || source === 'tail')
|
|
307
|
+
return 'pull_drained';
|
|
308
|
+
if (source === 'push' || source === 'group-push' || source === 'ordered')
|
|
309
|
+
return 'push';
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
noteDeliveryChanged(event, payload, source, context) {
|
|
313
|
+
if (!this.isDeliveryChangedMessage(event, payload))
|
|
314
|
+
return;
|
|
315
|
+
const trigger = this.deliveryChangedTrigger(source);
|
|
316
|
+
const namespace = this.deliveryChangedNamespace(event, payload);
|
|
317
|
+
if (!trigger || !namespace)
|
|
318
|
+
return;
|
|
319
|
+
const pending = trigger === 'pull_drained'
|
|
320
|
+
? this.pendingDeliveryChanges ?? new Map()
|
|
321
|
+
: context?.changes ?? this.pendingDeliveryChanges ?? new Map();
|
|
322
|
+
if (trigger === 'pull_drained' || !context)
|
|
323
|
+
this.pendingDeliveryChanges = pending;
|
|
324
|
+
pending.set(namespace, (pending.get(namespace) ?? 0) + 1);
|
|
325
|
+
if (!context && trigger !== 'pull_drained')
|
|
326
|
+
this.flushDeliveryChanged(trigger);
|
|
327
|
+
}
|
|
328
|
+
flushDeliveryChanged(trigger) {
|
|
329
|
+
const pending = this.pendingDeliveryChanges;
|
|
330
|
+
if (!pending || pending.size === 0)
|
|
331
|
+
return;
|
|
332
|
+
const changes = [...pending.entries()]
|
|
333
|
+
.filter(([, deliveredCount]) => deliveredCount > 0)
|
|
334
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
335
|
+
.map(([namespace, deliveredCount]) => ({ namespace, delivered_count: deliveredCount }));
|
|
336
|
+
pending.clear();
|
|
337
|
+
if (changes.length === 0)
|
|
338
|
+
return;
|
|
339
|
+
const payload = { trigger, changes };
|
|
340
|
+
const dispatcher = this.runtime.client._dispatcher;
|
|
341
|
+
const published = typeof dispatcher.enqueue === 'function'
|
|
342
|
+
? (dispatcher.enqueue('delivery.changed', payload), undefined)
|
|
343
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
344
|
+
? dispatcher.publishSyncAware('delivery.changed', payload)
|
|
345
|
+
: dispatcher.publish?.('delivery.changed', payload);
|
|
346
|
+
if (isPromiseLike(published))
|
|
347
|
+
void Promise.resolve(published).catch((exc) => {
|
|
348
|
+
this.runtime.client._clientLog.warn(`delivery.changed handler failed: ${formatDeliveryError(exc)}`);
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
onPullDrained() {
|
|
352
|
+
this.flushDeliveryChanged('pull_drained');
|
|
353
|
+
}
|
|
354
|
+
flushDeliveryChangedContext(context, trigger) {
|
|
355
|
+
if (context.generation !== this.deliveryChangedGeneration || context.changes.size === 0)
|
|
356
|
+
return;
|
|
357
|
+
const pending = this.pendingDeliveryChanges;
|
|
358
|
+
if (pending) {
|
|
359
|
+
for (const [namespace, count] of pending) {
|
|
360
|
+
context.changes.set(namespace, (context.changes.get(namespace) ?? 0) + count);
|
|
361
|
+
}
|
|
362
|
+
pending.clear();
|
|
363
|
+
}
|
|
364
|
+
const changes = [...context.changes.entries()]
|
|
365
|
+
.filter(([, count]) => count > 0)
|
|
366
|
+
.sort(([left], [right]) => left.localeCompare(right))
|
|
367
|
+
.map(([namespace, delivered_count]) => ({ namespace, delivered_count }));
|
|
368
|
+
context.changes.clear();
|
|
369
|
+
if (changes.length === 0)
|
|
370
|
+
return;
|
|
371
|
+
const dispatcher = this.runtime.client._dispatcher;
|
|
372
|
+
const payload = { trigger, changes };
|
|
373
|
+
const published = typeof dispatcher.enqueue === 'function'
|
|
374
|
+
? (dispatcher.enqueue('delivery.changed', payload), undefined)
|
|
375
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
376
|
+
? dispatcher.publishSyncAware('delivery.changed', payload)
|
|
377
|
+
: dispatcher.publish?.('delivery.changed', payload);
|
|
378
|
+
if (isPromiseLike(published))
|
|
379
|
+
void Promise.resolve(published).catch((exc) => {
|
|
380
|
+
this.runtime.client._clientLog.warn(`delivery.changed handler failed: ${formatDeliveryError(exc)}`);
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
invalidateDeliveryChanges() {
|
|
384
|
+
this.deliveryChangedGeneration += 1;
|
|
385
|
+
this.pendingDeliveryChanges = null;
|
|
386
|
+
}
|
|
271
387
|
inlineGenerationIsCurrent(generation) {
|
|
272
388
|
return this.inlineAckGeneration === generation;
|
|
273
389
|
}
|
|
@@ -310,10 +426,17 @@ export class MessageDeliveryEngine {
|
|
|
310
426
|
}
|
|
311
427
|
endRealtimeSync(ns) {
|
|
312
428
|
this.realtimeSyncing?.delete(ns);
|
|
429
|
+
this.runtime.client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
313
430
|
}
|
|
314
431
|
hasPendingPull(ns) {
|
|
315
432
|
return (this.pendingGroupPullUpper?.get(ns) ?? 0) > 0;
|
|
316
433
|
}
|
|
434
|
+
hasAnyPendingPull() {
|
|
435
|
+
return [...(this.pendingGroupPullUpper?.values() ?? [])].some((seq) => seq > 0)
|
|
436
|
+
|| Boolean(this.onlineUnreadHintTasks?.size)
|
|
437
|
+
|| Boolean(this.realtimeSyncing?.size)
|
|
438
|
+
|| Boolean(this.runtime.client._v2E2EE?.hasPendingSenderIKWork?.());
|
|
439
|
+
}
|
|
317
440
|
onPullGateIdle(ns) {
|
|
318
441
|
if (!ns)
|
|
319
442
|
return;
|
|
@@ -378,14 +501,14 @@ export class MessageDeliveryEngine {
|
|
|
378
501
|
client._pushedSeqs.set(ns, new Set(keep));
|
|
379
502
|
}
|
|
380
503
|
}
|
|
381
|
-
enqueueOrderedMessage(ns, event, seq, payload) {
|
|
504
|
+
enqueueOrderedMessage(ns, event, seq, payload, source = 'push') {
|
|
382
505
|
const client = this.runtime.client;
|
|
383
506
|
let queue = client._pendingOrderedMsgs.get(ns);
|
|
384
507
|
if (!queue) {
|
|
385
508
|
queue = new Map();
|
|
386
509
|
client._pendingOrderedMsgs.set(ns, queue);
|
|
387
510
|
}
|
|
388
|
-
queue.set(seq, { event, payload });
|
|
511
|
+
queue.set(seq, { event, payload, source });
|
|
389
512
|
if (queue.size > PENDING_ORDERED_LIMIT) {
|
|
390
513
|
const drop = [...queue.keys()].sort((a, b) => a - b).slice(0, queue.size - PENDING_ORDERED_LIMIT);
|
|
391
514
|
for (const oldSeq of drop)
|
|
@@ -395,7 +518,7 @@ export class MessageDeliveryEngine {
|
|
|
395
518
|
isGroupEventNamespace(ns) {
|
|
396
519
|
return ns.startsWith('group_event:');
|
|
397
520
|
}
|
|
398
|
-
async publishOrderedQueueItem(ns, event, seq, payload, source, pullResponse = false) {
|
|
521
|
+
async publishOrderedQueueItem(ns, event, seq, payload, source, pullResponse = false, deliveryContext) {
|
|
399
522
|
const client = this.runtime.client;
|
|
400
523
|
this.ensurePullOperationCurrent();
|
|
401
524
|
if (event === 'group.changed' && this.isGroupEventNamespace(ns)) {
|
|
@@ -409,12 +532,12 @@ export class MessageDeliveryEngine {
|
|
|
409
532
|
return;
|
|
410
533
|
}
|
|
411
534
|
if (pullResponse) {
|
|
412
|
-
const published = client._withPullResponseProcessing(ns, () =>
|
|
535
|
+
const published = client._withPullResponseProcessing(ns, () => this.publishAppEvent(event, payload, source, deliveryContext));
|
|
413
536
|
if (isPromiseLike(published))
|
|
414
537
|
await published;
|
|
415
538
|
}
|
|
416
539
|
else {
|
|
417
|
-
const published =
|
|
540
|
+
const published = this.publishAppEvent(event, payload, source, deliveryContext);
|
|
418
541
|
if (isPromiseLike(published))
|
|
419
542
|
await published;
|
|
420
543
|
}
|
|
@@ -934,7 +1057,7 @@ export class MessageDeliveryEngine {
|
|
|
934
1057
|
if (contig !== contigBefore)
|
|
935
1058
|
this.persistSeq(ns);
|
|
936
1059
|
}
|
|
937
|
-
publishAppEvent(event, payload, source = 'direct') {
|
|
1060
|
+
publishAppEvent(event, payload, source = 'direct', deliveryContext) {
|
|
938
1061
|
const client = this.runtime.client;
|
|
939
1062
|
if ((event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
940
1063
|
client._maybeAppendEchoTraceReceive(payload);
|
|
@@ -954,7 +1077,23 @@ export class MessageDeliveryEngine {
|
|
|
954
1077
|
client._clientLog.debug(`agent_md etag inject skipped: ${err instanceof Error ? err.message : String(err)}`);
|
|
955
1078
|
}
|
|
956
1079
|
}
|
|
957
|
-
|
|
1080
|
+
const generation = this.deliveryChangedGeneration;
|
|
1081
|
+
const normalized = this.normalizePublishedMessagePayload(event, payload);
|
|
1082
|
+
const dispatcher = client._dispatcher;
|
|
1083
|
+
const result = typeof dispatcher.enqueue === 'function'
|
|
1084
|
+
? (dispatcher.enqueue(event, normalized), undefined)
|
|
1085
|
+
: typeof dispatcher.publishSyncAware === 'function'
|
|
1086
|
+
? dispatcher.publishSyncAware(event, normalized)
|
|
1087
|
+
: dispatcher.publish?.(event, normalized);
|
|
1088
|
+
const note = () => {
|
|
1089
|
+
if (generation === this.deliveryChangedGeneration) {
|
|
1090
|
+
this.noteDeliveryChanged(event, payload, source, deliveryContext);
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
if (isPromiseLike(result))
|
|
1094
|
+
return Promise.resolve(result).then(note);
|
|
1095
|
+
note();
|
|
1096
|
+
return result;
|
|
958
1097
|
}
|
|
959
1098
|
messagePayloadForDebug(message) {
|
|
960
1099
|
if (!isJsonObject(message))
|
|
@@ -2845,6 +2984,7 @@ export class MessageDeliveryEngine {
|
|
|
2845
2984
|
targets.delete(ns);
|
|
2846
2985
|
if (tasks.get(ns) === task)
|
|
2847
2986
|
tasks.delete(ns);
|
|
2987
|
+
client._rpcPipeline?.requestPullDrainedCheck?.();
|
|
2848
2988
|
}
|
|
2849
2989
|
});
|
|
2850
2990
|
tasks.set(ns, task);
|
|
@@ -2975,13 +3115,13 @@ export class MessageDeliveryEngine {
|
|
|
2975
3115
|
catch (exc) {
|
|
2976
3116
|
const error = formatDeliveryError(exc);
|
|
2977
3117
|
client._clientLog.warn(`restore SeqTracker state failed: ${error}`);
|
|
2978
|
-
client._dispatcher.
|
|
3118
|
+
client._dispatcher.enqueue('seq_tracker.persist_error', {
|
|
2979
3119
|
phase: 'restore',
|
|
2980
3120
|
aid: client._aid,
|
|
2981
3121
|
device_id: client._deviceId,
|
|
2982
3122
|
slot_id: client._slotId,
|
|
2983
3123
|
error: String(error),
|
|
2984
|
-
})
|
|
3124
|
+
});
|
|
2985
3125
|
}
|
|
2986
3126
|
}
|
|
2987
3127
|
migrateSeqStateGroupIds(state) {
|
|
@@ -3200,13 +3340,13 @@ export class MessageDeliveryEngine {
|
|
|
3200
3340
|
catch (exc) {
|
|
3201
3341
|
const error = formatDeliveryError(exc);
|
|
3202
3342
|
client._clientLog.warn(`save SeqTracker state failed: ${error}`);
|
|
3203
|
-
client._dispatcher.
|
|
3343
|
+
client._dispatcher.enqueue('seq_tracker.persist_error', {
|
|
3204
3344
|
phase: 'save',
|
|
3205
3345
|
aid,
|
|
3206
3346
|
device_id: deviceId,
|
|
3207
3347
|
slot_id: slotId,
|
|
3208
3348
|
error: String(error),
|
|
3209
|
-
})
|
|
3349
|
+
});
|
|
3210
3350
|
if (throwOnError)
|
|
3211
3351
|
throw exc;
|
|
3212
3352
|
}
|
|
@@ -3324,45 +3464,67 @@ export class MessageDeliveryEngine {
|
|
|
3324
3464
|
}
|
|
3325
3465
|
return params;
|
|
3326
3466
|
}
|
|
3327
|
-
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true) {
|
|
3467
|
+
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, source = 'push', context) {
|
|
3328
3468
|
const client = this.runtime.client;
|
|
3329
3469
|
this.ensurePullOperationCurrent();
|
|
3330
3470
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3331
3471
|
if (!queue || queue.size === 0)
|
|
3332
3472
|
return;
|
|
3333
3473
|
let delivered = false;
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
.
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3474
|
+
const rootTrigger = this.deliveryChangedTrigger(source);
|
|
3475
|
+
const drainContexts = new Map();
|
|
3476
|
+
try {
|
|
3477
|
+
while (true) {
|
|
3478
|
+
this.ensurePullOperationCurrent();
|
|
3479
|
+
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
3480
|
+
const ready = [...queue.keys()]
|
|
3481
|
+
.filter((seq) => seq <= contig && (beforeSeq === undefined || seq < beforeSeq))
|
|
3482
|
+
.sort((a, b) => a - b);
|
|
3483
|
+
let seq = ready[0];
|
|
3484
|
+
if (seq === undefined) {
|
|
3485
|
+
const nextSeq = contig + 1;
|
|
3486
|
+
if (beforeSeq !== undefined && nextSeq >= beforeSeq)
|
|
3487
|
+
break;
|
|
3488
|
+
if (!queue.has(nextSeq))
|
|
3489
|
+
break;
|
|
3490
|
+
seq = nextSeq;
|
|
3491
|
+
}
|
|
3492
|
+
if (seq === undefined)
|
|
3493
|
+
continue;
|
|
3494
|
+
const item = queue.get(seq);
|
|
3495
|
+
queue.delete(seq);
|
|
3496
|
+
if (!item)
|
|
3497
|
+
continue;
|
|
3498
|
+
if (client._pushedSeqs.get(ns)?.has(seq)) {
|
|
3499
|
+
client._clientLog.debug(`publish ordered drain skipped duplicate: ns=${ns}, seq=${seq}, event=${item.event}`);
|
|
3500
|
+
client._markOrderedSeqDelivered(ns, seq);
|
|
3501
|
+
continue;
|
|
3502
|
+
}
|
|
3503
|
+
const itemSource = item.source ?? source;
|
|
3504
|
+
const itemTrigger = this.deliveryChangedTrigger(itemSource);
|
|
3505
|
+
let itemContext = itemTrigger === rootTrigger ? context : undefined;
|
|
3506
|
+
if (itemTrigger === 'push' || itemTrigger === 'inline_push') {
|
|
3507
|
+
if (!itemContext) {
|
|
3508
|
+
itemContext = drainContexts.get(itemTrigger);
|
|
3509
|
+
if (!itemContext) {
|
|
3510
|
+
itemContext = { generation: this.deliveryChangedGeneration, changes: new Map() };
|
|
3511
|
+
drainContexts.set(itemTrigger, itemContext);
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, itemSource, pullResponse, itemContext);
|
|
3516
|
+
this.ensurePullOperationCurrent();
|
|
3517
|
+
this.markPublishedSeq(ns, seq);
|
|
3357
3518
|
client._markOrderedSeqDelivered(ns, seq);
|
|
3358
|
-
|
|
3519
|
+
delivered = true;
|
|
3520
|
+
client._clientLog.debug(`publish ordered drain delivered: ns=${ns}, seq=${seq}, event=${item.event}`);
|
|
3521
|
+
}
|
|
3522
|
+
}
|
|
3523
|
+
finally {
|
|
3524
|
+
for (const [trigger, drainContext] of drainContexts) {
|
|
3525
|
+
if (drainContext !== context)
|
|
3526
|
+
this.flushDeliveryChangedContext(drainContext, trigger);
|
|
3359
3527
|
}
|
|
3360
|
-
await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, 'ordered-drain', pullResponse);
|
|
3361
|
-
this.ensurePullOperationCurrent();
|
|
3362
|
-
this.markPublishedSeq(ns, seq);
|
|
3363
|
-
client._markOrderedSeqDelivered(ns, seq);
|
|
3364
|
-
delivered = true;
|
|
3365
|
-
client._clientLog.debug(`publish ordered drain delivered: ns=${ns}, seq=${seq}, event=${item.event}`);
|
|
3366
3528
|
}
|
|
3367
3529
|
if (queue.size === 0) {
|
|
3368
3530
|
client._pendingOrderedMsgs.delete(ns);
|
|
@@ -3372,13 +3534,35 @@ export class MessageDeliveryEngine {
|
|
|
3372
3534
|
}
|
|
3373
3535
|
}
|
|
3374
3536
|
}
|
|
3375
|
-
async publishOrderedMessage(event, ns, seq, payload) {
|
|
3537
|
+
async publishOrderedMessage(event, ns, seq, payload, source = 'push') {
|
|
3538
|
+
const context = {
|
|
3539
|
+
generation: this.deliveryChangedGeneration,
|
|
3540
|
+
changes: new Map(),
|
|
3541
|
+
};
|
|
3542
|
+
try {
|
|
3543
|
+
return await this.publishOrderedMessageInternal(event, ns, seq, payload, source, context);
|
|
3544
|
+
}
|
|
3545
|
+
finally {
|
|
3546
|
+
const trigger = this.deliveryChangedTrigger(source);
|
|
3547
|
+
if (trigger === 'pull_drained' && context.generation === this.deliveryChangedGeneration) {
|
|
3548
|
+
const pending = this.pendingDeliveryChanges ?? new Map();
|
|
3549
|
+
this.pendingDeliveryChanges = pending;
|
|
3550
|
+
for (const [namespace, count] of context.changes) {
|
|
3551
|
+
pending.set(namespace, (pending.get(namespace) ?? 0) + count);
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3554
|
+
else if (trigger && trigger !== 'pull_drained') {
|
|
3555
|
+
this.flushDeliveryChangedContext(context, trigger);
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
async publishOrderedMessageInternal(event, ns, seq, payload, source, context) {
|
|
3376
3560
|
const client = this.runtime.client;
|
|
3377
3561
|
this.ensurePullOperationCurrent();
|
|
3378
3562
|
const seqNum = Number(seq);
|
|
3379
3563
|
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0) {
|
|
3380
3564
|
client._clientLog.debug(`publish ordered direct(no-seq): event=${event}, ns=${ns || '<none>'}, seq=${String(seq)}`);
|
|
3381
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload,
|
|
3565
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, source, false, context);
|
|
3382
3566
|
this.ensurePullOperationCurrent();
|
|
3383
3567
|
return true;
|
|
3384
3568
|
}
|
|
@@ -3393,10 +3577,10 @@ export class MessageDeliveryEngine {
|
|
|
3393
3577
|
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
3394
3578
|
if (seqNum > contig && seqNum !== contig + 1) {
|
|
3395
3579
|
client._clientLog.debug(`publish ordered enqueue(gap): event=${event}, ns=${ns}, seq=${seqNum}, contiguous=${contig}`);
|
|
3396
|
-
this.enqueueOrderedMessage(ns, event, seqNum, payload);
|
|
3580
|
+
this.enqueueOrderedMessage(ns, event, seqNum, payload, source);
|
|
3397
3581
|
return false;
|
|
3398
3582
|
}
|
|
3399
|
-
await this.drainOrderedMessages(ns, seqNum);
|
|
3583
|
+
await this.drainOrderedMessages(ns, seqNum, false, true, source, context);
|
|
3400
3584
|
this.ensurePullOperationCurrent();
|
|
3401
3585
|
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
3402
3586
|
client._clientLog.debug(`publish ordered skipped after-drain duplicate: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
@@ -3406,12 +3590,12 @@ export class MessageDeliveryEngine {
|
|
|
3406
3590
|
queue?.delete(seqNum);
|
|
3407
3591
|
if (queue && queue.size === 0)
|
|
3408
3592
|
client._pendingOrderedMsgs.delete(ns);
|
|
3409
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload,
|
|
3593
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, source, false, context);
|
|
3410
3594
|
this.ensurePullOperationCurrent();
|
|
3411
3595
|
this.markPublishedSeq(ns, seqNum);
|
|
3412
3596
|
client._markOrderedSeqDelivered(ns, seqNum);
|
|
3413
3597
|
client._clientLog.debug(`publish ordered delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
3414
|
-
await this.drainOrderedMessages(ns);
|
|
3598
|
+
await this.drainOrderedMessages(ns, undefined, false, true, source, context);
|
|
3415
3599
|
if (!client._pendingOrderedMsgs.get(ns)) {
|
|
3416
3600
|
this.ensurePullOperationCurrent();
|
|
3417
3601
|
await this.saveSeqTrackerState();
|
|
@@ -3469,7 +3653,7 @@ export class MessageDeliveryEngine {
|
|
|
3469
3653
|
client._pendingOrderedMsgs.delete(ns);
|
|
3470
3654
|
return false;
|
|
3471
3655
|
}
|
|
3472
|
-
await this.drainOrderedMessages(ns, seqNum, true, persist);
|
|
3656
|
+
await this.drainOrderedMessages(ns, seqNum, true, persist, 'pull');
|
|
3473
3657
|
this.ensurePullOperationCurrent();
|
|
3474
3658
|
queue?.delete(seqNum);
|
|
3475
3659
|
if (queue && queue.size === 0)
|
|
@@ -3479,7 +3663,7 @@ export class MessageDeliveryEngine {
|
|
|
3479
3663
|
this.ensurePullOperationCurrent();
|
|
3480
3664
|
this.markPublishedSeq(ns, seqNum);
|
|
3481
3665
|
client._clientLog.debug(`publish pulled delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
3482
|
-
await this.drainOrderedMessages(ns, undefined, true, persist);
|
|
3666
|
+
await this.drainOrderedMessages(ns, undefined, true, persist, 'pull');
|
|
3483
3667
|
this.ensurePullOperationCurrent();
|
|
3484
3668
|
return recallPublished;
|
|
3485
3669
|
}
|
|
@@ -3489,7 +3673,7 @@ export class MessageDeliveryEngine {
|
|
|
3489
3673
|
this.ensurePullOperationCurrent();
|
|
3490
3674
|
this.markPublishedSeq(ns, seqNum);
|
|
3491
3675
|
client._clientLog.debug(`publish pulled delivered: event=${event}, ns=${ns}, seq=${seqNum}`);
|
|
3492
|
-
await this.drainOrderedMessages(ns, undefined, true, persist);
|
|
3676
|
+
await this.drainOrderedMessages(ns, undefined, true, persist, 'pull');
|
|
3493
3677
|
this.ensurePullOperationCurrent();
|
|
3494
3678
|
return true;
|
|
3495
3679
|
}
|