@agentunion/fastaun-browser 0.5.19 → 0.5.20
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 +129 -78
- package/_packed_docs/CHANGELOG.md +129 -78
- package/_packed_docs/INDEX.md +201 -195
- package/_packed_docs/KITE_DOCS_GUIDE.md +93 -90
- package/_packed_docs/agent.md/SCHEMA.md +7 -7
- package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
- package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1072 -1072
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +443 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +658 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
- package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +67 -63
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +35 -8
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
- package/_packed_docs/sdk/09-group-rpc-manual.md +258 -254
- package/_packed_docs/sdk/09-message-rpc-manual.md +7 -4
- package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +61 -52
- package/_packed_docs/sdk/INDEX.md +92 -80
- package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +922 -0
- package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
- 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 +300 -0
- 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 +382 -0
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +476 -0
- package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
- package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
- package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
- package/dist/agent-md-schema.d.ts +15 -4
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +64 -30
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +10 -2
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +278 -121
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +46 -0
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +149 -10
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.d.ts +4 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +23 -42
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +85 -18
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +1581 -781
- package/dist/cert-utils.d.ts +49 -1
- package/dist/cert-utils.d.ts.map +1 -1
- package/dist/cert-utils.js +102 -56
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +7 -0
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +243 -28
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +89 -77
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +99 -80
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +31 -17
- package/dist/client.js.map +1 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +8 -6
- package/dist/crypto.js.map +1 -1
- package/dist/events.d.ts +5 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +33 -14
- package/dist/events.js.map +1 -1
- package/dist/facades.js +5 -5
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/org-protocol.d.ts.map +1 -1
- package/dist/org-protocol.js +72 -12
- package/dist/org-protocol.js.map +1 -1
- package/dist/ownership-v21.d.ts +25 -8
- package/dist/ownership-v21.d.ts.map +1 -1
- package/dist/ownership-v21.js +142 -73
- package/dist/ownership-v21.js.map +1 -1
- package/dist/ownership-workflow.d.ts +6 -1
- package/dist/ownership-workflow.d.ts.map +1 -1
- package/dist/ownership-workflow.js +221 -58
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +2 -1
- package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
- package/dist/tools/cross-sdk-agent.js +91 -8
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +1 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +2 -0
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/client/delivery.js
CHANGED
|
@@ -133,6 +133,9 @@ export class MessageDeliveryEngine {
|
|
|
133
133
|
pendingPullNoProgressAcks = null;
|
|
134
134
|
onlineUnreadHintTargets = null;
|
|
135
135
|
onlineUnreadHintOwners = null;
|
|
136
|
+
backgroundPullDemands = new Map();
|
|
137
|
+
backgroundPullTimer = null;
|
|
138
|
+
backgroundPullRecoveryQueued = false;
|
|
136
139
|
realtimeAcking = null;
|
|
137
140
|
pendingP2PInlineAcks = null;
|
|
138
141
|
pendingGroupInlineAcks = null;
|
|
@@ -161,6 +164,11 @@ export class MessageDeliveryEngine {
|
|
|
161
164
|
this.pendingPullNoProgressAcks = null;
|
|
162
165
|
this.onlineUnreadHintTargets = null;
|
|
163
166
|
this.onlineUnreadHintOwners = null;
|
|
167
|
+
this.backgroundPullDemands.clear();
|
|
168
|
+
if (this.backgroundPullTimer !== null)
|
|
169
|
+
clearTimeout(this.backgroundPullTimer);
|
|
170
|
+
this.backgroundPullTimer = null;
|
|
171
|
+
this.backgroundPullRecoveryQueued = false;
|
|
164
172
|
this.realtimeTailResults = null;
|
|
165
173
|
this.realtimeAcking = null;
|
|
166
174
|
this.pendingP2PInlineAcks = null;
|
|
@@ -326,8 +334,107 @@ export class MessageDeliveryEngine {
|
|
|
326
334
|
if (!ns)
|
|
327
335
|
return;
|
|
328
336
|
this.schedulePendingPullIfNeeded(ns, 'pull-gate-idle');
|
|
337
|
+
this.requestBackgroundPullRecovery();
|
|
338
|
+
}
|
|
339
|
+
recordBackgroundPullDemand(ns, throughSeq = 0, probe = false) {
|
|
340
|
+
const demand = this.backgroundPullDemands.get(ns) ?? {
|
|
341
|
+
throughSeq: 0, hasMore: false, probe: false, afterSeq: -1, retryAt: 0,
|
|
342
|
+
};
|
|
343
|
+
demand.throughSeq = Math.max(demand.throughSeq, positiveSafeSequenceHint(throughSeq));
|
|
344
|
+
demand.probe ||= probe;
|
|
345
|
+
this.backgroundPullDemands.set(ns, demand);
|
|
346
|
+
return demand;
|
|
347
|
+
}
|
|
348
|
+
observeBackgroundPullResponse(ns, afterSeq, result, limit = 50) {
|
|
349
|
+
if (!ns || this.runtime.client._sessionOptions?.background_sync === false)
|
|
350
|
+
return;
|
|
351
|
+
const cursor = isJsonObject(result.cursor) ? result.cursor : null;
|
|
352
|
+
const rows = Array.isArray(result.messages) ? result.messages : Array.isArray(result.events) ? result.events : [];
|
|
353
|
+
let throughSeq = Math.max(positiveSafeSequenceHint(cursor?.latest_seq), positiveSafeSequenceHint(result.latest_seq), positiveSafeSequenceHint(result.latest_message_seq), positiveSafeSequenceHint(result.latest_event_seq));
|
|
354
|
+
for (const row of rows) {
|
|
355
|
+
if (!isJsonObject(row) || this.isVolatileMessage(row))
|
|
356
|
+
continue;
|
|
357
|
+
throughSeq = Math.max(throughSeq, positiveSafeSequenceHint(row.seq ?? row.event_seq));
|
|
358
|
+
}
|
|
359
|
+
const demand = this.recordBackgroundPullDemand(ns, throughSeq);
|
|
360
|
+
if (afterSeq >= demand.afterSeq) {
|
|
361
|
+
demand.afterSeq = afterSeq;
|
|
362
|
+
demand.hasMore = result.has_more === true
|
|
363
|
+
|| positiveSafeSequenceHint(result.remaining) > 0
|
|
364
|
+
|| (!Object.prototype.hasOwnProperty.call(result, 'has_more') && limit > 0 && rows.length >= limit);
|
|
365
|
+
demand.probe = false;
|
|
366
|
+
}
|
|
367
|
+
this.requestBackgroundPullRecovery();
|
|
368
|
+
}
|
|
369
|
+
finishBackgroundPull(ns, afterSeq, failed) {
|
|
370
|
+
const demand = this.backgroundPullDemands.get(ns);
|
|
371
|
+
if (demand) {
|
|
372
|
+
const state = this.syncState(ns);
|
|
373
|
+
const ack = state.ack;
|
|
374
|
+
if (ack < state.tail - 1)
|
|
375
|
+
demand.throughSeq = Math.max(demand.throughSeq, state.tail - 1);
|
|
376
|
+
demand.probe = failed;
|
|
377
|
+
if (!demand.probe && !demand.hasMore && ack >= demand.throughSeq)
|
|
378
|
+
this.backgroundPullDemands.delete(ns);
|
|
379
|
+
else
|
|
380
|
+
demand.retryAt = failed || ack <= afterSeq || ack <= (this.pendingPullNoProgressAcks?.get(ns) ?? -1)
|
|
381
|
+
? Date.now() + P2P_GAP_FILL_RETRY_BASE_MS
|
|
382
|
+
: 0;
|
|
383
|
+
}
|
|
384
|
+
this.requestBackgroundPullRecovery();
|
|
385
|
+
}
|
|
386
|
+
requestBackgroundPullRecovery() {
|
|
387
|
+
if (this.backgroundPullRecoveryQueued)
|
|
388
|
+
return;
|
|
389
|
+
const generation = this.captureInlineGeneration();
|
|
390
|
+
this.backgroundPullRecoveryQueued = true;
|
|
391
|
+
void Promise.resolve().then(() => {
|
|
392
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
393
|
+
return;
|
|
394
|
+
this.backgroundPullRecoveryQueued = false;
|
|
395
|
+
const client = this.runtime.client;
|
|
396
|
+
if (!client._aid || client._sessionOptions?.background_sync === false
|
|
397
|
+
|| client.state !== ConnectionState.READY || client._closing)
|
|
398
|
+
return;
|
|
399
|
+
if (this.backgroundPullTimer !== null)
|
|
400
|
+
clearTimeout(this.backgroundPullTimer);
|
|
401
|
+
this.backgroundPullTimer = null;
|
|
402
|
+
let retryAt = 0;
|
|
403
|
+
for (const [ns, demand] of this.backgroundPullDemands) {
|
|
404
|
+
if (ns.startsWith('p2p:') && ns !== `p2p:${client._aid}`)
|
|
405
|
+
continue;
|
|
406
|
+
const dedupKey = ns.startsWith('p2p:') ? `p2p_pull:${ns}`
|
|
407
|
+
: ns.startsWith('group_event:') ? `group_event_pull:${ns}` : `group_pull:${ns}`;
|
|
408
|
+
if (client._gapFillDone.has(dedupKey) || this.onlineUnreadHintOwners?.has(ns)
|
|
409
|
+
|| this.realtimeSyncing?.has(ns) || client._rpcPipeline?.hasPullActivity?.(ns, false))
|
|
410
|
+
continue;
|
|
411
|
+
const ack = this.syncState(ns).ack;
|
|
412
|
+
if (!demand.probe && !demand.hasMore && ack >= demand.throughSeq) {
|
|
413
|
+
this.backgroundPullDemands.delete(ns);
|
|
414
|
+
continue;
|
|
415
|
+
}
|
|
416
|
+
if (demand.retryAt > Date.now()) {
|
|
417
|
+
retryAt = retryAt === 0 ? demand.retryAt : Math.min(retryAt, demand.retryAt);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (ns.startsWith('p2p:'))
|
|
421
|
+
client._safeAsync(this.fillP2pGap());
|
|
422
|
+
else if (ns.startsWith('group_event:'))
|
|
423
|
+
client._safeAsync(this.fillGroupEventGap(ns.slice('group_event:'.length)));
|
|
424
|
+
else if (ns.startsWith('group:'))
|
|
425
|
+
client._safeAsync(this.fillGroupGap(ns.slice('group:'.length)));
|
|
426
|
+
}
|
|
427
|
+
if (retryAt > 0) {
|
|
428
|
+
this.backgroundPullTimer = globalThis.setTimeout(() => {
|
|
429
|
+
this.backgroundPullTimer = null;
|
|
430
|
+
if (this.isInlineGenerationCurrent(generation))
|
|
431
|
+
this.requestBackgroundPullRecovery();
|
|
432
|
+
}, Math.max(0, retryAt - Date.now()));
|
|
433
|
+
}
|
|
434
|
+
});
|
|
329
435
|
}
|
|
330
436
|
onForegroundPullsDrained() {
|
|
437
|
+
this.requestBackgroundPullRecovery();
|
|
331
438
|
const client = this.runtime.client;
|
|
332
439
|
if (!client._aid || client._sessionOptions?.background_sync === false
|
|
333
440
|
|| client.state !== ConnectionState.READY || client._closing)
|
|
@@ -340,6 +447,7 @@ export class MessageDeliveryEngine {
|
|
|
340
447
|
client._safeAsync(this.fillP2pGap());
|
|
341
448
|
}
|
|
342
449
|
onPullWorkSettled() {
|
|
450
|
+
this.requestBackgroundPullRecovery();
|
|
343
451
|
const pipeline = this.runtime.client._rpcPipeline;
|
|
344
452
|
if (pipeline?.hasAnyPullActivity?.() === true)
|
|
345
453
|
return;
|
|
@@ -2228,7 +2336,14 @@ export class MessageDeliveryEngine {
|
|
|
2228
2336
|
return;
|
|
2229
2337
|
}
|
|
2230
2338
|
}
|
|
2339
|
+
const generation = this.captureInlineGeneration();
|
|
2340
|
+
const dedupKey = `group_pull:${ns}`;
|
|
2341
|
+
this.recordBackgroundPullDemand(ns, positiveSafeSequenceHint(notification.seq), true);
|
|
2342
|
+
if (client._gapFillDone.has(dedupKey))
|
|
2343
|
+
return;
|
|
2344
|
+
client._gapFillDone.add(dedupKey);
|
|
2231
2345
|
let rawCompleted = false;
|
|
2346
|
+
let failed = false;
|
|
2232
2347
|
try {
|
|
2233
2348
|
const key = client._rpcPipeline.pullGateKeyForCall('group.pull', {
|
|
2234
2349
|
group_id: groupId,
|
|
@@ -2244,12 +2359,17 @@ export class MessageDeliveryEngine {
|
|
|
2244
2359
|
limit: 50,
|
|
2245
2360
|
_rpc_background: true,
|
|
2246
2361
|
}, { background: true });
|
|
2362
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
2363
|
+
throw new Error('pull invalidated');
|
|
2247
2364
|
rawCompleted = true;
|
|
2365
|
+
if (isJsonObject(result))
|
|
2366
|
+
this.observeBackgroundPullResponse(ns, afterSeq, result, 50);
|
|
2248
2367
|
await this.commitPlainForwardPage(ns, afterSeq, 'group.pull', result, groupId);
|
|
2249
2368
|
this.prunePushedSeqs(ns);
|
|
2250
2369
|
}, true);
|
|
2251
2370
|
}
|
|
2252
2371
|
catch (exc) {
|
|
2372
|
+
failed = true;
|
|
2253
2373
|
// 页发布或本地提交失败不能 ACK;提交后 ACK 失败则保留 pending。
|
|
2254
2374
|
// 两种情况都不能再把原始通知当作第二条业务消息发布。
|
|
2255
2375
|
client._clientLog.warn(`auto pull group message commit/ack failed:${String(exc)}`);
|
|
@@ -2257,6 +2377,12 @@ export class MessageDeliveryEngine {
|
|
|
2257
2377
|
await client._publishAppEvent('group.message_created', notification, 'push');
|
|
2258
2378
|
}
|
|
2259
2379
|
}
|
|
2380
|
+
finally {
|
|
2381
|
+
if (this.isInlineGenerationCurrent(generation)) {
|
|
2382
|
+
client._gapFillDone.delete(dedupKey);
|
|
2383
|
+
this.finishBackgroundPull(ns, afterSeq, failed);
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2260
2386
|
}
|
|
2261
2387
|
scheduleP2pGapRetry(ns, retryAttempt) {
|
|
2262
2388
|
const client = this.runtime.client;
|
|
@@ -2280,6 +2406,7 @@ export class MessageDeliveryEngine {
|
|
|
2280
2406
|
}
|
|
2281
2407
|
async fillP2pGap(retryAttempt = 0) {
|
|
2282
2408
|
const client = this.runtime.client;
|
|
2409
|
+
const generation = this.captureInlineGeneration();
|
|
2283
2410
|
if (client._sessionOptions?.background_sync === false)
|
|
2284
2411
|
return;
|
|
2285
2412
|
if (client.state !== ConnectionState.READY || client._closing)
|
|
@@ -2291,9 +2418,11 @@ export class MessageDeliveryEngine {
|
|
|
2291
2418
|
const dedupKey = `p2p_pull:${ns}`;
|
|
2292
2419
|
if (client._gapFillDone.has(dedupKey))
|
|
2293
2420
|
return;
|
|
2421
|
+
this.recordBackgroundPullDemand(ns, 0, true);
|
|
2294
2422
|
client._gapFillDone.add(dedupKey);
|
|
2295
2423
|
this.runtime.delivery.setGapFillActive(true);
|
|
2296
2424
|
let filled = 0;
|
|
2425
|
+
let failed = false;
|
|
2297
2426
|
try {
|
|
2298
2427
|
const key = client._rpcPipeline.pullGateKeyForCall('message.pull', { after_seq: afterSeq, limit: 50 });
|
|
2299
2428
|
const messages = await client._rpcPipeline.runPullSerialized(key, () => client._pullV2(afterSeq, 50, { gateLocked: true }), true);
|
|
@@ -2309,22 +2438,27 @@ export class MessageDeliveryEngine {
|
|
|
2309
2438
|
client._clientLog.warn(`P2P message gap-fill V2 unavailable, used plain pull fallback:${String(formatDeliveryError(exc))}`);
|
|
2310
2439
|
}
|
|
2311
2440
|
catch (fallbackExc) {
|
|
2441
|
+
failed = true;
|
|
2312
2442
|
client._clientLog.warn(`P2P message gap-fill plain fallback failed:${String(formatDeliveryError(fallbackExc))}`);
|
|
2313
|
-
this.scheduleP2pGapRetry(ns, retryAttempt + 1);
|
|
2314
2443
|
}
|
|
2315
2444
|
}
|
|
2316
2445
|
else {
|
|
2446
|
+
failed = true;
|
|
2317
2447
|
client._clientLog.warn(`P2P message gap-fill failed:${String(formatDeliveryError(exc))}`);
|
|
2318
2448
|
}
|
|
2319
2449
|
}
|
|
2320
2450
|
finally {
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2451
|
+
if (this.isInlineGenerationCurrent(generation)) {
|
|
2452
|
+
client._gapFillDone.delete(dedupKey);
|
|
2453
|
+
this.runtime.delivery.setGapFillActive(false);
|
|
2454
|
+
this.schedulePendingPullIfNeeded(ns, 'gap-fill-complete');
|
|
2455
|
+
this.finishBackgroundPull(ns, afterSeq, failed);
|
|
2456
|
+
}
|
|
2324
2457
|
}
|
|
2325
2458
|
}
|
|
2326
2459
|
async fillP2pGapWithPlainPull(ns, afterSeq) {
|
|
2327
2460
|
const client = this.runtime.client;
|
|
2461
|
+
const generation = this.captureInlineGeneration();
|
|
2328
2462
|
const params = {
|
|
2329
2463
|
after_seq: afterSeq,
|
|
2330
2464
|
limit: 50,
|
|
@@ -2333,11 +2467,16 @@ export class MessageDeliveryEngine {
|
|
|
2333
2467
|
_rpc_background: true,
|
|
2334
2468
|
};
|
|
2335
2469
|
const raw = await client._rpcPipeline.rawCall('message.pull', params, { background: true });
|
|
2470
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
2471
|
+
throw new Error('pull invalidated');
|
|
2472
|
+
if (isJsonObject(raw))
|
|
2473
|
+
this.observeBackgroundPullResponse(ns, afterSeq, raw, 50);
|
|
2336
2474
|
const page = await this.commitPlainForwardPage(ns, afterSeq, 'message.pull', raw);
|
|
2337
2475
|
return page.publishedCount;
|
|
2338
2476
|
}
|
|
2339
2477
|
async fillGroupGap(groupId) {
|
|
2340
2478
|
const client = this.runtime.client;
|
|
2479
|
+
const generation = this.captureInlineGeneration();
|
|
2341
2480
|
if (client._sessionOptions?.background_sync === false)
|
|
2342
2481
|
return;
|
|
2343
2482
|
if (client.state !== ConnectionState.READY || client._closing)
|
|
@@ -2350,25 +2489,48 @@ export class MessageDeliveryEngine {
|
|
|
2350
2489
|
const dedupKey = `group_pull:${ns}`;
|
|
2351
2490
|
if (client._gapFillDone.has(dedupKey))
|
|
2352
2491
|
return;
|
|
2492
|
+
this.recordBackgroundPullDemand(ns, 0, true);
|
|
2353
2493
|
client._gapFillDone.add(dedupKey);
|
|
2354
2494
|
this.runtime.delivery.setGapFillActive(true);
|
|
2355
2495
|
let filled = 0;
|
|
2496
|
+
let failed = false;
|
|
2356
2497
|
try {
|
|
2357
2498
|
const key = client._rpcPipeline.pullGateKeyForCall('group.pull', { group_id: groupId, after_seq: afterSeq, limit: 50 });
|
|
2358
|
-
const messages = await client._rpcPipeline.runPullSerialized(key, () =>
|
|
2499
|
+
const messages = await client._rpcPipeline.runPullSerialized(key, async () => {
|
|
2500
|
+
if (client._v2Session)
|
|
2501
|
+
return await client._pullGroupV2(groupId, afterSeq, 50, { gateLocked: true });
|
|
2502
|
+
const result = await client._rpcPipeline.rawCall('group.pull', {
|
|
2503
|
+
group_id: groupId,
|
|
2504
|
+
after_message_seq: afterSeq,
|
|
2505
|
+
device_id: client._deviceId,
|
|
2506
|
+
slot_id: client._slotId,
|
|
2507
|
+
limit: 50,
|
|
2508
|
+
_rpc_background: true,
|
|
2509
|
+
}, { background: true });
|
|
2510
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
2511
|
+
throw new Error('pull invalidated');
|
|
2512
|
+
if (isJsonObject(result))
|
|
2513
|
+
this.observeBackgroundPullResponse(ns, afterSeq, result, 50);
|
|
2514
|
+
await this.commitPlainForwardPage(ns, afterSeq, 'group.pull', result, groupId);
|
|
2515
|
+
return isJsonObject(result) && Array.isArray(result.messages) ? result.messages : [];
|
|
2516
|
+
}, true);
|
|
2359
2517
|
filled = messages.length;
|
|
2360
2518
|
this.prunePushedSeqs(ns);
|
|
2361
2519
|
}
|
|
2362
2520
|
catch (exc) {
|
|
2521
|
+
failed = true;
|
|
2363
2522
|
client._clientLog.warn(`group message gap-fill failed:${String(exc)}`);
|
|
2364
2523
|
}
|
|
2365
2524
|
finally {
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
client.
|
|
2525
|
+
if (this.isInlineGenerationCurrent(generation)) {
|
|
2526
|
+
client._gapFillDone.delete(dedupKey);
|
|
2527
|
+
this.runtime.delivery.setGapFillActive(false);
|
|
2528
|
+
if (filled > 0 && client._seqTracker.getContiguousSeq(ns) > afterSeq) {
|
|
2529
|
+
this.recordBackgroundPullDemand(ns, 0, true);
|
|
2530
|
+
}
|
|
2531
|
+
this.schedulePendingPullIfNeeded(ns, 'gap-fill-complete');
|
|
2532
|
+
this.finishBackgroundPull(ns, afterSeq, failed);
|
|
2370
2533
|
}
|
|
2371
|
-
this.schedulePendingPullIfNeeded(ns, 'gap-fill-complete');
|
|
2372
2534
|
}
|
|
2373
2535
|
}
|
|
2374
2536
|
async fillGroupEventGap(groupId, options) {
|
|
@@ -2390,6 +2552,7 @@ export class MessageDeliveryEngine {
|
|
|
2390
2552
|
const dedupKey = `group_event_pull:${ns}`;
|
|
2391
2553
|
if (client._gapFillDone.has(dedupKey))
|
|
2392
2554
|
return;
|
|
2555
|
+
this.recordBackgroundPullDemand(ns, 0, true);
|
|
2393
2556
|
client._gapFillDone.add(dedupKey);
|
|
2394
2557
|
this.runtime.delivery.setGapFillActive(true);
|
|
2395
2558
|
let continuationAfterSeq = 0;
|
|
@@ -2409,6 +2572,10 @@ export class MessageDeliveryEngine {
|
|
|
2409
2572
|
_rpc_background: true,
|
|
2410
2573
|
};
|
|
2411
2574
|
const result = await client.call('group.pull_events', request);
|
|
2575
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
2576
|
+
throw new Error('pull invalidated');
|
|
2577
|
+
if (isJsonObject(result))
|
|
2578
|
+
this.observeBackgroundPullResponse(ns, nextAfterSeq, result, 50);
|
|
2412
2579
|
if (!isJsonObject(result))
|
|
2413
2580
|
return;
|
|
2414
2581
|
const events = result.events;
|
|
@@ -2455,8 +2622,10 @@ export class MessageDeliveryEngine {
|
|
|
2455
2622
|
await this.drainOrderedMessages(ns, undefined, false, false, undefined, 'pull', deliveryThrough);
|
|
2456
2623
|
if (!this.isInlineGenerationCurrent(generation))
|
|
2457
2624
|
throw new Error('pull invalidated');
|
|
2458
|
-
if (hasDissolvedEvent)
|
|
2625
|
+
if (hasDissolvedEvent) {
|
|
2626
|
+
this.backgroundPullDemands.delete(ns);
|
|
2459
2627
|
break;
|
|
2628
|
+
}
|
|
2460
2629
|
if (contiguousSeq === undefined)
|
|
2461
2630
|
client._seqTracker.onPullResult(ns, eventObjects, nextAfterSeq);
|
|
2462
2631
|
else
|
|
@@ -2504,15 +2673,12 @@ export class MessageDeliveryEngine {
|
|
|
2504
2673
|
client._clientLog.warn(`group event gap-fill failed:${String(exc)}`);
|
|
2505
2674
|
}
|
|
2506
2675
|
finally {
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
this.
|
|
2513
|
-
group_id: groupId,
|
|
2514
|
-
_online_hint_after_event_seq: continuationAfterSeq,
|
|
2515
|
-
});
|
|
2676
|
+
if (this.isInlineGenerationCurrent(generation)) {
|
|
2677
|
+
client._gapFillDone.delete(dedupKey);
|
|
2678
|
+
this.runtime.delivery.setGapFillActive(false);
|
|
2679
|
+
if (!client._rpcPipeline)
|
|
2680
|
+
this.syncStopped(failed ? 'aborted' : 'pull_drained');
|
|
2681
|
+
this.finishBackgroundPull(ns, afterSeq, failed);
|
|
2516
2682
|
}
|
|
2517
2683
|
}
|
|
2518
2684
|
}
|
|
@@ -2568,6 +2734,9 @@ export class MessageDeliveryEngine {
|
|
|
2568
2734
|
if (!groupId)
|
|
2569
2735
|
return;
|
|
2570
2736
|
const ns = `group:${groupId}`;
|
|
2737
|
+
const generation = this.captureInlineGeneration();
|
|
2738
|
+
const afterSeq = this.syncState(ns).ack;
|
|
2739
|
+
this.recordBackgroundPullDemand(ns, positiveSafeSequenceHint(data.seq), true);
|
|
2571
2740
|
const targets = this.onlineUnreadHintTargets ?? new Map();
|
|
2572
2741
|
const owners = this.onlineUnreadHintOwners ?? new Set();
|
|
2573
2742
|
this.onlineUnreadHintTargets = targets;
|
|
@@ -2577,11 +2746,16 @@ export class MessageDeliveryEngine {
|
|
|
2577
2746
|
return;
|
|
2578
2747
|
owners.add(ns);
|
|
2579
2748
|
client._safeAsync((async () => {
|
|
2749
|
+
let failed = false;
|
|
2750
|
+
let attemptAfterSeq = afterSeq;
|
|
2580
2751
|
try {
|
|
2581
2752
|
while (true) {
|
|
2582
2753
|
const throughSeq = targets.get(ns) ?? 0;
|
|
2583
2754
|
const ackBefore = this.syncState(ns).ack;
|
|
2755
|
+
attemptAfterSeq = ackBefore;
|
|
2584
2756
|
await this.runGroupForwardRecovery(groupId, ns, 50, true, throughSeq);
|
|
2757
|
+
if (!this.isInlineGenerationCurrent(generation))
|
|
2758
|
+
return;
|
|
2585
2759
|
const ackAfter = this.syncState(ns).ack;
|
|
2586
2760
|
const target = targets.get(ns) ?? 0;
|
|
2587
2761
|
if (ackAfter >= target || ackAfter <= ackBefore)
|
|
@@ -2589,6 +2763,7 @@ export class MessageDeliveryEngine {
|
|
|
2589
2763
|
}
|
|
2590
2764
|
}
|
|
2591
2765
|
catch (exc) {
|
|
2766
|
+
failed = true;
|
|
2592
2767
|
client._clientLog?.debug(`online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
2593
2768
|
}
|
|
2594
2769
|
finally {
|
|
@@ -2596,6 +2771,8 @@ export class MessageDeliveryEngine {
|
|
|
2596
2771
|
targets.delete(ns);
|
|
2597
2772
|
if (this.onlineUnreadHintOwners === owners)
|
|
2598
2773
|
owners.delete(ns);
|
|
2774
|
+
if (this.isInlineGenerationCurrent(generation))
|
|
2775
|
+
this.finishBackgroundPull(ns, attemptAfterSeq, failed);
|
|
2599
2776
|
}
|
|
2600
2777
|
})());
|
|
2601
2778
|
}
|
|
@@ -2604,6 +2781,7 @@ export class MessageDeliveryEngine {
|
|
|
2604
2781
|
const groupId = String(data.group_id ?? '').trim();
|
|
2605
2782
|
if (!groupId || client._sessionOptions?.background_sync === false)
|
|
2606
2783
|
return;
|
|
2784
|
+
this.recordBackgroundPullDemand(`group_event:${groupId}`, positiveSafeSequenceHint(data.event_seq), true);
|
|
2607
2785
|
const rawAfter = Number(data._online_hint_after_event_seq ?? 0);
|
|
2608
2786
|
const afterSeq = Number.isSafeInteger(rawAfter) && rawAfter > 0 ? rawAfter : 0;
|
|
2609
2787
|
client._safeAsync(this.fillGroupEventGap(groupId, {
|
|
@@ -3378,22 +3556,30 @@ export class MessageDeliveryEngine {
|
|
|
3378
3556
|
}
|
|
3379
3557
|
return;
|
|
3380
3558
|
}
|
|
3559
|
+
if (client._sessionOptions?.background_sync !== false)
|
|
3560
|
+
this.recordBackgroundPullDemand(ns, seq);
|
|
3381
3561
|
const pullActive = client._rpcPipeline?.hasPullActivity?.(ns) === true;
|
|
3382
3562
|
if (pullActive || !this.beginRealtimeSync(ns)) {
|
|
3383
3563
|
this.recordPendingPull(ns, seq);
|
|
3384
3564
|
client._clientLog?.debug(`V2 group push queued behind in-flight realtime sync: ns=${ns} seq=${seq}`);
|
|
3385
3565
|
return;
|
|
3386
3566
|
}
|
|
3567
|
+
const generation = this.captureInlineGeneration();
|
|
3568
|
+
let failed = false;
|
|
3387
3569
|
try {
|
|
3388
3570
|
// namespace 串行区必须覆盖 Tail 与其后至多一次 Forward 的完整周期。
|
|
3389
3571
|
await this.runGroupRealtimeSync(groupId, ns, seq, 50, false);
|
|
3390
3572
|
}
|
|
3391
3573
|
catch (exc) {
|
|
3574
|
+
failed = true;
|
|
3392
3575
|
client._clientLog.warn(`V2 group push auto-sync failed: group=${groupId} err=${formatDeliveryError(exc)}`);
|
|
3393
3576
|
}
|
|
3394
3577
|
finally {
|
|
3395
|
-
this.
|
|
3396
|
-
|
|
3578
|
+
if (this.isInlineGenerationCurrent(generation)) {
|
|
3579
|
+
this.endRealtimeSync(ns);
|
|
3580
|
+
this.schedulePendingPullIfNeeded(ns, 'push-auto-pull-complete');
|
|
3581
|
+
this.finishBackgroundPull(ns, before.ack, failed);
|
|
3582
|
+
}
|
|
3397
3583
|
}
|
|
3398
3584
|
}
|
|
3399
3585
|
async onV2PushNotification(data) {
|
|
@@ -3466,31 +3652,60 @@ export class MessageDeliveryEngine {
|
|
|
3466
3652
|
}
|
|
3467
3653
|
return;
|
|
3468
3654
|
}
|
|
3655
|
+
if (client._sessionOptions?.background_sync !== false)
|
|
3656
|
+
this.recordBackgroundPullDemand(ns, pushSeq);
|
|
3469
3657
|
const pullActive = client._rpcPipeline?.hasPullActivity?.(ns) === true;
|
|
3470
3658
|
if (pullActive || !this.beginRealtimeSync(ns)) {
|
|
3471
3659
|
this.recordPendingPull(ns, pushSeq);
|
|
3472
3660
|
client._clientLog?.debug(`V2 P2P push queued behind in-flight realtime sync: ns=${ns} seq=${pushSeq}`);
|
|
3473
3661
|
return;
|
|
3474
3662
|
}
|
|
3663
|
+
const generation = this.captureInlineGeneration();
|
|
3664
|
+
let failed = false;
|
|
3475
3665
|
try {
|
|
3476
3666
|
await this.runP2PRealtimeSync(ns, pushSeq, 50, false);
|
|
3477
3667
|
}
|
|
3478
3668
|
catch (exc) {
|
|
3669
|
+
failed = true;
|
|
3479
3670
|
client._clientLog.warn(`V2 P2P push auto-sync failed: ${formatDeliveryError(exc)}`);
|
|
3480
3671
|
}
|
|
3481
3672
|
finally {
|
|
3482
|
-
this.
|
|
3483
|
-
|
|
3673
|
+
if (this.isInlineGenerationCurrent(generation)) {
|
|
3674
|
+
this.endRealtimeSync(ns);
|
|
3675
|
+
this.schedulePendingPullIfNeeded(ns, 'push-auto-pull-complete');
|
|
3676
|
+
this.finishBackgroundPull(ns, before.ack, failed);
|
|
3677
|
+
}
|
|
3484
3678
|
}
|
|
3485
3679
|
}
|
|
3486
3680
|
enqueueOnlineUnreadP2pHint(data) {
|
|
3487
3681
|
const client = this.runtime.client;
|
|
3488
|
-
if (!client._aid || !client._v2Session)
|
|
3682
|
+
if (!client._aid || !client._v2Session || client._sessionOptions?.background_sync === false)
|
|
3489
3683
|
return;
|
|
3490
3684
|
const ns = `p2p:${client._aid}`;
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3685
|
+
const generation = this.captureInlineGeneration();
|
|
3686
|
+
const afterSeq = this.syncState(ns).ack;
|
|
3687
|
+
this.recordBackgroundPullDemand(ns, positiveSafeSequenceHint(data.seq), true);
|
|
3688
|
+
const owners = this.onlineUnreadHintOwners ?? new Set();
|
|
3689
|
+
this.onlineUnreadHintOwners = owners;
|
|
3690
|
+
if (owners.has(ns))
|
|
3691
|
+
return;
|
|
3692
|
+
owners.add(ns);
|
|
3693
|
+
client._safeAsync((async () => {
|
|
3694
|
+
let failed = false;
|
|
3695
|
+
try {
|
|
3696
|
+
await this.runP2PForwardRecovery(ns, 50, true);
|
|
3697
|
+
}
|
|
3698
|
+
catch (exc) {
|
|
3699
|
+
failed = true;
|
|
3700
|
+
client._clientLog?.debug(`P2P online unread hint background Forward failed: ns=${ns} err=${formatDeliveryError(exc)}`);
|
|
3701
|
+
}
|
|
3702
|
+
finally {
|
|
3703
|
+
if (this.onlineUnreadHintOwners === owners)
|
|
3704
|
+
owners.delete(ns);
|
|
3705
|
+
if (this.isInlineGenerationCurrent(generation))
|
|
3706
|
+
this.finishBackgroundPull(ns, afterSeq, failed);
|
|
3707
|
+
}
|
|
3708
|
+
})());
|
|
3494
3709
|
}
|
|
3495
3710
|
async restoreSeqTrackerState() {
|
|
3496
3711
|
const client = this.runtime.client;
|