@agentunion/fastaun-browser 0.5.8 → 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 +62 -0
- package/_packed_docs/CHANGELOG.md +62 -0
- package/_packed_docs/agent.md/examples//347/276/244/347/273/204-/345/274/200/345/217/221/345/233/242/351/230/237.md +21 -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.d.ts.map +1 -1
- package/dist/agent-md.js +24 -1
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +1 -3
- package/dist/aid-store.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +16 -2
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +1247 -269
- package/dist/client/delivery.d.ts +30 -7
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +354 -92
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.js +8 -8
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.d.ts.map +1 -1
- package/dist/client/lifecycle.js +41 -34
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +12 -0
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +205 -36
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +72 -18
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +0 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +128 -45
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +31 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +167 -7
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +7 -3
- package/dist/facades.js.map +1 -1
- package/dist/register-flow.d.ts.map +1 -1
- package/dist/register-flow.js +16 -2
- package/dist/register-flow.js.map +1 -1
- package/dist/transport.d.ts +10 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +283 -29
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +1 -1
- package/_packed_docs//345/217/221/345/270/203/346/212/245/345/221/212-0.5.6.md +0 -260
package/dist/client/delivery.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { slotIsolationKey } from '../config.js';
|
|
2
|
+
import { normalizeGroupAid } from '../group-id.js';
|
|
2
3
|
import { ConnectionState, isJsonObject } from '../types.js';
|
|
3
4
|
import { hasGroupMentionModeField, normalizeGroupMentionMode } from './mention-mode.js';
|
|
4
5
|
const PUSHED_SEQS_LIMIT = 50_000;
|
|
@@ -94,10 +95,15 @@ function p2pAppEventFromPlainPullMessage(message) {
|
|
|
94
95
|
}
|
|
95
96
|
export class MessageDeliveryEngine {
|
|
96
97
|
runtime;
|
|
98
|
+
pendingPullDeliveryChanges = null;
|
|
99
|
+
deliveryGeneration = 0;
|
|
97
100
|
realtimeTailResults = null;
|
|
98
101
|
realtimeSyncing = null;
|
|
99
102
|
pendingP2pPullUpper = null;
|
|
100
103
|
pendingGroupPullUpper = null;
|
|
104
|
+
pendingPullNoProgressAcks = null;
|
|
105
|
+
onlineUnreadHintTargets = null;
|
|
106
|
+
onlineUnreadHintOwners = null;
|
|
101
107
|
realtimeAcking = null;
|
|
102
108
|
pendingP2PInlineAcks = null;
|
|
103
109
|
pendingGroupInlineAcks = null;
|
|
@@ -111,9 +117,15 @@ export class MessageDeliveryEngine {
|
|
|
111
117
|
}
|
|
112
118
|
resetInlineAckState() {
|
|
113
119
|
this.inlineGeneration += 1;
|
|
120
|
+
this.deliveryGeneration += 1;
|
|
121
|
+
this.pendingPullDeliveryChanges = null;
|
|
122
|
+
void this.runtime.client._rpcPipeline?.invalidatePulls?.();
|
|
114
123
|
this.realtimeSyncing = null;
|
|
115
124
|
this.pendingP2pPullUpper = null;
|
|
116
125
|
this.pendingGroupPullUpper = null;
|
|
126
|
+
this.pendingPullNoProgressAcks = null;
|
|
127
|
+
this.onlineUnreadHintTargets = null;
|
|
128
|
+
this.onlineUnreadHintOwners = null;
|
|
117
129
|
this.realtimeTailResults = null;
|
|
118
130
|
this.realtimeAcking = null;
|
|
119
131
|
this.pendingP2PInlineAcks = null;
|
|
@@ -123,6 +135,20 @@ export class MessageDeliveryEngine {
|
|
|
123
135
|
isInlineGenerationCurrent(generation) {
|
|
124
136
|
return generation === this.inlineGeneration;
|
|
125
137
|
}
|
|
138
|
+
isPullOperationCurrent() {
|
|
139
|
+
const client = this.runtime.client;
|
|
140
|
+
const generation = client._pullOperationGeneration;
|
|
141
|
+
if (generation === undefined)
|
|
142
|
+
return true;
|
|
143
|
+
const pipeline = client._rpcPipeline;
|
|
144
|
+
return typeof pipeline?.isPullGenerationCurrent === 'function'
|
|
145
|
+
? pipeline.isPullGenerationCurrent(generation)
|
|
146
|
+
: true;
|
|
147
|
+
}
|
|
148
|
+
ensurePullOperationCurrent() {
|
|
149
|
+
if (!this.isPullOperationCurrent())
|
|
150
|
+
throw new Error('pull invalidated');
|
|
151
|
+
}
|
|
126
152
|
captureInlineGeneration() {
|
|
127
153
|
return this.inlineGeneration;
|
|
128
154
|
}
|
|
@@ -146,6 +172,85 @@ export class MessageDeliveryEngine {
|
|
|
146
172
|
return;
|
|
147
173
|
this.schedulePendingPullIfNeeded(ns, 'pull-gate-idle');
|
|
148
174
|
}
|
|
175
|
+
onPullWorkSettled() {
|
|
176
|
+
const pipeline = this.runtime.client._rpcPipeline;
|
|
177
|
+
if (pipeline?.hasAnyPullActivity?.() === true)
|
|
178
|
+
return;
|
|
179
|
+
void this.flushPullDeliveryChanges();
|
|
180
|
+
}
|
|
181
|
+
deliveryChangeNamespace(event, payload, ns = '') {
|
|
182
|
+
if (event === 'message.received')
|
|
183
|
+
return 'p2p';
|
|
184
|
+
if (event !== 'group.message_created')
|
|
185
|
+
return '';
|
|
186
|
+
if (!isJsonObject(payload))
|
|
187
|
+
return '';
|
|
188
|
+
const aid = String(this.runtime.client._aid ?? '').trim().toLowerCase();
|
|
189
|
+
const dot = aid.indexOf('.');
|
|
190
|
+
const localIssuer = dot > 0 ? aid.slice(dot + 1) : '';
|
|
191
|
+
const fallback = ns.startsWith('group:') ? ns.slice('group:'.length) : '';
|
|
192
|
+
const groupAid = normalizeGroupAid(payload.group_aid ?? payload.group_id ?? fallback, { localIssuer });
|
|
193
|
+
return groupAid.includes('.') ? `group:${groupAid}` : '';
|
|
194
|
+
}
|
|
195
|
+
isDeliverableMessageBody(event, payload) {
|
|
196
|
+
if ((event !== 'message.received' && event !== 'group.message_created') || !isJsonObject(payload))
|
|
197
|
+
return false;
|
|
198
|
+
const messageId = typeof payload.message_id === 'string' && payload.message_id.trim().length > 0;
|
|
199
|
+
const seq = typeof payload.seq === 'number' && Number.isSafeInteger(payload.seq) && payload.seq > 0;
|
|
200
|
+
return messageId || seq;
|
|
201
|
+
}
|
|
202
|
+
recordDeliveryChange(changes, event, payload, ns, generation) {
|
|
203
|
+
if (generation !== this.deliveryGeneration || !this.isDeliverableMessageBody(event, payload))
|
|
204
|
+
return;
|
|
205
|
+
const namespace = this.deliveryChangeNamespace(event, payload, ns);
|
|
206
|
+
if (!namespace)
|
|
207
|
+
return;
|
|
208
|
+
changes.set(namespace, (changes.get(namespace) ?? 0) + 1);
|
|
209
|
+
}
|
|
210
|
+
deliveryChangesPayload(changes) {
|
|
211
|
+
return [...changes.entries()]
|
|
212
|
+
.filter(([, deliveredCount]) => deliveredCount > 0)
|
|
213
|
+
.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
214
|
+
.map(([namespace, deliveredCount]) => ({ namespace, delivered_count: deliveredCount }));
|
|
215
|
+
}
|
|
216
|
+
createDeliveryChangeBatch(trigger) {
|
|
217
|
+
return { generation: this.deliveryGeneration, trigger, changes: new Map(), closed: false };
|
|
218
|
+
}
|
|
219
|
+
async flushRealtimeDeliveryChanges(batch) {
|
|
220
|
+
if (batch.closed)
|
|
221
|
+
return;
|
|
222
|
+
batch.closed = true;
|
|
223
|
+
if (batch.generation !== this.deliveryGeneration)
|
|
224
|
+
return;
|
|
225
|
+
if (this.deliveryChangesPayload(batch.changes).length === 0)
|
|
226
|
+
return;
|
|
227
|
+
const pendingPull = this.pendingPullDeliveryChanges;
|
|
228
|
+
this.pendingPullDeliveryChanges = null;
|
|
229
|
+
if (pendingPull) {
|
|
230
|
+
for (const [namespace, count] of pendingPull) {
|
|
231
|
+
batch.changes.set(namespace, (batch.changes.get(namespace) ?? 0) + count);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (batch.generation !== this.deliveryGeneration)
|
|
235
|
+
return;
|
|
236
|
+
const changes = this.deliveryChangesPayload(batch.changes);
|
|
237
|
+
if (changes.length === 0)
|
|
238
|
+
return;
|
|
239
|
+
this.runtime.client._dispatcher.enqueue('delivery.changed', { trigger: batch.trigger, changes });
|
|
240
|
+
}
|
|
241
|
+
async flushPullDeliveryChanges() {
|
|
242
|
+
const generation = this.deliveryGeneration;
|
|
243
|
+
const pending = this.pendingPullDeliveryChanges;
|
|
244
|
+
if (!pending || pending.size === 0 || generation !== this.deliveryGeneration)
|
|
245
|
+
return;
|
|
246
|
+
this.pendingPullDeliveryChanges = null;
|
|
247
|
+
if (generation !== this.deliveryGeneration)
|
|
248
|
+
return;
|
|
249
|
+
const changes = this.deliveryChangesPayload(pending);
|
|
250
|
+
if (changes.length === 0)
|
|
251
|
+
return;
|
|
252
|
+
this.runtime.client._dispatcher.enqueue('delivery.changed', { trigger: 'pull_drained', changes });
|
|
253
|
+
}
|
|
149
254
|
recordPendingPull(ns, seq) {
|
|
150
255
|
if (!ns || !Number.isSafeInteger(seq) || seq <= 0)
|
|
151
256
|
return;
|
|
@@ -160,8 +265,15 @@ export class MessageDeliveryEngine {
|
|
|
160
265
|
}
|
|
161
266
|
consumePendingPull(ns, throughSeq) {
|
|
162
267
|
const pending = ns.startsWith('p2p:') ? this.pendingP2pPullUpper : this.pendingGroupPullUpper;
|
|
163
|
-
if ((pending?.get(ns) ?? 0) <= throughSeq)
|
|
268
|
+
if ((pending?.get(ns) ?? 0) <= throughSeq) {
|
|
164
269
|
pending?.delete(ns);
|
|
270
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
markPendingPullNoProgress(ns, ack) {
|
|
274
|
+
const blocked = this.pendingPullNoProgressAcks ?? new Map();
|
|
275
|
+
this.pendingPullNoProgressAcks = blocked;
|
|
276
|
+
blocked.set(ns, ack);
|
|
165
277
|
}
|
|
166
278
|
schedulePendingPullIfNeeded(ns, reason) {
|
|
167
279
|
const pending = ns.startsWith('p2p:') ? this.pendingP2pPullUpper : this.pendingGroupPullUpper;
|
|
@@ -170,15 +282,21 @@ export class MessageDeliveryEngine {
|
|
|
170
282
|
const upper = pending.get(ns) ?? 0;
|
|
171
283
|
if (upper <= 0) {
|
|
172
284
|
pending.delete(ns);
|
|
285
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
173
286
|
return false;
|
|
174
287
|
}
|
|
175
288
|
const client = this.runtime.client;
|
|
176
289
|
const contiguous = client._seqTracker.getContiguousSeq(ns);
|
|
177
290
|
if (upper <= contiguous) {
|
|
178
291
|
pending.delete(ns);
|
|
292
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
179
293
|
client._clientLog?.debug(`pending pull upper already covered: ns=${ns}, upper_seq=${upper}, contiguous=${contiguous}, reason=${reason}`);
|
|
180
294
|
return false;
|
|
181
295
|
}
|
|
296
|
+
const blockedAck = this.pendingPullNoProgressAcks?.get(ns);
|
|
297
|
+
if (blockedAck !== undefined && contiguous <= blockedAck)
|
|
298
|
+
return false;
|
|
299
|
+
this.pendingPullNoProgressAcks?.delete(ns);
|
|
182
300
|
if (client.state !== ConnectionState.READY || client._closing || this.realtimeSyncing?.has(ns)
|
|
183
301
|
|| client._rpcPipeline?.hasPullActivity?.(ns, false))
|
|
184
302
|
return false;
|
|
@@ -620,6 +738,20 @@ export class MessageDeliveryEngine {
|
|
|
620
738
|
else if (Object.prototype.hasOwnProperty.call(row, 'ack_seq')) {
|
|
621
739
|
value = row.ack_seq;
|
|
622
740
|
}
|
|
741
|
+
else if (Object.prototype.hasOwnProperty.call(row, 'cursor')) {
|
|
742
|
+
const cursor = row.cursor;
|
|
743
|
+
const cursorRow = isJsonObject(cursor)
|
|
744
|
+
? cursor
|
|
745
|
+
: null;
|
|
746
|
+
if (cursorRow) {
|
|
747
|
+
if (!Object.prototype.hasOwnProperty.call(cursorRow, 'current_seq'))
|
|
748
|
+
return 0;
|
|
749
|
+
value = cursorRow.current_seq;
|
|
750
|
+
}
|
|
751
|
+
else {
|
|
752
|
+
value = cursor;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
623
755
|
else {
|
|
624
756
|
return requestedSeq;
|
|
625
757
|
}
|
|
@@ -640,6 +772,7 @@ export class MessageDeliveryEngine {
|
|
|
640
772
|
}
|
|
641
773
|
async confirmPlainForwardAck(ns, method, ackSeq, groupId = '') {
|
|
642
774
|
const client = this.runtime.client;
|
|
775
|
+
this.ensurePullOperationCurrent();
|
|
643
776
|
const coordinator = this.forwardCoordinator();
|
|
644
777
|
const generation = this.captureInlineGeneration();
|
|
645
778
|
coordinator.recordForwardAck(ns, ackSeq);
|
|
@@ -658,6 +791,7 @@ export class MessageDeliveryEngine {
|
|
|
658
791
|
_rpc_background: true,
|
|
659
792
|
};
|
|
660
793
|
const result = await client._rpcPipeline.rawCall(method, params, { background: true });
|
|
794
|
+
this.ensurePullOperationCurrent();
|
|
661
795
|
const actualAckSeq = this.resolveForwardAckSeq(result, ackSeq);
|
|
662
796
|
if (actualAckSeq < ackSeq) {
|
|
663
797
|
throw new Error(`${method} server ACK watermark ${actualAckSeq} is below requested ${ackSeq}`);
|
|
@@ -675,6 +809,7 @@ export class MessageDeliveryEngine {
|
|
|
675
809
|
throw new Error(`${method} response must be an object`);
|
|
676
810
|
}
|
|
677
811
|
const client = this.runtime.client;
|
|
812
|
+
this.ensurePullOperationCurrent();
|
|
678
813
|
const response = result;
|
|
679
814
|
const messages = deduplicatePlainForwardPageMessages(response.messages, afterSeq);
|
|
680
815
|
const coordinator = this.forwardCoordinator();
|
|
@@ -705,25 +840,30 @@ export class MessageDeliveryEngine {
|
|
|
705
840
|
let committed = false;
|
|
706
841
|
try {
|
|
707
842
|
for (const rawMessage of messages) {
|
|
843
|
+
this.ensurePullOperationCurrent();
|
|
708
844
|
const seq = positiveSafeSequenceHint(rawMessage.seq);
|
|
709
845
|
if (method === 'message.pull') {
|
|
710
846
|
const appEvent = p2pAppEventFromPlainPullMessage(rawMessage);
|
|
711
847
|
if (await this.publishPulledMessage(appEvent.event, ns, seq, appEvent.payload, false)) {
|
|
712
848
|
publishedCount += 1;
|
|
713
849
|
}
|
|
850
|
+
this.ensurePullOperationCurrent();
|
|
714
851
|
continue;
|
|
715
852
|
}
|
|
716
853
|
const message = normalizeGroupMentionMode(rawMessage);
|
|
717
854
|
if (this.recallEventFromGroupMessage(message)) {
|
|
718
855
|
if (await this.publishGroupRecallTombstone(groupId, seq, message)) {
|
|
856
|
+
this.ensurePullOperationCurrent();
|
|
719
857
|
this.markPublishedSeq(ns, seq);
|
|
720
858
|
publishedCount += 1;
|
|
721
859
|
}
|
|
722
860
|
}
|
|
723
861
|
else if (await this.publishPulledMessage('group.message_created', ns, seq, message, false)) {
|
|
862
|
+
this.ensurePullOperationCurrent();
|
|
724
863
|
publishedCount += 1;
|
|
725
864
|
}
|
|
726
865
|
}
|
|
866
|
+
this.ensurePullOperationCurrent();
|
|
727
867
|
if (messages.length > 0)
|
|
728
868
|
client._seqTracker.onPullResult(ns, messages, afterSeq);
|
|
729
869
|
const commitTarget = Math.max(client._seqTracker.getContiguousSeq(ns), retentionFloor, visibilityFloor, deferredServerCursor);
|
|
@@ -731,18 +871,21 @@ export class MessageDeliveryEngine {
|
|
|
731
871
|
client._seqTracker.forceContiguousSeq(ns, commitTarget);
|
|
732
872
|
}
|
|
733
873
|
if (client._seqTracker.getContiguousSeq(ns) !== pageContigBefore) {
|
|
874
|
+
this.ensurePullOperationCurrent();
|
|
734
875
|
await this.drainOrderedMessages(ns, undefined, false, false);
|
|
876
|
+
this.ensurePullOperationCurrent();
|
|
735
877
|
await client._commitSeqTrackerState(ns);
|
|
736
878
|
}
|
|
737
879
|
committed = true;
|
|
738
880
|
}
|
|
739
881
|
catch (exc) {
|
|
740
|
-
if (!committed && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
|
|
882
|
+
if (this.isPullOperationCurrent() && !committed && typeof client._seqTracker.restoreNamespaceSnapshot === 'function') {
|
|
741
883
|
client._seqTracker.restoreNamespaceSnapshot(ns, pageTrackerSnapshot);
|
|
742
884
|
this.dropSeqTrackerPending(ns);
|
|
743
885
|
}
|
|
744
886
|
throw exc;
|
|
745
887
|
}
|
|
888
|
+
this.ensurePullOperationCurrent();
|
|
746
889
|
const committedAck = client._seqTracker.getContiguousSeq(ns);
|
|
747
890
|
if (deferredServerCursor > 0 && committedAck >= deferredServerCursor) {
|
|
748
891
|
coordinator.clearForwardCursor(ns, committedAck);
|
|
@@ -773,18 +916,19 @@ export class MessageDeliveryEngine {
|
|
|
773
916
|
if (clampedAckSeq < pendingAckSeq) {
|
|
774
917
|
throw new Error(`${ackMethod} cannot confirm pending Forward watermark ${pendingAckSeq}`);
|
|
775
918
|
}
|
|
919
|
+
this.ensurePullOperationCurrent();
|
|
776
920
|
await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
|
|
777
921
|
}
|
|
778
922
|
return { rawCount: messages.length, publishedCount };
|
|
779
923
|
}
|
|
780
|
-
enqueueOrderedMessage(ns, event, seq, payload) {
|
|
924
|
+
enqueueOrderedMessage(ns, event, seq, payload, source = 'push') {
|
|
781
925
|
const client = this.runtime.client;
|
|
782
926
|
let queue = client._pendingOrderedMsgs.get(ns);
|
|
783
927
|
if (!queue) {
|
|
784
928
|
queue = new Map();
|
|
785
929
|
client._pendingOrderedMsgs.set(ns, queue);
|
|
786
930
|
}
|
|
787
|
-
queue.set(seq, { event, payload });
|
|
931
|
+
queue.set(seq, { event, payload, source });
|
|
788
932
|
if (queue.size > PENDING_ORDERED_LIMIT) {
|
|
789
933
|
const drop = [...queue.keys()].sort((a, b) => a - b).slice(0, queue.size - PENDING_ORDERED_LIMIT);
|
|
790
934
|
for (const oldSeq of drop)
|
|
@@ -794,7 +938,7 @@ export class MessageDeliveryEngine {
|
|
|
794
938
|
isGroupEventNamespace(ns) {
|
|
795
939
|
return ns.startsWith('group_event:');
|
|
796
940
|
}
|
|
797
|
-
async publishOrderedQueueItem(ns, event, seq, payload, pullResponse = false) {
|
|
941
|
+
async publishOrderedQueueItem(ns, event, seq, payload, pullResponse = false, source = 'push', batch) {
|
|
798
942
|
const client = this.runtime.client;
|
|
799
943
|
if (event === 'group.changed' && this.isGroupEventNamespace(ns)) {
|
|
800
944
|
await this.publishOrderedGroupChanged(payload);
|
|
@@ -805,10 +949,10 @@ export class MessageDeliveryEngine {
|
|
|
805
949
|
return;
|
|
806
950
|
}
|
|
807
951
|
if (pullResponse) {
|
|
808
|
-
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
952
|
+
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
809
953
|
return;
|
|
810
954
|
}
|
|
811
|
-
await client._publishAppEvent(event, payload);
|
|
955
|
+
await client._publishAppEvent(event, payload, source, ns, batch);
|
|
812
956
|
}
|
|
813
957
|
async publishOrderedGroupChanged(payload) {
|
|
814
958
|
const client = this.runtime.client;
|
|
@@ -983,6 +1127,7 @@ export class MessageDeliveryEngine {
|
|
|
983
1127
|
setIfPresent('type', firstValue(body.type, params.type, params.message_type, params.payload_type));
|
|
984
1128
|
setIfPresent('kind', firstValue(body.kind, params.kind));
|
|
985
1129
|
setIfPresent('version', firstValue(body.version, params.version));
|
|
1130
|
+
setIfPresent('message_id', firstValue(params.message_id, body.message_id, resultObj.message_id));
|
|
986
1131
|
setIfPresent('timestamp', firstValue(params.timestamp, resultObj.timestamp, resultObj.created_at, resultObj.t_server, Date.now()));
|
|
987
1132
|
envelope.encrypted = Boolean(encrypted);
|
|
988
1133
|
const context = this.envelopeMetadata(params.context);
|
|
@@ -1325,8 +1470,9 @@ export class MessageDeliveryEngine {
|
|
|
1325
1470
|
if (contig !== contigBefore)
|
|
1326
1471
|
this.persistSeq(ns);
|
|
1327
1472
|
}
|
|
1328
|
-
async publishAppEvent(event, payload) {
|
|
1473
|
+
async publishAppEvent(event, payload, source = '', ns = '', batch) {
|
|
1329
1474
|
const client = this.runtime.client;
|
|
1475
|
+
const generation = this.deliveryGeneration;
|
|
1330
1476
|
if ((event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
1331
1477
|
client._maybeAppendEchoTraceReceive(payload);
|
|
1332
1478
|
}
|
|
@@ -1346,7 +1492,25 @@ export class MessageDeliveryEngine {
|
|
|
1346
1492
|
client._clientLog.debug(`agent_md etag inject skipped: ${String(exc)}`);
|
|
1347
1493
|
}
|
|
1348
1494
|
}
|
|
1349
|
-
|
|
1495
|
+
client._dispatcher.enqueue(event, this.normalizePublishedMessagePayload(event, payload));
|
|
1496
|
+
if (generation !== this.deliveryGeneration)
|
|
1497
|
+
return;
|
|
1498
|
+
if (source !== 'pull' && source !== 'tail' && source !== 'pending_retry'
|
|
1499
|
+
&& source !== 'push' && source !== 'inline_push')
|
|
1500
|
+
return;
|
|
1501
|
+
if (source === 'push' || source === 'inline_push') {
|
|
1502
|
+
const localBatch = batch ?? this.createDeliveryChangeBatch(source);
|
|
1503
|
+
this.recordDeliveryChange(localBatch.changes, event, payload, ns, generation);
|
|
1504
|
+
if (!batch)
|
|
1505
|
+
await this.flushRealtimeDeliveryChanges(localBatch);
|
|
1506
|
+
}
|
|
1507
|
+
else {
|
|
1508
|
+
const changes = this.pendingPullDeliveryChanges ?? new Map();
|
|
1509
|
+
this.pendingPullDeliveryChanges = changes;
|
|
1510
|
+
this.recordDeliveryChange(changes, event, payload, ns, generation);
|
|
1511
|
+
if (client._rpcPipeline?.hasAnyPullActivity?.() !== true)
|
|
1512
|
+
await this.flushPullDeliveryChanges();
|
|
1513
|
+
}
|
|
1350
1514
|
}
|
|
1351
1515
|
messageTargetsCurrentInstance(message) {
|
|
1352
1516
|
if (!isJsonObject(message))
|
|
@@ -1502,7 +1666,7 @@ export class MessageDeliveryEngine {
|
|
|
1502
1666
|
const client = this.runtime.client;
|
|
1503
1667
|
try {
|
|
1504
1668
|
if (!isJsonObject(data)) {
|
|
1505
|
-
await client._publishAppEvent('message.received', data);
|
|
1669
|
+
await client._publishAppEvent('message.received', data, 'push');
|
|
1506
1670
|
return;
|
|
1507
1671
|
}
|
|
1508
1672
|
const msg = { ...data };
|
|
@@ -1554,7 +1718,7 @@ export class MessageDeliveryEngine {
|
|
|
1554
1718
|
await client._publishEncryptedPushMessage('message.received', 'message.undecryptable', '', seq ?? 0, msg, false);
|
|
1555
1719
|
return;
|
|
1556
1720
|
}
|
|
1557
|
-
await client._publishAppEvent('message.received', msg);
|
|
1721
|
+
await client._publishAppEvent('message.received', msg, 'push');
|
|
1558
1722
|
}
|
|
1559
1723
|
}
|
|
1560
1724
|
catch (exc) {
|
|
@@ -1598,7 +1762,7 @@ export class MessageDeliveryEngine {
|
|
|
1598
1762
|
const client = this.runtime.client;
|
|
1599
1763
|
try {
|
|
1600
1764
|
if (!isJsonObject(data)) {
|
|
1601
|
-
await client._publishAppEvent('group.message_created', data);
|
|
1765
|
+
await client._publishAppEvent('group.message_created', data, 'push');
|
|
1602
1766
|
return;
|
|
1603
1767
|
}
|
|
1604
1768
|
const msg = { ...data };
|
|
@@ -1677,7 +1841,7 @@ export class MessageDeliveryEngine {
|
|
|
1677
1841
|
await client._publishEncryptedPushMessage('group.message_created', 'group.message_undecryptable', '', seq ?? 0, msg, true);
|
|
1678
1842
|
return;
|
|
1679
1843
|
}
|
|
1680
|
-
await client._publishAppEvent('group.message_created', msg);
|
|
1844
|
+
await client._publishAppEvent('group.message_created', msg, 'push');
|
|
1681
1845
|
}
|
|
1682
1846
|
}
|
|
1683
1847
|
catch (exc) {
|
|
@@ -1761,12 +1925,15 @@ export class MessageDeliveryEngine {
|
|
|
1761
1925
|
return;
|
|
1762
1926
|
const delayMs = Math.min(P2P_GAP_FILL_RETRY_BASE_MS * retryAttempt, P2P_GAP_FILL_RETRY_MAX_MS);
|
|
1763
1927
|
client._gapFillDone.add(retryKey);
|
|
1928
|
+
const releasePullWork = client._rpcPipeline?.reservePullWork?.() ?? (() => { });
|
|
1764
1929
|
client._clientLog.debug(`P2P message gap-fill retry scheduled: ns=${ns} attempt=${retryAttempt} delay_ms=${delayMs}`);
|
|
1765
1930
|
globalThis.setTimeout(() => {
|
|
1766
1931
|
client._gapFillDone.delete(retryKey);
|
|
1767
|
-
if (client.state !== ConnectionState.READY || client._closing)
|
|
1932
|
+
if (client.state !== ConnectionState.READY || client._closing) {
|
|
1933
|
+
releasePullWork();
|
|
1768
1934
|
return;
|
|
1769
|
-
|
|
1935
|
+
}
|
|
1936
|
+
client._safeAsync(this.fillP2pGap(retryAttempt).finally(releasePullWork));
|
|
1770
1937
|
}, delayMs);
|
|
1771
1938
|
}
|
|
1772
1939
|
async fillP2pGap(retryAttempt = 0) {
|
|
@@ -2075,9 +2242,36 @@ export class MessageDeliveryEngine {
|
|
|
2075
2242
|
if (!groupId)
|
|
2076
2243
|
return;
|
|
2077
2244
|
const ns = `group:${groupId}`;
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2245
|
+
const targets = this.onlineUnreadHintTargets ?? new Map();
|
|
2246
|
+
const owners = this.onlineUnreadHintOwners ?? new Set();
|
|
2247
|
+
this.onlineUnreadHintTargets = targets;
|
|
2248
|
+
this.onlineUnreadHintOwners = owners;
|
|
2249
|
+
targets.set(ns, Math.max(targets.get(ns) ?? 0, positiveSafeSequenceHint(data.seq)));
|
|
2250
|
+
if (owners.has(ns))
|
|
2251
|
+
return;
|
|
2252
|
+
owners.add(ns);
|
|
2253
|
+
client._safeAsync((async () => {
|
|
2254
|
+
try {
|
|
2255
|
+
while (true) {
|
|
2256
|
+
const throughSeq = targets.get(ns) ?? 0;
|
|
2257
|
+
const ackBefore = this.syncState(ns).ack;
|
|
2258
|
+
await this.runGroupForwardRecovery(groupId, ns, 50, true, throughSeq);
|
|
2259
|
+
const ackAfter = this.syncState(ns).ack;
|
|
2260
|
+
const target = targets.get(ns) ?? 0;
|
|
2261
|
+
if (ackAfter >= target || ackAfter <= ackBefore)
|
|
2262
|
+
return;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
catch (exc) {
|
|
2266
|
+
client._clientLog?.debug(`online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
2267
|
+
}
|
|
2268
|
+
finally {
|
|
2269
|
+
if (this.onlineUnreadHintTargets === targets)
|
|
2270
|
+
targets.delete(ns);
|
|
2271
|
+
if (this.onlineUnreadHintOwners === owners)
|
|
2272
|
+
owners.delete(ns);
|
|
2273
|
+
}
|
|
2274
|
+
})());
|
|
2081
2275
|
}
|
|
2082
2276
|
enqueueOnlineUnreadEventHint(data) {
|
|
2083
2277
|
const client = this.runtime.client;
|
|
@@ -2109,17 +2303,19 @@ export class MessageDeliveryEngine {
|
|
|
2109
2303
|
const key = pipeline.pullGateKeyForCall('message.pull', request);
|
|
2110
2304
|
return await pipeline.runPullSerialized(key, invoke, background);
|
|
2111
2305
|
}
|
|
2112
|
-
async runGroupForwardRecovery(groupId, ns, pageLimit, background = false) {
|
|
2306
|
+
async runGroupForwardRecovery(groupId, ns, pageLimit, background = false, throughSeq = 0) {
|
|
2113
2307
|
const client = this.runtime.client;
|
|
2308
|
+
const state = this.syncState(ns);
|
|
2309
|
+
const maxPages = this.forwardMaxPages(state.ack, throughSeq, pageLimit);
|
|
2114
2310
|
const request = {
|
|
2115
2311
|
group_id: groupId,
|
|
2116
|
-
after_seq:
|
|
2312
|
+
after_seq: state.ack,
|
|
2117
2313
|
limit: pageLimit,
|
|
2118
|
-
max_pages:
|
|
2314
|
+
max_pages: maxPages,
|
|
2119
2315
|
};
|
|
2120
2316
|
const invoke = async () => {
|
|
2121
2317
|
const after = this.syncState(ns).ack;
|
|
2122
|
-
const messages = await client._pullGroupV2(groupId, after, pageLimit, { gateLocked: true, maxPages
|
|
2318
|
+
const messages = await client._pullGroupV2(groupId, after, pageLimit, { gateLocked: true, maxPages });
|
|
2123
2319
|
return { messages, raw_count: messages.length };
|
|
2124
2320
|
};
|
|
2125
2321
|
const pipeline = client._rpcPipeline;
|
|
@@ -2135,6 +2331,10 @@ export class MessageDeliveryEngine {
|
|
|
2135
2331
|
const ack = Number(tracker.getContiguousSeq(ns) || 0);
|
|
2136
2332
|
return { ack, tail: ack, head: Math.max(ack, Number(tracker.getMaxSeenSeq?.(ns) || 0)) };
|
|
2137
2333
|
}
|
|
2334
|
+
forwardMaxPages(ack, throughSeq, pageLimit) {
|
|
2335
|
+
const limit = Number.isSafeInteger(pageLimit) && pageLimit > 0 ? pageLimit : 1;
|
|
2336
|
+
return Math.max(1, Math.ceil(Math.max(0, throughSeq - ack) / limit));
|
|
2337
|
+
}
|
|
2138
2338
|
inlineMessage(data) {
|
|
2139
2339
|
if (!isJsonObject(data))
|
|
2140
2340
|
return null;
|
|
@@ -2434,7 +2634,7 @@ export class MessageDeliveryEngine {
|
|
|
2434
2634
|
? tracker.snapshotNamespace(ns)
|
|
2435
2635
|
: null;
|
|
2436
2636
|
try {
|
|
2437
|
-
const published = await this.publishPulledMessage(event, ns, seq, payload);
|
|
2637
|
+
const published = await this.publishPulledMessage(event, ns, seq, payload, true, 'inline_push');
|
|
2438
2638
|
if (!this.isInlineGenerationCurrent(generation))
|
|
2439
2639
|
return false;
|
|
2440
2640
|
if (!published)
|
|
@@ -2642,16 +2842,24 @@ export class MessageDeliveryEngine {
|
|
|
2642
2842
|
// 落盘的 ack 为起点,至多补一页普通 Forward 即可恢复该小窗口。
|
|
2643
2843
|
const tailMissedDuringPull = tailCompleted
|
|
2644
2844
|
&& Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
2845
|
+
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
2645
2846
|
const pendingThroughSeq = tailMissedDuringPull
|
|
2646
|
-
?
|
|
2847
|
+
? maxSeen
|
|
2647
2848
|
: 0;
|
|
2648
2849
|
const tailForward = tailCompleted && (state.ack < state.tail - 1 || tailMissedDuringPull);
|
|
2649
2850
|
const backgroundWindowForward = order[0] === 'forward' && !headForward;
|
|
2650
2851
|
if (headForward || tailForward
|
|
2651
2852
|
|| (client._sessionOptions?.background_sync !== false && backgroundWindowForward)) {
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2853
|
+
const forwardTarget = Math.max(headForward ? Math.max(pushSeq, maxSeen) : 0, (tailForward || backgroundWindowForward) ? state.tail - 1 : 0, tailMissedDuringPull ? maxSeen : 0);
|
|
2854
|
+
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
2855
|
+
result = await run(false, !(headForward || tailForward), forwardMaxPages, headForward || tailMissedDuringPull);
|
|
2856
|
+
if (pendingThroughSeq > 0) {
|
|
2857
|
+
const committedAck = this.syncState(ns).ack;
|
|
2858
|
+
if (committedAck >= pendingThroughSeq)
|
|
2859
|
+
this.consumePendingPull(ns, pendingThroughSeq);
|
|
2860
|
+
else if (committedAck <= state.ack)
|
|
2861
|
+
this.markPendingPullNoProgress(ns, committedAck);
|
|
2862
|
+
}
|
|
2655
2863
|
}
|
|
2656
2864
|
const finalState = this.syncState(ns);
|
|
2657
2865
|
if (tailCompleted && finalState.ack < finalState.tail - 1) {
|
|
@@ -2706,16 +2914,24 @@ export class MessageDeliveryEngine {
|
|
|
2706
2914
|
// 期间新到达的序号;绝不重新规划或再执行 Tail。
|
|
2707
2915
|
const tailMissedDuringPull = tailCompleted
|
|
2708
2916
|
&& Number(client._seqTracker.getMaxSeenSeq(ns) || 0) > state.head;
|
|
2917
|
+
const maxSeen = Number(client._seqTracker.getMaxSeenSeq(ns) || 0);
|
|
2709
2918
|
const pendingThroughSeq = tailMissedDuringPull
|
|
2710
|
-
?
|
|
2919
|
+
? maxSeen
|
|
2711
2920
|
: 0;
|
|
2712
2921
|
const tailForward = tailCompleted && (state.ack < state.tail - 1 || tailMissedDuringPull);
|
|
2713
2922
|
const backgroundWindowForward = order[0] === 'forward' && !headForward;
|
|
2714
2923
|
if (headForward || tailForward
|
|
2715
2924
|
|| (client._sessionOptions?.background_sync !== false && backgroundWindowForward)) {
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2925
|
+
const forwardTarget = Math.max(headForward ? Math.max(pushSeq, maxSeen) : 0, (tailForward || backgroundWindowForward) ? state.tail - 1 : 0, tailMissedDuringPull ? maxSeen : 0);
|
|
2926
|
+
const forwardMaxPages = this.forwardMaxPages(state.ack, forwardTarget, pageLimit);
|
|
2927
|
+
result = await run(false, !(headForward || tailForward), forwardMaxPages, headForward || tailMissedDuringPull);
|
|
2928
|
+
if (pendingThroughSeq > 0) {
|
|
2929
|
+
const committedAck = this.syncState(ns).ack;
|
|
2930
|
+
if (committedAck >= pendingThroughSeq)
|
|
2931
|
+
this.consumePendingPull(ns, pendingThroughSeq);
|
|
2932
|
+
else if (committedAck <= state.ack)
|
|
2933
|
+
this.markPendingPullNoProgress(ns, committedAck);
|
|
2934
|
+
}
|
|
2719
2935
|
}
|
|
2720
2936
|
const finalState = this.syncState(ns);
|
|
2721
2937
|
if (tailCompleted && finalState.ack < finalState.tail - 1) {
|
|
@@ -2998,13 +3214,13 @@ export class MessageDeliveryEngine {
|
|
|
2998
3214
|
}
|
|
2999
3215
|
}
|
|
3000
3216
|
catch (exc) {
|
|
3001
|
-
client._dispatcher.
|
|
3217
|
+
client._dispatcher.enqueue('seq_tracker.persist_error', {
|
|
3002
3218
|
phase: 'restore',
|
|
3003
3219
|
aid,
|
|
3004
3220
|
device_id: deviceId,
|
|
3005
3221
|
slot_id: slotId,
|
|
3006
3222
|
error: String(exc),
|
|
3007
|
-
})
|
|
3223
|
+
});
|
|
3008
3224
|
}
|
|
3009
3225
|
}
|
|
3010
3226
|
async migrateSeqStateGroupIds(state) {
|
|
@@ -3212,13 +3428,13 @@ export class MessageDeliveryEngine {
|
|
|
3212
3428
|
catch (exc) {
|
|
3213
3429
|
const error = formatDeliveryError(exc);
|
|
3214
3430
|
client._clientLog.warn(`save SeqTracker state failed: ${error}`);
|
|
3215
|
-
client._dispatcher.
|
|
3431
|
+
client._dispatcher.enqueue('seq_tracker.persist_error', {
|
|
3216
3432
|
phase: 'save',
|
|
3217
3433
|
aid,
|
|
3218
3434
|
device_id: deviceId,
|
|
3219
3435
|
slot_id: slotId,
|
|
3220
3436
|
error: String(error),
|
|
3221
|
-
})
|
|
3437
|
+
});
|
|
3222
3438
|
if (throwOnError)
|
|
3223
3439
|
throw exc;
|
|
3224
3440
|
}
|
|
@@ -3337,8 +3553,9 @@ export class MessageDeliveryEngine {
|
|
|
3337
3553
|
}
|
|
3338
3554
|
return params;
|
|
3339
3555
|
}
|
|
3340
|
-
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true) {
|
|
3556
|
+
async drainOrderedMessages(ns, beforeSeq, pullResponse = false, persist = true, batch, source = 'pull') {
|
|
3341
3557
|
const client = this.runtime.client;
|
|
3558
|
+
this.ensurePullOperationCurrent();
|
|
3342
3559
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3343
3560
|
if (!queue || queue.size === 0)
|
|
3344
3561
|
return;
|
|
@@ -3347,83 +3564,128 @@ export class MessageDeliveryEngine {
|
|
|
3347
3564
|
.filter((seq) => seq <= contig && (beforeSeq === undefined || seq < beforeSeq))
|
|
3348
3565
|
.sort((a, b) => a - b);
|
|
3349
3566
|
let delivered = false;
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3567
|
+
const drainBatches = new Map();
|
|
3568
|
+
try {
|
|
3569
|
+
for (const seq of ready) {
|
|
3570
|
+
this.ensurePullOperationCurrent();
|
|
3571
|
+
const item = queue.get(seq);
|
|
3572
|
+
queue.delete(seq);
|
|
3573
|
+
if (!item || client._pushedSeqs.get(ns)?.has(seq))
|
|
3574
|
+
continue;
|
|
3575
|
+
const itemSource = item.source ?? source;
|
|
3576
|
+
let itemBatch = batch;
|
|
3577
|
+
if ((itemSource === 'push' || itemSource === 'inline_push')
|
|
3578
|
+
&& (!batch || batch.trigger !== itemSource)) {
|
|
3579
|
+
itemBatch = drainBatches.get(itemSource);
|
|
3580
|
+
if (!itemBatch) {
|
|
3581
|
+
itemBatch = this.createDeliveryChangeBatch(itemSource);
|
|
3582
|
+
drainBatches.set(itemSource, itemBatch);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
await this.publishOrderedQueueItem(ns, item.event, seq, item.payload, pullResponse, itemSource, itemBatch);
|
|
3586
|
+
this.ensurePullOperationCurrent();
|
|
3587
|
+
this.markPublishedSeq(ns, seq);
|
|
3588
|
+
delivered = true;
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
finally {
|
|
3592
|
+
for (const drainBatch of drainBatches.values()) {
|
|
3593
|
+
await this.flushRealtimeDeliveryChanges(drainBatch);
|
|
3594
|
+
}
|
|
3358
3595
|
}
|
|
3359
3596
|
if (queue.size === 0) {
|
|
3360
3597
|
client._pendingOrderedMsgs.delete(ns);
|
|
3361
|
-
if (delivered && persist)
|
|
3598
|
+
if (delivered && persist) {
|
|
3599
|
+
this.ensurePullOperationCurrent();
|
|
3362
3600
|
await this.saveSeqTrackerState();
|
|
3601
|
+
}
|
|
3363
3602
|
}
|
|
3364
3603
|
}
|
|
3365
|
-
async publishOrderedMessage(event, ns, seq, payload) {
|
|
3604
|
+
async publishOrderedMessage(event, ns, seq, payload, source = 'push', operationBatch) {
|
|
3366
3605
|
const client = this.runtime.client;
|
|
3367
|
-
const
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3606
|
+
const ownsBatch = !operationBatch && (source === 'push' || source === 'inline_push');
|
|
3607
|
+
const batch = operationBatch ?? (ownsBatch ? this.createDeliveryChangeBatch(source) : undefined);
|
|
3608
|
+
try {
|
|
3609
|
+
const seqNum = Number(seq);
|
|
3610
|
+
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0) {
|
|
3611
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, false, source, batch);
|
|
3612
|
+
return true;
|
|
3613
|
+
}
|
|
3614
|
+
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
3615
|
+
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3616
|
+
queue?.delete(seqNum);
|
|
3617
|
+
if (queue && queue.size === 0)
|
|
3618
|
+
client._pendingOrderedMsgs.delete(ns);
|
|
3619
|
+
return false;
|
|
3620
|
+
}
|
|
3621
|
+
const contig = client._seqTracker.getContiguousSeq(ns);
|
|
3622
|
+
if (seqNum > contig) {
|
|
3623
|
+
this.enqueueOrderedMessage(ns, event, seqNum, payload, source);
|
|
3624
|
+
return false;
|
|
3625
|
+
}
|
|
3626
|
+
await this.drainOrderedMessages(ns, seqNum, true, true, batch, source);
|
|
3627
|
+
if (client._pushedSeqs.get(ns)?.has(seqNum))
|
|
3628
|
+
return false;
|
|
3373
3629
|
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3374
3630
|
queue?.delete(seqNum);
|
|
3375
3631
|
if (queue && queue.size === 0)
|
|
3376
3632
|
client._pendingOrderedMsgs.delete(ns);
|
|
3377
|
-
|
|
3633
|
+
await this.publishOrderedQueueItem(ns, event, seqNum, payload, false, source, batch);
|
|
3634
|
+
this.markPublishedSeq(ns, seqNum);
|
|
3635
|
+
await this.drainOrderedMessages(ns, undefined, false, true, batch, source);
|
|
3636
|
+
if (!client._pendingOrderedMsgs.get(ns))
|
|
3637
|
+
await this.saveSeqTrackerState();
|
|
3638
|
+
return true;
|
|
3378
3639
|
}
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
return false;
|
|
3640
|
+
finally {
|
|
3641
|
+
if (ownsBatch && batch)
|
|
3642
|
+
await this.flushRealtimeDeliveryChanges(batch);
|
|
3383
3643
|
}
|
|
3384
|
-
await this.drainOrderedMessages(ns, seqNum, true);
|
|
3385
|
-
if (client._pushedSeqs.get(ns)?.has(seqNum))
|
|
3386
|
-
return false;
|
|
3387
|
-
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3388
|
-
queue?.delete(seqNum);
|
|
3389
|
-
if (queue && queue.size === 0)
|
|
3390
|
-
client._pendingOrderedMsgs.delete(ns);
|
|
3391
|
-
await this.publishOrderedQueueItem(ns, event, seqNum, payload);
|
|
3392
|
-
this.markPublishedSeq(ns, seqNum);
|
|
3393
|
-
await this.drainOrderedMessages(ns);
|
|
3394
|
-
if (!client._pendingOrderedMsgs.get(ns))
|
|
3395
|
-
await this.saveSeqTrackerState();
|
|
3396
|
-
return true;
|
|
3397
3644
|
}
|
|
3398
|
-
async publishPulledMessage(event, ns, seq, payload, persist = true) {
|
|
3645
|
+
async publishPulledMessage(event, ns, seq, payload, persist = true, source = 'pull', operationBatch) {
|
|
3399
3646
|
const client = this.runtime.client;
|
|
3400
|
-
const
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3647
|
+
const ownsBatch = !operationBatch && (source === 'push' || source === 'inline_push');
|
|
3648
|
+
const batch = operationBatch ?? (ownsBatch ? this.createDeliveryChangeBatch(source) : undefined);
|
|
3649
|
+
try {
|
|
3650
|
+
this.ensurePullOperationCurrent();
|
|
3651
|
+
const seqNum = Number(seq);
|
|
3652
|
+
if (!Number.isFinite(seqNum) || !Number.isInteger(seqNum) || seqNum <= 0 || !ns) {
|
|
3653
|
+
if (event === 'message.recalled') {
|
|
3654
|
+
const published = await client._withPullResponseProcessing(ns, () => this.publishMessageRecallTombstone(seq, payload));
|
|
3655
|
+
this.ensurePullOperationCurrent();
|
|
3656
|
+
return published;
|
|
3657
|
+
}
|
|
3658
|
+
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
3659
|
+
this.ensurePullOperationCurrent();
|
|
3660
|
+
return true;
|
|
3404
3661
|
}
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3662
|
+
const queue = client._pendingOrderedMsgs.get(ns);
|
|
3663
|
+
if (client._pushedSeqs.get(ns)?.has(seqNum)) {
|
|
3664
|
+
queue?.delete(seqNum);
|
|
3665
|
+
if (queue && queue.size === 0)
|
|
3666
|
+
client._pendingOrderedMsgs.delete(ns);
|
|
3667
|
+
return false;
|
|
3668
|
+
}
|
|
3669
|
+
await this.drainOrderedMessages(ns, seqNum, false, persist, batch, source);
|
|
3670
|
+
this.ensurePullOperationCurrent();
|
|
3410
3671
|
queue?.delete(seqNum);
|
|
3411
3672
|
if (queue && queue.size === 0)
|
|
3412
3673
|
client._pendingOrderedMsgs.delete(ns);
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3674
|
+
if (event === 'message.recalled') {
|
|
3675
|
+
const published = await client._withPullResponseProcessing(ns, () => this.publishMessageRecallTombstone(seqNum, payload));
|
|
3676
|
+
this.ensurePullOperationCurrent();
|
|
3677
|
+
this.markPublishedSeq(ns, seqNum);
|
|
3678
|
+
return published;
|
|
3679
|
+
}
|
|
3680
|
+
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload, source, ns, batch));
|
|
3681
|
+
this.ensurePullOperationCurrent();
|
|
3421
3682
|
this.markPublishedSeq(ns, seqNum);
|
|
3422
|
-
return
|
|
3683
|
+
return true;
|
|
3684
|
+
}
|
|
3685
|
+
finally {
|
|
3686
|
+
if (ownsBatch && batch)
|
|
3687
|
+
await this.flushRealtimeDeliveryChanges(batch);
|
|
3423
3688
|
}
|
|
3424
|
-
await client._withPullResponseProcessing(ns, () => client._publishAppEvent(event, payload));
|
|
3425
|
-
this.markPublishedSeq(ns, seqNum);
|
|
3426
|
-
return true;
|
|
3427
3689
|
}
|
|
3428
3690
|
}
|
|
3429
3691
|
//# sourceMappingURL=delivery.js.map
|