@agentunion/fastaun 0.5.33 → 0.5.35
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 +59 -2
- package/README.md +28 -26
- package/_packed_docs/CHANGELOG.md +59 -2
- package/_packed_docs/INDEX.md +26 -12
- package/_packed_docs/KITE_DOCS_GUIDE.md +17 -11
- package/_packed_docs/agent.md/SCHEMA.md +1 -1
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +2 -2
- package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +58 -8
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +17 -17
- package/_packed_docs/protocol/echo-probe-gateway.md +99 -0
- package/_packed_docs/protocol/echo-probe-sdk.md +91 -0
- package/_packed_docs/sdk/0.5.33-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +464 -316
- package/_packed_docs/sdk/0.5.33-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +499 -304
- package/_packed_docs/sdk/0.5.34-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +133 -0
- package/_packed_docs/sdk/0.5.34-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +107 -0
- package/_packed_docs/sdk/0.5.35-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +189 -0
- package/_packed_docs/sdk/0.5.35-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +204 -0
- package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +16 -13
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +13 -1
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +19 -9
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +87 -20
- package/_packed_docs/sdk/09-collab-rpc-manual.md +48 -30
- package/_packed_docs/sdk/09-custody-api-manual.md +3 -3
- package/_packed_docs/sdk/09-group-rpc-manual.md +60 -13
- package/_packed_docs/sdk/09-message-rpc-manual.md +22 -0
- package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -1
- package/_packed_docs/sdk/09-payload-reference.md +9 -8
- package/_packed_docs/sdk/09-proxy-rpc-manual.md +20 -14
- package/_packed_docs/sdk/09-storage-rpc-manual.md +1698 -1659
- package/_packed_docs/sdk/09-stream-rpc-manual.md +33 -20
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +19 -17
- package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +125 -30
- package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/274/200/345/217/221/347/247/273/346/244/215/346/214/207/345/215/227.md +109 -33
- package/_packed_docs/sdk/INDEX.md +30 -18
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +1 -1
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +5 -5
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +5 -5
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +9 -9
- package/_packed_docs/sdk/README.md +11 -6
- package/_packed_docs//346/266/210/346/201/257/345/274/271/346/200/247/350/241/245/346/213/211/351/200/232/351/201/223/345/256/236/346/226/275/350/256/241/345/210/222.md +400 -0
- package/_packed_docs//346/266/210/346/201/257/345/274/271/346/200/247/350/241/245/346/213/211/351/200/232/351/201/223/346/226/271/346/241/210.md +485 -0
- package/dist/auth.js +39 -45
- package/dist/auth.js.map +1 -1
- package/dist/client/control-messages.js +2 -2
- package/dist/client/control-messages.js.map +1 -1
- package/dist/client/delivery.d.ts +12 -1
- package/dist/client/delivery.js +281 -46
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/lifecycle.js +13 -1
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-budget.d.ts +21 -0
- package/dist/client/rpc-budget.js +82 -0
- package/dist/client/rpc-budget.js.map +1 -0
- package/dist/client/rpc-pipeline.d.ts +5 -0
- package/dist/client/rpc-pipeline.js +227 -63
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/sync-channels.d.ts +90 -0
- package/dist/client/sync-channels.js +508 -0
- package/dist/client/sync-channels.js.map +1 -0
- package/dist/client/v2-e2ee.d.ts +5 -1
- package/dist/client/v2-e2ee.js +420 -303
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +17 -0
- package/dist/client.js +373 -50
- package/dist/client.js.map +1 -1
- package/dist/events.d.ts +1 -0
- package/dist/events.js +5 -0
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mail-client.d.ts +101 -0
- package/dist/mail-client.js +369 -0
- package/dist/mail-client.js.map +1 -0
- package/dist/pubsub/binding.js +23 -3
- package/dist/pubsub/binding.js.map +1 -1
- package/dist/pubsub/channel.d.ts +15 -3
- package/dist/pubsub/channel.js +114 -7
- package/dist/pubsub/channel.js.map +1 -1
- package/dist/pubsub/client.d.ts +17 -2
- package/dist/pubsub/client.js +205 -40
- package/dist/pubsub/client.js.map +1 -1
- package/dist/pubsub/credentials.d.ts +3 -0
- package/dist/pubsub/credentials.js +57 -20
- package/dist/pubsub/credentials.js.map +1 -1
- package/dist/pubsub/index.d.ts +5 -2
- package/dist/pubsub/index.js +70 -54
- package/dist/pubsub/index.js.map +1 -1
- package/dist/pubsub/service.d.ts +9 -0
- package/dist/pubsub/service.js +266 -20
- package/dist/pubsub/service.js.map +1 -1
- package/dist/pubsub/types.d.ts +13 -1
- package/dist/storage/lowlevel.d.ts +3 -1
- package/dist/storage/lowlevel.js +13 -0
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/types.d.ts +10 -0
- package/dist/storage/types.js.map +1 -1
- package/dist/storage/vfs.d.ts +3 -1
- package/dist/storage/vfs.js +2 -2
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +55 -5
- package/dist/tools/cross-sdk-agent.js +88 -21
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +16 -0
- package/dist/transport.js +129 -7
- package/dist/transport.js.map +1 -1
- package/dist/udp-standby.d.ts +89 -0
- package/dist/udp-standby.js +487 -0
- package/dist/udp-standby.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
- package/scripts/patch-imapflow-external.mjs +69 -0
package/dist/client/delivery.js
CHANGED
|
@@ -14,6 +14,11 @@ const GROUP_RECALL_SEEN_LIMIT = 10_000;
|
|
|
14
14
|
const VOLATILE_SEEN_LIMIT = 10_000;
|
|
15
15
|
const SEQ_TRACKER_PERSIST_FLUSH_DELAY_MS = 200;
|
|
16
16
|
const BACKGROUND_PULL_RETRY_DELAY_MS = 250;
|
|
17
|
+
function isOversizedPullError(error) {
|
|
18
|
+
const failure = error;
|
|
19
|
+
return [failure?.data?.code, failure?.data?.reason, failure?.stringCode].includes('OVERSIZED_MESSAGE')
|
|
20
|
+
|| String(failure?.message ?? '').includes('OVERSIZED_MESSAGE');
|
|
21
|
+
}
|
|
17
22
|
function isTerminalGroupPullError(error) {
|
|
18
23
|
if (!error || typeof error !== 'object')
|
|
19
24
|
return false;
|
|
@@ -99,9 +104,73 @@ function deduplicatePlainForwardPageMessages(value, afterSeq) {
|
|
|
99
104
|
}
|
|
100
105
|
export class MessageDeliveryEngine {
|
|
101
106
|
runtime;
|
|
107
|
+
forwardAckJobs = new Map();
|
|
108
|
+
forwardAckTasks = new Set();
|
|
109
|
+
scheduleForwardAck(ns, seq, send) {
|
|
110
|
+
const client = this.runtime.client;
|
|
111
|
+
if (client._closing || seq <= 0)
|
|
112
|
+
return;
|
|
113
|
+
const scope = () => [client._aid, client._deviceId, client._slotId, this.captureInlineAckGeneration(),
|
|
114
|
+
client._v2RuntimeGeneration, client._transport, client._transport?._connectionGeneration,
|
|
115
|
+
client._transport?._workerGeneration, this.captureSeqNamespaceGeneration(ns)];
|
|
116
|
+
const current = scope();
|
|
117
|
+
const previous = this.forwardAckJobs.get(ns);
|
|
118
|
+
if (previous && previous.scope.every((value, i) => value === current[i])) {
|
|
119
|
+
if (seq > previous.seq) {
|
|
120
|
+
previous.seq = seq;
|
|
121
|
+
previous.send = send;
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const job = { seq, scope: current, send };
|
|
126
|
+
this.forwardAckJobs.set(ns, job);
|
|
127
|
+
const isCurrent = () => this.forwardAckJobs.get(ns) === job && job.scope.every((value, i) => value === scope()[i]);
|
|
128
|
+
const task = (async () => {
|
|
129
|
+
let failures = 0;
|
|
130
|
+
while (isCurrent()) {
|
|
131
|
+
const pending = job.seq;
|
|
132
|
+
try {
|
|
133
|
+
await job.send(pending);
|
|
134
|
+
failures = 0;
|
|
135
|
+
if (job.seq <= pending) {
|
|
136
|
+
if (this.forwardAckJobs.get(ns) === job)
|
|
137
|
+
this.forwardAckJobs.delete(ns);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
if (!isCurrent() || client._closing || client.state !== ConnectionState.READY)
|
|
143
|
+
return;
|
|
144
|
+
if (job.seq <= pending)
|
|
145
|
+
await new Promise(resolve => setTimeout(resolve, Math.min(100 * 2 ** Math.min(failures++, 5), 3000)));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
})().finally(() => {
|
|
149
|
+
if (this.forwardAckJobs.get(ns) === job)
|
|
150
|
+
this.forwardAckJobs.delete(ns);
|
|
151
|
+
this.forwardAckTasks.delete(task);
|
|
152
|
+
});
|
|
153
|
+
this.forwardAckTasks.add(task);
|
|
154
|
+
}
|
|
155
|
+
drainForwardAcks() {
|
|
156
|
+
if (!this.forwardAckTasks.size)
|
|
157
|
+
return;
|
|
158
|
+
return this.waitForwardAcks();
|
|
159
|
+
}
|
|
160
|
+
async waitForwardAcks() {
|
|
161
|
+
let timer;
|
|
162
|
+
try {
|
|
163
|
+
await Promise.race([Promise.allSettled([...this.forwardAckTasks]), new Promise(resolve => { timer = setTimeout(resolve, 1000); })]);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
if (timer)
|
|
167
|
+
clearTimeout(timer);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
102
170
|
realtimeTailHeads = null;
|
|
103
171
|
realtimeSyncing = null;
|
|
104
172
|
pendingGroupPullUpper = null;
|
|
173
|
+
pendingV2GroupPulls = new Set();
|
|
105
174
|
onlineUnreadHintTargets = null;
|
|
106
175
|
onlineUnreadHintTasks = null;
|
|
107
176
|
backgroundPullNeeds = new Map();
|
|
@@ -135,6 +204,9 @@ export class MessageDeliveryEngine {
|
|
|
135
204
|
seqTrackerNamespaceGenerations = new Map();
|
|
136
205
|
peerRecoveryTasks = new Map();
|
|
137
206
|
peerRecoveryNeeds = new Map();
|
|
207
|
+
peerVolatileNeeds = new Set();
|
|
208
|
+
peerVolatileTask = null;
|
|
209
|
+
oversizedPulls = new Set();
|
|
138
210
|
peerForwardNeeds = new Map();
|
|
139
211
|
peerPushVersions = new Map();
|
|
140
212
|
peerCatalogVersion = null;
|
|
@@ -163,6 +235,7 @@ export class MessageDeliveryEngine {
|
|
|
163
235
|
this.automaticPullFailures.clear();
|
|
164
236
|
this.terminalGroupPulls.clear();
|
|
165
237
|
this.groupPullVersions.clear();
|
|
238
|
+
this.oversizedPulls.clear();
|
|
166
239
|
}
|
|
167
240
|
groupPullNamespace(namespace) {
|
|
168
241
|
let groupId = namespace.startsWith('group_event:') ? namespace.slice('group_event:'.length)
|
|
@@ -267,6 +340,17 @@ export class MessageDeliveryEngine {
|
|
|
267
340
|
catch (error) {
|
|
268
341
|
if (!groupCurrent())
|
|
269
342
|
throw new Error('pull invalidated');
|
|
343
|
+
if (!signal.aborted && generation === this.captureInlineAckGeneration() && isOversizedPullError(error)) {
|
|
344
|
+
this.oversizedPulls.add(namespace);
|
|
345
|
+
this.automaticPullFailures.delete(namespace);
|
|
346
|
+
this.backgroundPullNeeds.delete(namespace);
|
|
347
|
+
const peer = this.peerRecoveryNeeds.get(this.peerSender(namespace));
|
|
348
|
+
if (peer)
|
|
349
|
+
peer.paused = true;
|
|
350
|
+
if (this.groupPullNamespace(namespace))
|
|
351
|
+
this.stopAutomaticGroupPull(namespace, error);
|
|
352
|
+
throw error;
|
|
353
|
+
}
|
|
270
354
|
if (!signal.aborted && generation === this.captureInlineAckGeneration()
|
|
271
355
|
&& this.groupPullNamespace(namespace) && isTerminalGroupPullError(error)) {
|
|
272
356
|
this.stopAutomaticGroupPull(namespace, error);
|
|
@@ -471,6 +555,8 @@ export class MessageDeliveryEngine {
|
|
|
471
555
|
this.peerPullConfirmedThrough.clear();
|
|
472
556
|
this.peerServerConfirmedAcks.clear();
|
|
473
557
|
this.peerRecoveryTasks.clear();
|
|
558
|
+
this.peerVolatileNeeds.clear();
|
|
559
|
+
this.peerVolatileTask = null;
|
|
474
560
|
this.settledDeliveries.clear();
|
|
475
561
|
this.deliveryInflight.clear();
|
|
476
562
|
this.peerCatalogTask = null;
|
|
@@ -791,6 +877,8 @@ export class MessageDeliveryEngine {
|
|
|
791
877
|
}
|
|
792
878
|
refreshPendingPeers() {
|
|
793
879
|
this.ensurePeerContext();
|
|
880
|
+
if (this.oversizedPulls.has('message.peers'))
|
|
881
|
+
return;
|
|
794
882
|
this.peerCatalogVersion = {};
|
|
795
883
|
if (!this.hasP2pApplicationSubscription())
|
|
796
884
|
return;
|
|
@@ -818,15 +906,57 @@ export class MessageDeliveryEngine {
|
|
|
818
906
|
}
|
|
819
907
|
})();
|
|
820
908
|
this.peerCatalogTask = task.then(() => ({}), () => ({}));
|
|
821
|
-
client._safeAsync(task.catch(() => {
|
|
909
|
+
client._safeAsync(task.catch((error) => {
|
|
822
910
|
if (generation !== this.captureInlineAckGeneration())
|
|
823
911
|
return;
|
|
912
|
+
if (isOversizedPullError(error))
|
|
913
|
+
return;
|
|
824
914
|
const timer = setTimeout(() => { if (generation === this.captureInlineAckGeneration())
|
|
825
915
|
this.refreshPendingPeers(); }, BACKGROUND_PULL_RETRY_DELAY_MS);
|
|
826
916
|
timer.unref?.();
|
|
827
917
|
}).finally(() => { if (generation === this.captureInlineAckGeneration())
|
|
828
918
|
this.peerCatalogTask = null; }));
|
|
829
919
|
}
|
|
920
|
+
schedulePeerVolatileRecovery(sender) {
|
|
921
|
+
const client = this.runtime.client;
|
|
922
|
+
const namespace = `${this.peerNamespace(sender)}|volatile`;
|
|
923
|
+
if (this.oversizedPulls.has(namespace))
|
|
924
|
+
return;
|
|
925
|
+
this.peerVolatileNeeds.add(sender);
|
|
926
|
+
if (this.peerVolatileTask)
|
|
927
|
+
return;
|
|
928
|
+
const generation = this.captureInlineAckGeneration(), context = this.ensurePeerContext();
|
|
929
|
+
const current = () => generation === this.captureInlineAckGeneration() && context === this.ensurePeerContext();
|
|
930
|
+
const task = (async () => {
|
|
931
|
+
while (current() && this.peerVolatileNeeds.size && this.hasP2pApplicationSubscription()
|
|
932
|
+
&& client._sessionOptions?.background_sync !== false && !client._closing) {
|
|
933
|
+
const peer = this.peerVolatileNeeds.values().next().value;
|
|
934
|
+
this.peerVolatileNeeds.delete(peer);
|
|
935
|
+
try {
|
|
936
|
+
const result = await client._v2E2EE.pullPeerV2Volatile(peer, { background: true, retainMessages: false, maxPages: 1 });
|
|
937
|
+
if (!current())
|
|
938
|
+
return;
|
|
939
|
+
if (!result.complete)
|
|
940
|
+
this.peerVolatileNeeds.add(peer);
|
|
941
|
+
}
|
|
942
|
+
catch (error) {
|
|
943
|
+
if (!current())
|
|
944
|
+
return;
|
|
945
|
+
if (isOversizedPullError(error)) {
|
|
946
|
+
this.oversizedPulls.add(`${this.peerNamespace(peer)}|volatile`);
|
|
947
|
+
client._dispatcher.enqueue('sync.error', { namespace: `${this.peerNamespace(peer)}|volatile`, method: 'message.v2.pull', code: 'OVERSIZED_MESSAGE', error: String(error) });
|
|
948
|
+
}
|
|
949
|
+
else
|
|
950
|
+
client._safeAsync(Promise.reject(error));
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
})();
|
|
954
|
+
this.peerVolatileTask = task;
|
|
955
|
+
client._safeAsync(task.finally(() => {
|
|
956
|
+
if (current() && this.peerVolatileTask === task)
|
|
957
|
+
this.peerVolatileTask = null;
|
|
958
|
+
}));
|
|
959
|
+
}
|
|
830
960
|
schedulePeerRecovery(sender, head = 0, volatile = false) {
|
|
831
961
|
const client = this.runtime.client;
|
|
832
962
|
if (!sender || client._closing)
|
|
@@ -855,6 +985,11 @@ export class MessageDeliveryEngine {
|
|
|
855
985
|
this.peerForwardNeeds.set(namespace, {});
|
|
856
986
|
return;
|
|
857
987
|
}
|
|
988
|
+
if (volatile && client._syncChannelCoordinator?.needsSplit?.()
|
|
989
|
+
&& (this.peerRecoveryTasks.has(sender) || this.oversizedPulls.has(namespace)))
|
|
990
|
+
this.schedulePeerVolatileRecovery(sender);
|
|
991
|
+
if (this.oversizedPulls.has(namespace))
|
|
992
|
+
return;
|
|
858
993
|
const need = this.peerRecoveryNeeds.get(sender) ?? { head: 0, volatile: false, pending: false };
|
|
859
994
|
need.paused = false;
|
|
860
995
|
need.head = Math.max(need.head, head);
|
|
@@ -953,9 +1088,11 @@ export class MessageDeliveryEngine {
|
|
|
953
1088
|
}
|
|
954
1089
|
})();
|
|
955
1090
|
this.peerRecoveryTasks.set(sender, task);
|
|
956
|
-
client._safeAsync(task.catch(() => {
|
|
1091
|
+
client._safeAsync(task.catch((error) => {
|
|
957
1092
|
if (generation !== this.captureInlineAckGeneration())
|
|
958
1093
|
return;
|
|
1094
|
+
if (isOversizedPullError(error) || need.paused)
|
|
1095
|
+
return;
|
|
959
1096
|
const timer = setTimeout(() => {
|
|
960
1097
|
if (generation === this.captureInlineAckGeneration() && this.peerRecoveryNeeds.get(sender) === need
|
|
961
1098
|
&& !need.paused && !this.peerRecoveryTasks.has(sender))
|
|
@@ -1033,7 +1170,7 @@ export class MessageDeliveryEngine {
|
|
|
1033
1170
|
this.onGroupV2AckSucceeded(groupId, actualAckSeq, generation);
|
|
1034
1171
|
}
|
|
1035
1172
|
}
|
|
1036
|
-
async commitPlainForwardPage(ns, afterSeq, method, result, groupId = '') {
|
|
1173
|
+
async commitPlainForwardPage(ns, afterSeq, method, result, groupId = '', background = false) {
|
|
1037
1174
|
if (!isJsonObject(result)) {
|
|
1038
1175
|
throw new Error(`${method} response must be an object`);
|
|
1039
1176
|
}
|
|
@@ -1177,7 +1314,10 @@ export class MessageDeliveryEngine {
|
|
|
1177
1314
|
throw new Error(`${ackMethod} cannot confirm pending Forward watermark ${pendingAckSeq}`);
|
|
1178
1315
|
}
|
|
1179
1316
|
this.ensurePullOperationCurrent(ns);
|
|
1180
|
-
|
|
1317
|
+
if (background)
|
|
1318
|
+
this.scheduleForwardAck(ns, pendingAckSeq, seq => this.confirmPlainForwardAck(ns, ackMethod, seq, groupId));
|
|
1319
|
+
else
|
|
1320
|
+
await this.confirmPlainForwardAck(ns, ackMethod, pendingAckSeq, groupId);
|
|
1181
1321
|
}
|
|
1182
1322
|
this.syncProgress(ns, {
|
|
1183
1323
|
rawCount: messages.length,
|
|
@@ -1385,6 +1525,7 @@ export class MessageDeliveryEngine {
|
|
|
1385
1525
|
this.pendingGroupInlineAckNamespaces = null;
|
|
1386
1526
|
this.realtimeSyncing = null;
|
|
1387
1527
|
this.pendingGroupPullUpper = null;
|
|
1528
|
+
this.pendingV2GroupPulls.clear();
|
|
1388
1529
|
this.onlineUnreadHintTargets = null;
|
|
1389
1530
|
this.onlineUnreadHintTasks = null;
|
|
1390
1531
|
this.realtimeTailHeads = null;
|
|
@@ -1399,6 +1540,8 @@ export class MessageDeliveryEngine {
|
|
|
1399
1540
|
this.peerPullConfirmedThrough.clear();
|
|
1400
1541
|
this.peerServerConfirmedAcks.clear();
|
|
1401
1542
|
this.peerRecoveryTasks.clear();
|
|
1543
|
+
this.peerVolatileNeeds.clear();
|
|
1544
|
+
this.peerVolatileTask = null;
|
|
1402
1545
|
}
|
|
1403
1546
|
deliveryChangedNamespace(event, payload) {
|
|
1404
1547
|
if (event === 'group.message_created' && isJsonObject(payload)) {
|
|
@@ -1669,8 +1812,31 @@ export class MessageDeliveryEngine {
|
|
|
1669
1812
|
pendingPullUpper(ns) {
|
|
1670
1813
|
return this.pendingGroupPullUpper?.get(ns) ?? 0;
|
|
1671
1814
|
}
|
|
1815
|
+
pendingHistoryNamespaces() {
|
|
1816
|
+
const namespaces = new Set(), client = this.runtime.client, now = Date.now();
|
|
1817
|
+
for (const [sender, need] of this.peerRecoveryNeeds) {
|
|
1818
|
+
const ns = this.peerNamespace(sender);
|
|
1819
|
+
if (need.pending && !need.paused && !this.peerRecoveryTasks.has(sender) && !this.oversizedPulls.has(ns)
|
|
1820
|
+
&& (this.automaticPullFailures.get(ns)?.retryAt ?? 0) <= now)
|
|
1821
|
+
namespaces.add(ns);
|
|
1822
|
+
}
|
|
1823
|
+
for (const [ns, need] of this.backgroundPullNeeds) {
|
|
1824
|
+
if (need.messageClassRequest || need.retryAt > now || !(need.probe || need.hasMore)
|
|
1825
|
+
|| this.automaticGroupPullStopped(ns) || this.oversizedPulls.has(ns) || this.backgroundPullTasks.has(ns)
|
|
1826
|
+
|| this.realtimeSyncing?.has(ns) || this.onlineUnreadHintTasks?.has(ns))
|
|
1827
|
+
continue;
|
|
1828
|
+
const eventScope = ns.startsWith('group_event:');
|
|
1829
|
+
if ((!eventScope && client._rpcPipeline?.hasPullActivity?.(ns, false))
|
|
1830
|
+
|| (eventScope && ['pulling', 'processing', 'pulled'].includes(client._rpcPipeline?.getPullLifecycle?.(ns))))
|
|
1831
|
+
continue;
|
|
1832
|
+
if (ns.startsWith('group:') || eventScope || ns === `p2p:${client._aid}`)
|
|
1833
|
+
namespaces.add(ns);
|
|
1834
|
+
}
|
|
1835
|
+
return [...namespaces];
|
|
1836
|
+
}
|
|
1672
1837
|
hasAnyPendingPull() {
|
|
1673
1838
|
return this.peerCatalogDirty || [...this.peerRecoveryNeeds.values()].some((need) => !need.paused) || this.peerRecoveryTasks.size > 0 || Boolean(this.peerCatalogTask)
|
|
1839
|
+
|| Boolean(this.peerVolatileTask) || this.peerVolatileNeeds.size > 0
|
|
1674
1840
|
|| [...(this.pendingGroupPullUpper?.values() ?? [])].some((seq) => seq > 0)
|
|
1675
1841
|
|| [...this.backgroundPullNeeds.values()].some((need) => need.retryAt !== Infinity)
|
|
1676
1842
|
|| Boolean(this.onlineUnreadHintTasks?.size)
|
|
@@ -1696,7 +1862,7 @@ export class MessageDeliveryEngine {
|
|
|
1696
1862
|
return;
|
|
1697
1863
|
this.ensurePeerContext();
|
|
1698
1864
|
const ns = `message_class/${params.message_class}/${group ? params.volatile ? 'volatile_group' : 'group' : 'peer'}/${group ? params.group_id ?? params.group_aid : params.sender_aid}`;
|
|
1699
|
-
if (this.automaticGroupPullStopped(ns))
|
|
1865
|
+
if (this.automaticGroupPullStopped(ns) || this.oversizedPulls.has(ns))
|
|
1700
1866
|
return;
|
|
1701
1867
|
this.recordBackgroundPullNeed(ns, 0, true, true);
|
|
1702
1868
|
this.backgroundPullNeeds.get(ns).messageClassRequest = { ...params };
|
|
@@ -1740,7 +1906,7 @@ export class MessageDeliveryEngine {
|
|
|
1740
1906
|
}
|
|
1741
1907
|
}
|
|
1742
1908
|
recordBackgroundPullNeed(ns, throughSeq = 0, probe = false, restart = false) {
|
|
1743
|
-
if (this.automaticGroupPullStopped(ns))
|
|
1909
|
+
if (this.automaticGroupPullStopped(ns) || this.oversizedPulls.has(ns))
|
|
1744
1910
|
return;
|
|
1745
1911
|
const client = this.runtime.client;
|
|
1746
1912
|
if (client._sessionOptions?.background_sync === false || !client._aid
|
|
@@ -1759,7 +1925,7 @@ export class MessageDeliveryEngine {
|
|
|
1759
1925
|
need.probe ||= probe;
|
|
1760
1926
|
this.backgroundPullNeeds.set(ns, need);
|
|
1761
1927
|
}
|
|
1762
|
-
observeBackgroundPullResponse(ns, afterSeq, result, limit =
|
|
1928
|
+
observeBackgroundPullResponse(ns, afterSeq, result, limit = _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize) {
|
|
1763
1929
|
if (!isJsonObject(result))
|
|
1764
1930
|
return;
|
|
1765
1931
|
const response = result;
|
|
@@ -1785,7 +1951,7 @@ export class MessageDeliveryEngine {
|
|
|
1785
1951
|
finishBackgroundPull(ns, generation, afterSeq, failed, trigger) {
|
|
1786
1952
|
if (generation !== this.captureInlineAckGeneration())
|
|
1787
1953
|
return;
|
|
1788
|
-
if (this.automaticGroupPullStopped(ns))
|
|
1954
|
+
if (this.automaticGroupPullStopped(ns) || this.oversizedPulls.has(ns))
|
|
1789
1955
|
return;
|
|
1790
1956
|
const need = this.backgroundPullNeeds.get(ns);
|
|
1791
1957
|
if (need && trigger && need.trigger !== trigger) {
|
|
@@ -1812,7 +1978,7 @@ export class MessageDeliveryEngine {
|
|
|
1812
1978
|
this.requestBackgroundPullRecovery();
|
|
1813
1979
|
}
|
|
1814
1980
|
requestBackgroundPullRecovery() {
|
|
1815
|
-
if (this.backgroundPullCheckQueued || (this.backgroundPullNeeds.size === 0 && !this.peerCatalogDirty && this.peerRecoveryNeeds.size === 0))
|
|
1981
|
+
if (this.backgroundPullCheckQueued || (this.backgroundPullNeeds.size === 0 && !this.peerCatalogDirty && this.peerRecoveryNeeds.size === 0 && this.peerVolatileNeeds.size === 0))
|
|
1816
1982
|
return;
|
|
1817
1983
|
this.backgroundPullCheckQueued = true;
|
|
1818
1984
|
const generation = this.captureInlineAckGeneration();
|
|
@@ -1824,6 +1990,8 @@ export class MessageDeliveryEngine {
|
|
|
1824
1990
|
if (client._sessionOptions?.background_sync === false || client.state !== ConnectionState.READY || client._closing)
|
|
1825
1991
|
return;
|
|
1826
1992
|
if (client._p2pPeerPullEnabled) {
|
|
1993
|
+
if (this.peerVolatileNeeds.size && !this.peerVolatileTask)
|
|
1994
|
+
this.schedulePeerVolatileRecovery(this.peerVolatileNeeds.values().next().value);
|
|
1827
1995
|
if (this.peerCatalogDirty && !this.peerCatalogTask)
|
|
1828
1996
|
this.refreshPendingPeers();
|
|
1829
1997
|
for (const [sender, need] of this.peerRecoveryNeeds) {
|
|
@@ -1837,6 +2005,11 @@ export class MessageDeliveryEngine {
|
|
|
1837
2005
|
this.backgroundPullNeeds.delete(ns);
|
|
1838
2006
|
continue;
|
|
1839
2007
|
}
|
|
2008
|
+
if (this.pendingV2GroupPulls.has(ns)) {
|
|
2009
|
+
if (!client._v2Session)
|
|
2010
|
+
continue;
|
|
2011
|
+
this.pendingV2GroupPulls.delete(ns);
|
|
2012
|
+
}
|
|
1840
2013
|
if (ns.startsWith('p2p:') && !this.hasP2pApplicationSubscription())
|
|
1841
2014
|
continue;
|
|
1842
2015
|
if (need.messageClassRequest && need.messageClassRequest.message_class !== 'sdk_control') {
|
|
@@ -2262,6 +2435,8 @@ export class MessageDeliveryEngine {
|
|
|
2262
2435
|
return applicationResult({ ...result, message_class: 'sdk_control' });
|
|
2263
2436
|
if (!APP_SEND_ENVELOPE_METHODS.has(method) || !isJsonObject(result))
|
|
2264
2437
|
return result;
|
|
2438
|
+
if (result.status === 'echo_return')
|
|
2439
|
+
return result;
|
|
2265
2440
|
let out = { ...result };
|
|
2266
2441
|
const serverEnvelope = method === 'group.send' && isJsonObject(out.envelope)
|
|
2267
2442
|
? { ...out.envelope }
|
|
@@ -2586,8 +2761,10 @@ export class MessageDeliveryEngine {
|
|
|
2586
2761
|
return this.runApplicationPage(namespace, source, async () => { await this.publishAppEvent(event, payload, source, deliveryContext); });
|
|
2587
2762
|
}
|
|
2588
2763
|
}
|
|
2589
|
-
if ((event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
2590
|
-
client._maybeAppendEchoTraceReceive(payload)
|
|
2764
|
+
if (source !== 'echo_return' && (event === 'message.received' || event === 'group.message_created') && isJsonObject(payload)) {
|
|
2765
|
+
if (client._maybeAppendEchoTraceReceive(payload)) {
|
|
2766
|
+
return client._returnReceivedEcho(payload);
|
|
2767
|
+
}
|
|
2591
2768
|
}
|
|
2592
2769
|
this.logAppMessagePublish(event, payload, source);
|
|
2593
2770
|
if (isJsonObject(payload)) {
|
|
@@ -2829,7 +3006,14 @@ export class MessageDeliveryEngine {
|
|
|
2829
3006
|
}
|
|
2830
3007
|
async onRawMessageReceived(data) {
|
|
2831
3008
|
const client = this.runtime.client;
|
|
2832
|
-
if (client.
|
|
3009
|
+
if (isJsonObject(data) && !client._echoStarts.has(data))
|
|
3010
|
+
client._echoStarts.set(data, performance.now());
|
|
3011
|
+
const message = isJsonObject(data) ? data : undefined;
|
|
3012
|
+
const payload = message?.payload;
|
|
3013
|
+
const plainEcho = message && !message.encrypted && !message.encrypt && isJsonObject(payload)
|
|
3014
|
+
&& !String(payload.type ?? '').trim().toLowerCase().startsWith('e2ee') && !payload.ciphertext
|
|
3015
|
+
&& !client._isEncryptedPushMessage(message) && client._isEchoPayload(payload);
|
|
3016
|
+
if (client._p2pPeerPullEnabled && !plainEcho) {
|
|
2833
3017
|
await this.onPeerPush(data);
|
|
2834
3018
|
return;
|
|
2835
3019
|
}
|
|
@@ -2898,6 +3082,7 @@ export class MessageDeliveryEngine {
|
|
|
2898
3082
|
return;
|
|
2899
3083
|
}
|
|
2900
3084
|
const msg = { ...data };
|
|
3085
|
+
client._echoStarts.set(msg, client._echoStarts.get(data) ?? performance.now());
|
|
2901
3086
|
if (!this.messageTargetsCurrentInstance(msg)) {
|
|
2902
3087
|
client._clientLog.debug(`P2P push filtered by instance: message_id=${String(msg.message_id ?? '')}, seq=${String(msg.seq ?? '')}, target_device=${String(msg.device_id ?? '')}, target_slot=${String(msg.slot_id ?? '')}, local_device=${client._deviceId}, local_slot=${client._slotId}`);
|
|
2903
3088
|
return;
|
|
@@ -2954,6 +3139,8 @@ export class MessageDeliveryEngine {
|
|
|
2954
3139
|
}
|
|
2955
3140
|
async onRawGroupMessageCreated(data) {
|
|
2956
3141
|
const client = this.runtime.client;
|
|
3142
|
+
if (isJsonObject(data) && !client._echoStarts.has(data))
|
|
3143
|
+
client._echoStarts.set(data, performance.now());
|
|
2957
3144
|
const tStart = Date.now();
|
|
2958
3145
|
if (isJsonObject(data)) {
|
|
2959
3146
|
client._logMessageDebug('server-push', '_raw.group.message_created', 'group.message_created', data);
|
|
@@ -2994,6 +3181,7 @@ export class MessageDeliveryEngine {
|
|
|
2994
3181
|
}
|
|
2995
3182
|
const msg = { ...data };
|
|
2996
3183
|
const groupId = String(msg.group_id ?? '');
|
|
3184
|
+
client._echoStarts.set(msg, client._echoStarts.get(data) ?? performance.now());
|
|
2997
3185
|
const seq = msg.seq;
|
|
2998
3186
|
const payload = msg.payload;
|
|
2999
3187
|
if (groupId) {
|
|
@@ -3068,12 +3256,15 @@ export class MessageDeliveryEngine {
|
|
|
3068
3256
|
const afterSeq = client._seqTracker.getContiguousSeq(ns);
|
|
3069
3257
|
client._clientLog.debug(`auto pull group messages start: group=${groupId}, after_seq=${afterSeq}, seq=${String(notification.seq ?? '')}`);
|
|
3070
3258
|
const operation = async () => {
|
|
3071
|
-
|
|
3259
|
+
let count;
|
|
3260
|
+
const messages = await client._pullGroupV2(groupId, afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, {
|
|
3261
|
+
gateLocked: true, background: true, retainMessages: false, onMessageCount: (value) => { count = value; },
|
|
3262
|
+
});
|
|
3072
3263
|
this.prunePushedSeqs(ns);
|
|
3073
|
-
return messages.length;
|
|
3264
|
+
return count ?? messages.length;
|
|
3074
3265
|
};
|
|
3075
3266
|
if (client._rpcPipeline) {
|
|
3076
|
-
const key = client._rpcPipeline.pullGateKeyForCall('group.pull', { group_id: groupId, after_seq: afterSeq, limit:
|
|
3267
|
+
const key = client._rpcPipeline.pullGateKeyForCall('group.pull', { group_id: groupId, after_seq: afterSeq, limit: _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize });
|
|
3077
3268
|
await this.runAutomaticPull(ns, operation, (attempt) => client._rpcPipeline.runPullNamespaceSerialized(key, attempt, true));
|
|
3078
3269
|
}
|
|
3079
3270
|
else {
|
|
@@ -3107,9 +3298,9 @@ export class MessageDeliveryEngine {
|
|
|
3107
3298
|
try {
|
|
3108
3299
|
// Gap Fill 本身就是 Forward Pull,必须沿用协调器的完整事务:
|
|
3109
3300
|
// 原始页提交成功后由协调器负责 Piggyback/终端 ACK。
|
|
3110
|
-
const operation = () => client._pullV2(afterSeq,
|
|
3301
|
+
const operation = () => client._pullV2(afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, { gateLocked: true, background: true });
|
|
3111
3302
|
const messages = await this.runAutomaticPull(ns, operation, (attempt) => client._rpcPipeline
|
|
3112
|
-
? client._rpcPipeline.runPullSerialized(client._rpcPipeline.pullGateKeyForCall('message.pull', { after_seq: afterSeq, limit:
|
|
3303
|
+
? client._rpcPipeline.runPullSerialized(client._rpcPipeline.pullGateKeyForCall('message.pull', { after_seq: afterSeq, limit: _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize }), attempt, true)
|
|
3113
3304
|
: client._withBackgroundRpc(attempt));
|
|
3114
3305
|
filled = messages.length;
|
|
3115
3306
|
this.prunePushedSeqs(ns);
|
|
@@ -3149,11 +3340,14 @@ export class MessageDeliveryEngine {
|
|
|
3149
3340
|
let filled = 0;
|
|
3150
3341
|
let failed = false;
|
|
3151
3342
|
try {
|
|
3152
|
-
|
|
3343
|
+
let count;
|
|
3344
|
+
const operation = () => client._pullGroupV2(groupId, afterSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, {
|
|
3345
|
+
gateLocked: true, background: true, retainMessages: false, onMessageCount: (value) => { count = value; },
|
|
3346
|
+
});
|
|
3153
3347
|
const messages = await this.runAutomaticPull(ns, operation, (attempt) => client._rpcPipeline
|
|
3154
|
-
? client._rpcPipeline.runPullNamespaceSerialized(client._rpcPipeline.pullGateKeyForCall('group.pull', { group_id: groupId, after_seq: afterSeq, limit:
|
|
3348
|
+
? client._rpcPipeline.runPullNamespaceSerialized(client._rpcPipeline.pullGateKeyForCall('group.pull', { group_id: groupId, after_seq: afterSeq, limit: _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize }), attempt, true)
|
|
3155
3349
|
: client._withBackgroundRpc(attempt));
|
|
3156
|
-
filled = messages.length;
|
|
3350
|
+
filled = count ?? messages.length;
|
|
3157
3351
|
this.prunePushedSeqs(ns);
|
|
3158
3352
|
client._clientLog.debug(`group message gap fill done: group=${groupId}, after_seq=${afterSeq}, filled=${filled}`);
|
|
3159
3353
|
}
|
|
@@ -3263,7 +3457,7 @@ export class MessageDeliveryEngine {
|
|
|
3263
3457
|
return;
|
|
3264
3458
|
if (generation !== this.captureInlineAckGeneration())
|
|
3265
3459
|
return;
|
|
3266
|
-
this.observeBackgroundPullResponse(ns, nextAfterSeq, result);
|
|
3460
|
+
this.observeBackgroundPullResponse(ns, nextAfterSeq, result, request.limit);
|
|
3267
3461
|
const events = result.events;
|
|
3268
3462
|
if (!Array.isArray(events))
|
|
3269
3463
|
return;
|
|
@@ -3355,12 +3549,15 @@ export class MessageDeliveryEngine {
|
|
|
3355
3549
|
if (eventObjects.length > 0 && ackContig > 0 && ackContig !== pageContigBefore) {
|
|
3356
3550
|
const ackSeq = this.clampAckSeq('group.ack_events', 'event_seq', ns, ackContig);
|
|
3357
3551
|
try {
|
|
3358
|
-
const
|
|
3552
|
+
const ackParams = {
|
|
3359
3553
|
group_id: groupId,
|
|
3360
3554
|
event_seq: ackSeq,
|
|
3361
3555
|
device_id: client._deviceId,
|
|
3362
3556
|
slot_id: client._slotId,
|
|
3363
|
-
}
|
|
3557
|
+
};
|
|
3558
|
+
const ackPromise = !singlePage && client._rpcPipeline
|
|
3559
|
+
? client._rpcPipeline.rawCall('group.ack_events', ackParams, { signed: false, background: true })
|
|
3560
|
+
: client._transport.call('group.ack_events', ackParams, undefined, undefined, true);
|
|
3364
3561
|
if (singlePage)
|
|
3365
3562
|
await ackPromise;
|
|
3366
3563
|
else
|
|
@@ -3716,7 +3913,7 @@ export class MessageDeliveryEngine {
|
|
|
3716
3913
|
return requestedSeq;
|
|
3717
3914
|
return typeof raw === 'number' && Number.isSafeInteger(raw) && raw >= 0 ? raw : 0;
|
|
3718
3915
|
}
|
|
3719
|
-
async runP2PRealtimeSync(ns, pushSeq, pageLimit =
|
|
3916
|
+
async runP2PRealtimeSync(ns, pushSeq, pageLimit = _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, forceTail = false) {
|
|
3720
3917
|
const client = this.runtime.client;
|
|
3721
3918
|
const before = this.syncState(ns);
|
|
3722
3919
|
const order = forceTail ? ['tail'] : typeof client._seqTracker.planRealtimeSync === 'function'
|
|
@@ -3745,12 +3942,12 @@ export class MessageDeliveryEngine {
|
|
|
3745
3942
|
const tailResult = await client._v2E2EE.pullV2TailInternal({
|
|
3746
3943
|
window_mode: 'tail',
|
|
3747
3944
|
after_seq: after,
|
|
3748
|
-
limit: pageLimit,
|
|
3945
|
+
limit: Math.min(pageLimit, 50),
|
|
3749
3946
|
}, true);
|
|
3750
3947
|
tailHead = this.syncState(ns).head;
|
|
3751
3948
|
return tailResult;
|
|
3752
3949
|
}
|
|
3753
|
-
const opts = { gateLocked: true };
|
|
3950
|
+
const opts = { gateLocked: true, background };
|
|
3754
3951
|
if (request.max_pages !== undefined)
|
|
3755
3952
|
opts.maxPages = request.max_pages;
|
|
3756
3953
|
const messages = await client._pullV2(after, pageLimit, opts);
|
|
@@ -3762,7 +3959,7 @@ export class MessageDeliveryEngine {
|
|
|
3762
3959
|
return await this.runAutomaticPull(ns, invoke, (attempt) => client._rpcPipeline.runPullSerialized(key, attempt, background));
|
|
3763
3960
|
};
|
|
3764
3961
|
if (order.length === 1 && order[0] === 'tail') {
|
|
3765
|
-
result = await run({ window_mode: 'tail', after_seq: this.syncState(ns).ack, limit: pageLimit }, false);
|
|
3962
|
+
result = await run({ window_mode: 'tail', after_seq: this.syncState(ns).ack, limit: Math.min(pageLimit, 50) }, false);
|
|
3766
3963
|
}
|
|
3767
3964
|
const state = this.syncState(ns);
|
|
3768
3965
|
const needsForward = state.ack < state.tail - 1;
|
|
@@ -3793,7 +3990,7 @@ export class MessageDeliveryEngine {
|
|
|
3793
3990
|
}
|
|
3794
3991
|
return result;
|
|
3795
3992
|
}
|
|
3796
|
-
async runGroupRealtimeSync(groupId, ns, pushSeq, pageLimit =
|
|
3993
|
+
async runGroupRealtimeSync(groupId, ns, pushSeq, pageLimit = _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, forceTail = false) {
|
|
3797
3994
|
const client = this.runtime.client;
|
|
3798
3995
|
const before = this.syncState(ns);
|
|
3799
3996
|
const order = forceTail ? ['tail'] : typeof client._seqTracker.planRealtimeSync === 'function'
|
|
@@ -3828,11 +4025,13 @@ export class MessageDeliveryEngine {
|
|
|
3828
4025
|
tailHead = this.syncState(ns).head;
|
|
3829
4026
|
return tailResult;
|
|
3830
4027
|
}
|
|
3831
|
-
|
|
4028
|
+
let count;
|
|
4029
|
+
const opts = { gateLocked: true, background, retainMessages: !background,
|
|
4030
|
+
onMessageCount: (value) => { count = value; } };
|
|
3832
4031
|
if (request.max_pages !== undefined)
|
|
3833
4032
|
opts.maxPages = request.max_pages;
|
|
3834
4033
|
const messages = await client._pullGroupV2(groupId, after, pageLimit, opts);
|
|
3835
|
-
return { messages, raw_count: messages.length };
|
|
4034
|
+
return { messages, raw_count: count ?? messages.length };
|
|
3836
4035
|
};
|
|
3837
4036
|
if (!client._rpcPipeline)
|
|
3838
4037
|
return await this.runAutomaticPull(ns, invoke);
|
|
@@ -3874,7 +4073,7 @@ export class MessageDeliveryEngine {
|
|
|
3874
4073
|
const client = this.runtime.client;
|
|
3875
4074
|
const request = { after_seq: this.syncState(ns).ack, limit: pageLimit, max_pages: 1 };
|
|
3876
4075
|
const invoke = async () => {
|
|
3877
|
-
const messages = await client._pullV2(Number(request.after_seq), pageLimit, { gateLocked: true, maxPages: 1 });
|
|
4076
|
+
const messages = await client._pullV2(Number(request.after_seq), pageLimit, { gateLocked: true, maxPages: 1, background });
|
|
3878
4077
|
return { messages, raw_count: messages.length };
|
|
3879
4078
|
};
|
|
3880
4079
|
if (!client._rpcPipeline)
|
|
@@ -3888,8 +4087,11 @@ export class MessageDeliveryEngine {
|
|
|
3888
4087
|
const maxPages = Math.max(1, Math.ceil(Math.max(0, throughSeq - ack) / pageLimit));
|
|
3889
4088
|
const request = { group_id: groupId, after_seq: ack, limit: pageLimit, max_pages: maxPages };
|
|
3890
4089
|
const invoke = async () => {
|
|
3891
|
-
|
|
3892
|
-
|
|
4090
|
+
let count;
|
|
4091
|
+
const messages = await client._pullGroupV2(groupId, Number(request.after_seq), pageLimit, {
|
|
4092
|
+
gateLocked: true, maxPages, background, retainMessages: !background, onMessageCount: (value) => { count = value; },
|
|
4093
|
+
});
|
|
4094
|
+
return { messages, raw_count: count ?? messages.length };
|
|
3893
4095
|
};
|
|
3894
4096
|
if (!client._rpcPipeline)
|
|
3895
4097
|
return await this.runAutomaticPull(ns, invoke);
|
|
@@ -4097,7 +4299,7 @@ export class MessageDeliveryEngine {
|
|
|
4097
4299
|
if (!this.beginRealtimeSync(ns))
|
|
4098
4300
|
return;
|
|
4099
4301
|
try {
|
|
4100
|
-
await this.runP2PRealtimeSync(ns, this.syncState(ns).head,
|
|
4302
|
+
await this.runP2PRealtimeSync(ns, this.syncState(ns).head, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true);
|
|
4101
4303
|
}
|
|
4102
4304
|
catch (exc) {
|
|
4103
4305
|
client._clientLog.warn(`V2 P2P invalid-seq Tail failed: ${formatDeliveryError(exc)}`);
|
|
@@ -4112,7 +4314,7 @@ export class MessageDeliveryEngine {
|
|
|
4112
4314
|
if (!this.beginRealtimeSync(ns))
|
|
4113
4315
|
return;
|
|
4114
4316
|
try {
|
|
4115
|
-
await this.runGroupRealtimeSync(groupId, ns, this.syncState(ns).head,
|
|
4317
|
+
await this.runGroupRealtimeSync(groupId, ns, this.syncState(ns).head, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true);
|
|
4116
4318
|
}
|
|
4117
4319
|
catch (exc) {
|
|
4118
4320
|
client._clientLog.warn(`V2 group invalid-seq Tail failed: group=${groupId} ${formatDeliveryError(exc)}`);
|
|
@@ -4692,7 +4894,7 @@ export class MessageDeliveryEngine {
|
|
|
4692
4894
|
}
|
|
4693
4895
|
let pullFailed = false;
|
|
4694
4896
|
try {
|
|
4695
|
-
await this.runP2PRealtimeSync(ns, pushSeq,
|
|
4897
|
+
await this.runP2PRealtimeSync(ns, pushSeq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, false);
|
|
4696
4898
|
if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
|
|
4697
4899
|
return;
|
|
4698
4900
|
// Tail 期间新到达的 Push 已由 realtime sync 在同一周期内补至多一页 Forward。
|
|
@@ -4729,7 +4931,7 @@ export class MessageDeliveryEngine {
|
|
|
4729
4931
|
const coordinator = client._v2E2EE;
|
|
4730
4932
|
const pendingAckSeq = Number(coordinator.pendingForwardAck?.(ns, committedAck) ?? 0);
|
|
4731
4933
|
if (pendingAckSeq > 0) {
|
|
4732
|
-
|
|
4934
|
+
this.scheduleForwardAck(ns, pendingAckSeq, seq => coordinator.confirmForwardGroupAck(groupId, seq, String(data.group_aid ?? '').trim() || undefined, true));
|
|
4733
4935
|
}
|
|
4734
4936
|
else {
|
|
4735
4937
|
const pendingNs = this.resolvePendingGroupInlineAckNamespace(ns);
|
|
@@ -4755,7 +4957,7 @@ export class MessageDeliveryEngine {
|
|
|
4755
4957
|
while (true) {
|
|
4756
4958
|
const ackBefore = this.syncState(ns).ack;
|
|
4757
4959
|
attemptAfterSeq = ackBefore;
|
|
4758
|
-
await this.runGroupForwardRecovery(groupId, ns,
|
|
4960
|
+
await this.runGroupForwardRecovery(groupId, ns, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true, targets.get(ns) ?? 0);
|
|
4759
4961
|
const ackAfter = this.syncState(ns).ack;
|
|
4760
4962
|
if (ackAfter >= (targets.get(ns) ?? 0) || ackAfter <= ackBefore)
|
|
4761
4963
|
return;
|
|
@@ -4790,8 +4992,6 @@ export class MessageDeliveryEngine {
|
|
|
4790
4992
|
const groupId = typeof d.group_id === 'string' ? d.group_id.trim() : '';
|
|
4791
4993
|
const rawSeq = d.seq;
|
|
4792
4994
|
const inlinePresent = hasNonEmptyInlineMessage(d.inline_message);
|
|
4793
|
-
if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent))
|
|
4794
|
-
return;
|
|
4795
4995
|
const seq = this.realtimeHeadSeq(rawSeq, inlinePresent);
|
|
4796
4996
|
if (!groupId) {
|
|
4797
4997
|
client._clientLog.debug(`_onRawGroupV2MessageCreated skipped: group=${groupId || '<empty>'}, seq=${String(d.seq ?? '')}`);
|
|
@@ -4804,6 +5004,15 @@ export class MessageDeliveryEngine {
|
|
|
4804
5004
|
return;
|
|
4805
5005
|
}
|
|
4806
5006
|
const eventKind = String(d.kind ?? '').trim();
|
|
5007
|
+
if (!client._v2Session && !(expectedVersion === 'v1' && inlinePresent)) {
|
|
5008
|
+
if (client._sessionOptions?.background_sync !== false) {
|
|
5009
|
+
const ns = `group:${groupId}`;
|
|
5010
|
+
this.recordBackgroundPullNeed(ns, seq, eventKind === 'group.online_unread_hint', true);
|
|
5011
|
+
if (this.backgroundPullNeeds.has(ns))
|
|
5012
|
+
this.pendingV2GroupPulls.add(ns);
|
|
5013
|
+
}
|
|
5014
|
+
return;
|
|
5015
|
+
}
|
|
4807
5016
|
if (eventKind === 'group.online_unread_hint') {
|
|
4808
5017
|
if (client._sessionOptions.background_sync === false)
|
|
4809
5018
|
return;
|
|
@@ -4852,7 +5061,7 @@ export class MessageDeliveryEngine {
|
|
|
4852
5061
|
return;
|
|
4853
5062
|
}
|
|
4854
5063
|
let pullFailed = false;
|
|
4855
|
-
void this.runGroupRealtimeSync(groupId, ns, seq,
|
|
5064
|
+
void this.runGroupRealtimeSync(groupId, ns, seq, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, false).then(async () => {
|
|
4856
5065
|
if (inlineGeneration !== undefined && !this.inlineGenerationIsCurrent(inlineGeneration))
|
|
4857
5066
|
return;
|
|
4858
5067
|
// Tail 期间新到达的 Push 已由 realtime sync 在同一周期内补至多一页 Forward。
|
|
@@ -4938,18 +5147,44 @@ export class MessageDeliveryEngine {
|
|
|
4938
5147
|
this.refreshPendingPeers();
|
|
4939
5148
|
return;
|
|
4940
5149
|
}
|
|
4941
|
-
if (!client._aid || !client._v2Session)
|
|
5150
|
+
if (!client._aid || !client._v2Session || client._sessionOptions?.background_sync === false)
|
|
4942
5151
|
return;
|
|
4943
5152
|
const ns = `p2p:${client._aid}`;
|
|
4944
5153
|
const generation = this.captureInlineAckGeneration();
|
|
4945
|
-
const
|
|
4946
|
-
|
|
5154
|
+
const state = this.syncState(ns);
|
|
5155
|
+
const afterSeq = state.ack;
|
|
5156
|
+
const hintSeq = positiveSafeSequenceHint(data.seq);
|
|
5157
|
+
if (hintSeq > 0 && afterSeq >= Math.max(hintSeq, state.head, Number(client._seqTracker.getMaxSeenSeq?.(ns) ?? 0), Number(client._pendingP2pPullUpper?.get?.(ns) ?? 0))
|
|
5158
|
+
&& afterSeq >= state.tail - 1 && !client._pendingOrderedMsgs.get(ns)?.size) {
|
|
5159
|
+
const coordinator = client._v2E2EE;
|
|
5160
|
+
const pendingAckSeq = Number(coordinator.pendingForwardAck?.(ns, afterSeq) ?? 0);
|
|
5161
|
+
if (pendingAckSeq > 0) {
|
|
5162
|
+
this.scheduleForwardAck(ns, pendingAckSeq, seq => coordinator.confirmForwardP2PAck(seq));
|
|
5163
|
+
}
|
|
5164
|
+
else {
|
|
5165
|
+
const pending = this.pendingP2PInlineAcks?.get(ns);
|
|
5166
|
+
if (pending)
|
|
5167
|
+
this.retryPendingP2PInlineAck(ns, pending.seq, 'covered online hint', afterSeq);
|
|
5168
|
+
}
|
|
5169
|
+
return;
|
|
5170
|
+
}
|
|
5171
|
+
this.recordBackgroundPullNeed(ns, hintSeq, true, true);
|
|
4947
5172
|
const pullTrigger = this.backgroundPullNeeds.get(ns)?.trigger;
|
|
5173
|
+
const tasks = this.onlineUnreadHintTasks ?? new Map();
|
|
5174
|
+
this.onlineUnreadHintTasks = tasks;
|
|
5175
|
+
if (tasks.has(ns))
|
|
5176
|
+
return;
|
|
4948
5177
|
let failed = false;
|
|
4949
|
-
|
|
5178
|
+
const task = this.runP2PForwardRecovery(ns, _INTERNAL_MESSAGE_FLOW_LIMITS.pullPageSize, true).then(() => undefined).catch((exc) => {
|
|
4950
5179
|
failed = true;
|
|
4951
5180
|
client._clientLog.debug(`P2P online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
4952
|
-
}).finally(() =>
|
|
5181
|
+
}).finally(() => {
|
|
5182
|
+
if (tasks.get(ns) === task)
|
|
5183
|
+
tasks.delete(ns);
|
|
5184
|
+
this.finishBackgroundPull(ns, generation, afterSeq, failed, pullTrigger);
|
|
5185
|
+
});
|
|
5186
|
+
tasks.set(ns, task);
|
|
5187
|
+
client._safeAsync(task);
|
|
4953
5188
|
}
|
|
4954
5189
|
async saveSeqTrackerState() {
|
|
4955
5190
|
const client = this.runtime.client;
|