@agentunion/fastaun 0.5.31 → 0.5.33
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 +69 -1
- package/_packed_docs/CHANGELOG.md +69 -1
- package/_packed_docs/sdk/0.5.32-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +350 -0
- package/_packed_docs/sdk/0.5.32-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +319 -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 +316 -0
- 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 +304 -0
- package/_packed_docs/sdk/09-storage-rpc-manual.md +33 -16
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +12 -5
- 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 +459 -0
- 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 +554 -0
- package/_packed_docs/sdk/INDEX.md +27 -5
- package/_packed_docs/sdk//345/255/220AID/344/277/256/346/224/271agent.md/351/200/232/347/237/245Owner/345/234/272/346/231/257/346/214/207/345/215/227.md +234 -0
- package/dist/agent-md.d.ts +2 -1
- package/dist/agent-md.js +17 -0
- package/dist/agent-md.js.map +1 -1
- package/dist/client/control-messages.d.ts +22 -6
- package/dist/client/control-messages.js +210 -148
- package/dist/client/control-messages.js.map +1 -1
- package/dist/client/delivery.d.ts +3 -0
- package/dist/client/delivery.js +67 -3
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.d.ts +3 -0
- package/dist/client/group-state.js +48 -14
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.js +3 -2
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +9 -3
- package/dist/client/rpc-pipeline.js +80 -27
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +13 -1
- package/dist/client/v2-e2ee.js +32 -19
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +13 -5
- package/dist/client.js +121 -37
- package/dist/client.js.map +1 -1
- package/dist/group-fs.js +1 -1
- package/dist/group-fs.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/ownership-workflow.d.ts +23 -3
- package/dist/ownership-workflow.js +39 -16
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/pubsub/binding.d.ts +54 -0
- package/dist/pubsub/binding.js +343 -0
- package/dist/pubsub/binding.js.map +1 -0
- package/dist/pubsub/channel.d.ts +45 -0
- package/dist/pubsub/channel.js +137 -0
- package/dist/pubsub/channel.js.map +1 -0
- package/dist/pubsub/client.d.ts +93 -0
- package/dist/pubsub/client.js +318 -0
- package/dist/pubsub/client.js.map +1 -0
- package/dist/pubsub/credentials.d.ts +51 -0
- package/dist/pubsub/credentials.js +360 -0
- package/dist/pubsub/credentials.js.map +1 -0
- package/dist/pubsub/errors.d.ts +5 -0
- package/dist/pubsub/errors.js +6 -0
- package/dist/pubsub/errors.js.map +1 -0
- package/dist/pubsub/index.d.ts +48 -0
- package/dist/pubsub/index.js +152 -0
- package/dist/pubsub/index.js.map +1 -0
- package/dist/pubsub/scheduler.d.ts +58 -0
- package/dist/pubsub/scheduler.js +249 -0
- package/dist/pubsub/scheduler.js.map +1 -0
- package/dist/pubsub/service.d.ts +100 -0
- package/dist/pubsub/service.js +650 -0
- package/dist/pubsub/service.js.map +1 -0
- package/dist/pubsub/types.d.ts +119 -0
- package/dist/pubsub/types.js +2 -0
- package/dist/pubsub/types.js.map +1 -0
- package/dist/storage/lowlevel.d.ts +4 -2
- package/dist/storage/lowlevel.js +46 -7
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/read-cache.d.ts +7 -3
- package/dist/storage/read-cache.js +149 -18
- package/dist/storage/read-cache.js.map +1 -1
- package/dist/storage/vfs.d.ts +5 -2
- package/dist/storage/vfs.js +13 -3
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +8 -2
- package/dist/tools/cross-sdk-agent.js +81 -16
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/tools/pubsub-actor.d.ts +27 -0
- package/dist/tools/pubsub-actor.js +260 -0
- package/dist/tools/pubsub-actor.js.map +1 -0
- package/dist/transport.d.ts +25 -1
- package/dist/transport.js +175 -10
- 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/transport.js
CHANGED
|
@@ -19,8 +19,15 @@ import { messageClassOf } from './client/control-messages.js';
|
|
|
19
19
|
const MAX_WS_PAYLOAD_SIZE = 1_000_000;
|
|
20
20
|
const MAX_RPC_INFLIGHT = 16;
|
|
21
21
|
const MAX_BACKGROUND_RPC_INFLIGHT = 8;
|
|
22
|
+
const MAX_EVENT_RPC_INFLIGHT = 4;
|
|
23
|
+
const MAX_PULL_RPC_INFLIGHT = 4;
|
|
22
24
|
const WORKER_START_TIMEOUT_MS = 2_000;
|
|
23
25
|
const SHORT_RPC_WORKER_START_TIMEOUT_MS = 2_000;
|
|
26
|
+
function normalizeRpcBackground(value) {
|
|
27
|
+
if (value === 'event' || value === 'pull')
|
|
28
|
+
return value;
|
|
29
|
+
return value === true ? true : false;
|
|
30
|
+
}
|
|
24
31
|
const _noopLogger = {
|
|
25
32
|
error: () => { },
|
|
26
33
|
warn: () => { },
|
|
@@ -569,9 +576,14 @@ export class RPCTransport {
|
|
|
569
576
|
_pending = new Map();
|
|
570
577
|
_pendingMeta = new Map();
|
|
571
578
|
_pendingBackground = new Set();
|
|
579
|
+
_pendingEvent = new Set();
|
|
580
|
+
_pendingPull = new Set();
|
|
572
581
|
_rpcQueue = [];
|
|
573
582
|
_backgroundRpcQueue = [];
|
|
574
583
|
_drainingRpcQueue = false;
|
|
584
|
+
_rateLimitUntil = 0;
|
|
585
|
+
_rateLimitTimer = null;
|
|
586
|
+
_rateLimitWaiters = new Set();
|
|
575
587
|
_onForegroundDrained;
|
|
576
588
|
_onRpcResponse;
|
|
577
589
|
_sendQueue = [];
|
|
@@ -605,6 +617,19 @@ export class RPCTransport {
|
|
|
605
617
|
_workerConnectAttempt = 0;
|
|
606
618
|
_workerBufferedEvents = [];
|
|
607
619
|
_workerOptions;
|
|
620
|
+
get inflightCounts() {
|
|
621
|
+
return {
|
|
622
|
+
total: this._pending.size,
|
|
623
|
+
background: this._pendingBackground.size,
|
|
624
|
+
event: this._pendingEvent.size,
|
|
625
|
+
pull: this._pendingPull.size,
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
get foregroundWaiting() {
|
|
629
|
+
return this._rpcQueue.length;
|
|
630
|
+
}
|
|
631
|
+
_eventBackpressure(timeout = 30_000) { if (this._worker)
|
|
632
|
+
return this._workerCommand({ type: 'event_backpressure', timeout }); return Promise.resolve(this.foregroundWaiting > 0 || Number(this._ws?.bufferedAmount ?? 0) >= 65536); }
|
|
608
633
|
constructor(opts) {
|
|
609
634
|
this._logger = opts.logger ?? _noopLogger;
|
|
610
635
|
this._dispatcher = opts.eventDispatcher;
|
|
@@ -782,6 +807,8 @@ export class RPCTransport {
|
|
|
782
807
|
}
|
|
783
808
|
this._workerDisabled = true;
|
|
784
809
|
this._workerConnected = false;
|
|
810
|
+
for (const wake of this._rateLimitWaiters)
|
|
811
|
+
wake();
|
|
785
812
|
this._workerConnecting = false;
|
|
786
813
|
this._workerGeneration = null;
|
|
787
814
|
this._workerBufferedEvents = [];
|
|
@@ -837,6 +864,12 @@ export class RPCTransport {
|
|
|
837
864
|
}
|
|
838
865
|
if (this._workerGeneration === null || message.generation !== this._workerGeneration)
|
|
839
866
|
return;
|
|
867
|
+
if (message.event === '_transport.rate_limit') {
|
|
868
|
+
const until = Number(message.payload?.until_ms);
|
|
869
|
+
if (Number.isFinite(until))
|
|
870
|
+
this._rateLimitUntil = Math.max(this._rateLimitUntil, until);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
840
873
|
if (message.event === '_transport.risk_control') {
|
|
841
874
|
this._dispatchRiskControl(message.payload, () => message.generation === this._workerGeneration);
|
|
842
875
|
return;
|
|
@@ -856,6 +889,8 @@ export class RPCTransport {
|
|
|
856
889
|
}
|
|
857
890
|
if (message.event === '_transport.disconnect') {
|
|
858
891
|
this._workerConnected = false;
|
|
892
|
+
for (const wake of this._rateLimitWaiters)
|
|
893
|
+
wake();
|
|
859
894
|
this._workerGeneration = null;
|
|
860
895
|
const payload = (message.payload && typeof message.payload === 'object')
|
|
861
896
|
? { ...message.payload }
|
|
@@ -911,7 +946,7 @@ export class RPCTransport {
|
|
|
911
946
|
const id = `worker-${++this._workerSeq}`;
|
|
912
947
|
const timeoutMs = command.type === 'call'
|
|
913
948
|
? null
|
|
914
|
-
: command.type === 'connect' ? this._connectTimeout + 1_000 : 30_000;
|
|
949
|
+
: command.type === 'connect' ? this._connectTimeout + 1_000 : command.type === 'event_backpressure' ? command.timeout ?? 30_000 : 30_000;
|
|
915
950
|
let posted = false;
|
|
916
951
|
const promise = new Promise((resolve, reject) => {
|
|
917
952
|
const timer = timeoutMs === null ? null : setTimeout(() => {
|
|
@@ -1495,6 +1530,9 @@ export class RPCTransport {
|
|
|
1495
1530
|
async close() {
|
|
1496
1531
|
if (this._worker) {
|
|
1497
1532
|
const worker = this._worker;
|
|
1533
|
+
this._workerConnected = false;
|
|
1534
|
+
for (const wake of this._rateLimitWaiters)
|
|
1535
|
+
wake();
|
|
1498
1536
|
try {
|
|
1499
1537
|
await this._workerCommand({ type: 'close' });
|
|
1500
1538
|
}
|
|
@@ -1531,6 +1569,11 @@ export class RPCTransport {
|
|
|
1531
1569
|
this._handshakeAbort = null;
|
|
1532
1570
|
abortHandshake?.();
|
|
1533
1571
|
this._closed = true;
|
|
1572
|
+
for (const wake of this._rateLimitWaiters)
|
|
1573
|
+
wake();
|
|
1574
|
+
if (this._rateLimitTimer !== null)
|
|
1575
|
+
clearTimeout(this._rateLimitTimer);
|
|
1576
|
+
this._rateLimitTimer = null;
|
|
1534
1577
|
this._riskDeliveries = 0;
|
|
1535
1578
|
this._startSendQueue();
|
|
1536
1579
|
this._connectionGeneration += 1;
|
|
@@ -1543,6 +1586,8 @@ export class RPCTransport {
|
|
|
1543
1586
|
this._pending.clear();
|
|
1544
1587
|
this._pendingMeta.clear();
|
|
1545
1588
|
this._pendingBackground.clear();
|
|
1589
|
+
this._pendingEvent.clear();
|
|
1590
|
+
this._pendingPull.clear();
|
|
1546
1591
|
for (const queued of this._rpcQueue) {
|
|
1547
1592
|
clearTimeout(queued.pending.timer);
|
|
1548
1593
|
queued.pending.reject(new ConnectionError('transport closed'));
|
|
@@ -1647,7 +1692,7 @@ export class RPCTransport {
|
|
|
1647
1692
|
const requestLog = withLogContext(this._logger, requestContext);
|
|
1648
1693
|
const responseLog = withLogContext(requestLog, { direction: 'inbound', peerAid: requestContext.peerAid });
|
|
1649
1694
|
requestLog.debug(`RPC request queued: method=${method}`);
|
|
1650
|
-
const request = this._workerCommand({ type: 'call', method, params, timeout, trace, background, ...(onSent ? { trackSent: true } : {}) }, undefined, onSent, sentCheckpoint);
|
|
1695
|
+
const request = this._workerCommand({ type: 'call', method, params, timeout, trace, background, rateLimitUntil: this._rateLimitUntil, ...(onSent ? { trackSent: true } : {}) }, undefined, onSent, sentCheckpoint);
|
|
1651
1696
|
const result = request.then((result) => {
|
|
1652
1697
|
responseLog.debug(`RPC response ok: method=${method}`);
|
|
1653
1698
|
return result;
|
|
@@ -1667,15 +1712,20 @@ export class RPCTransport {
|
|
|
1667
1712
|
});
|
|
1668
1713
|
}
|
|
1669
1714
|
const rpcId = `rpc-${crypto.randomBytes(8).toString('hex')}`;
|
|
1670
|
-
const
|
|
1715
|
+
const deadline = typeof params?._rpc_deadline === 'number' ? params._rpc_deadline : undefined;
|
|
1716
|
+
const effectiveTimeout = deadline === undefined ? timeout ?? this._timeout : Math.min(timeout ?? this._timeout, deadline - Date.now());
|
|
1717
|
+
if (effectiveTimeout <= 0)
|
|
1718
|
+
throw new TimeoutError(`rpc timeout before send: ${method}`, { retryable: true });
|
|
1671
1719
|
const tStart = Date.now();
|
|
1672
1720
|
// 注入 _trace(会话级或调用级 mode 非 off 时)
|
|
1673
1721
|
const effectiveTraceMode = (trace === 'off' || trace === 'log' || trace === 'diag') ? trace : this._traceMode;
|
|
1674
1722
|
let traceId = '';
|
|
1675
1723
|
const sendParams = { ...(params ?? {}) };
|
|
1676
1724
|
const localParams = sendParams;
|
|
1677
|
-
const
|
|
1725
|
+
const selectedBackground = normalizeRpcBackground(background !== false ? background : localParams._rpc_background);
|
|
1726
|
+
const backgroundRpc = selectedBackground === true && ['message.peers', 'message.pull', 'message.v2.pull', 'message.ack', 'message.v2.ack', 'group.pull', 'group.v2.pull', 'group.pull_events', 'group.ack_messages', 'group.v2.ack'].includes(method) ? 'pull' : selectedBackground;
|
|
1678
1727
|
delete localParams._rpc_background;
|
|
1728
|
+
delete localParams._rpc_deadline;
|
|
1679
1729
|
const requestContext = trafficLogContext('outbound', sendParams);
|
|
1680
1730
|
const requestLog = withLogContext(this._logger, requestContext);
|
|
1681
1731
|
const responseLog = withLogContext(requestLog, {
|
|
@@ -1706,7 +1756,9 @@ export class RPCTransport {
|
|
|
1706
1756
|
const timer = setTimeout(() => {
|
|
1707
1757
|
this._removeRpc(rpcId, pending);
|
|
1708
1758
|
requestLog.warn(`RPC timeout: method=${method}, id=${rpcId}, elapsed=${Date.now() - tStart}ms, timeout=${effectiveTimeout}ms`);
|
|
1709
|
-
reject(
|
|
1759
|
+
reject(backgroundRpc && !pending.sent && this._rateLimitRemainingMs() > 0
|
|
1760
|
+
? this._rateLimitError()
|
|
1761
|
+
: new TimeoutError(`rpc timeout: ${method}`, { retryable: true }));
|
|
1710
1762
|
this._drainRpcQueue();
|
|
1711
1763
|
}, effectiveTimeout);
|
|
1712
1764
|
const pending = {
|
|
@@ -1787,7 +1839,7 @@ export class RPCTransport {
|
|
|
1787
1839
|
pending,
|
|
1788
1840
|
tStart,
|
|
1789
1841
|
timeoutMs: effectiveTimeout,
|
|
1790
|
-
background:
|
|
1842
|
+
background: backgroundRpc,
|
|
1791
1843
|
priority: this._messagePriority(localParams.message_class),
|
|
1792
1844
|
logger: requestLog,
|
|
1793
1845
|
onSent,
|
|
@@ -1843,6 +1895,64 @@ export class RPCTransport {
|
|
|
1843
1895
|
}
|
|
1844
1896
|
_messagePriority(messageClass) { return messageClass === 'sdk_control' ? 2 : messageClass === 'control' ? 1 : 0; }
|
|
1845
1897
|
_isRiskControlMethod(method) { return ['gateway.risk_ack', 'meta.ping', 'system.ping', 'ping', 'auth.disconnect'].includes(method); }
|
|
1898
|
+
_rateLimitRemainingMs() { return Math.max(0, this._rateLimitUntil - Date.now()); }
|
|
1899
|
+
_rateLimitError() {
|
|
1900
|
+
const remaining = this._rateLimitRemainingMs();
|
|
1901
|
+
return new RateLimitError('RPC rate limited: local backoff', {
|
|
1902
|
+
code: -32429, retryable: true, data: { retry_after_seconds: Math.ceil(remaining / 1000), retry_after_ms: Math.ceil(remaining) },
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
async _waitRateLimit(timeout = this._timeout, signal) {
|
|
1906
|
+
const started = Date.now();
|
|
1907
|
+
while (this._rateLimitRemainingMs() > 0) {
|
|
1908
|
+
if (signal?.aborted)
|
|
1909
|
+
throw new TimeoutError('rpc cancelled', { retryable: true });
|
|
1910
|
+
if (!this.isConnected())
|
|
1911
|
+
throw new ConnectionError('transport closed');
|
|
1912
|
+
const remaining = this._rateLimitRemainingMs();
|
|
1913
|
+
const budget = timeout - (Date.now() - started);
|
|
1914
|
+
if (budget <= 0)
|
|
1915
|
+
throw this._rateLimitError();
|
|
1916
|
+
await new Promise(resolve => {
|
|
1917
|
+
const wake = () => {
|
|
1918
|
+
clearTimeout(timer);
|
|
1919
|
+
this._rateLimitWaiters.delete(wake);
|
|
1920
|
+
signal?.removeEventListener('abort', wake);
|
|
1921
|
+
resolve();
|
|
1922
|
+
};
|
|
1923
|
+
const timer = setTimeout(wake, Math.min(remaining, budget, 2_147_483_647));
|
|
1924
|
+
this._rateLimitWaiters.add(wake);
|
|
1925
|
+
signal?.addEventListener('abort', wake, { once: true });
|
|
1926
|
+
});
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
_observeRateLimit(error) {
|
|
1930
|
+
if (![4290, 429, -32429, -32029].includes(Number(error.code)))
|
|
1931
|
+
return;
|
|
1932
|
+
const data = error.data;
|
|
1933
|
+
const seconds = Number(data?.retry_after_seconds);
|
|
1934
|
+
const milliseconds = Number(data?.retry_after_ms);
|
|
1935
|
+
this._rateLimitUntil = Math.max(this._rateLimitUntil, Date.now() + Math.max(60_000, Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : 0, Number.isFinite(milliseconds) && milliseconds > 0 ? milliseconds : 0));
|
|
1936
|
+
this._worker?.postMessage({ type: 'rate_limit', rateLimitUntil: this._rateLimitUntil });
|
|
1937
|
+
if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
|
|
1938
|
+
parentPort.postMessage({ type: 'event', generation: this._connectionGeneration, event: '_transport.rate_limit', payload: { until_ms: this._rateLimitUntil } });
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
_canDispatch(entry) {
|
|
1942
|
+
if (this._pending.size >= MAX_RPC_INFLIGHT && !this._isRiskControlMethod(entry.method))
|
|
1943
|
+
return false;
|
|
1944
|
+
if (!entry.background)
|
|
1945
|
+
return true;
|
|
1946
|
+
if (this._rateLimitRemainingMs() > 0)
|
|
1947
|
+
return false;
|
|
1948
|
+
if (this._pendingBackground.size >= MAX_BACKGROUND_RPC_INFLIGHT)
|
|
1949
|
+
return false;
|
|
1950
|
+
if (entry.background === 'event')
|
|
1951
|
+
return this._pendingEvent.size < MAX_EVENT_RPC_INFLIGHT;
|
|
1952
|
+
if (entry.background === 'pull')
|
|
1953
|
+
return this._pendingPull.size < MAX_PULL_RPC_INFLIGHT;
|
|
1954
|
+
return true;
|
|
1955
|
+
}
|
|
1846
1956
|
_enqueueSend(task, priority = 0) {
|
|
1847
1957
|
const result = new Promise((resolve, reject) => { this._sendQueue.push({ task, priority, resolve, reject }); });
|
|
1848
1958
|
this._startSendQueue();
|
|
@@ -1956,6 +2066,8 @@ export class RPCTransport {
|
|
|
1956
2066
|
this._pending.delete(rpcId);
|
|
1957
2067
|
this._pendingMeta.delete(rpcId);
|
|
1958
2068
|
this._pendingBackground.delete(rpcId);
|
|
2069
|
+
this._pendingEvent.delete(rpcId);
|
|
2070
|
+
this._pendingPull.delete(rpcId);
|
|
1959
2071
|
}
|
|
1960
2072
|
if (this._rpcQueue.length > 0) {
|
|
1961
2073
|
this._rpcQueue = this._rpcQueue.filter((entry) => entry.rpcId !== rpcId || (pending !== undefined && entry.pending !== pending));
|
|
@@ -1979,10 +2091,12 @@ export class RPCTransport {
|
|
|
1979
2091
|
let entry;
|
|
1980
2092
|
let selectedQueue;
|
|
1981
2093
|
let selectedIndex = -1;
|
|
1982
|
-
for (const queue of [this._rpcQueue,
|
|
2094
|
+
for (const queue of [this._rpcQueue, this._backgroundRpcQueue]) {
|
|
1983
2095
|
for (let index = 0; index < queue.length; index++) {
|
|
1984
2096
|
if (controlOnly && !this._isRiskControlMethod(queue[index].method))
|
|
1985
2097
|
continue;
|
|
2098
|
+
if (!this._canDispatch(queue[index]))
|
|
2099
|
+
continue;
|
|
1986
2100
|
if (!entry || queue[index].priority > entry.priority) {
|
|
1987
2101
|
entry = queue[index];
|
|
1988
2102
|
selectedQueue = queue;
|
|
@@ -1999,7 +2113,9 @@ export class RPCTransport {
|
|
|
1999
2113
|
if (elapsed >= entry.timeoutMs) {
|
|
2000
2114
|
clearTimeout(entry.pending.timer);
|
|
2001
2115
|
entry.logger.warn(`RPC queue timeout: method=${entry.method}, id=${entry.rpcId}, elapsed=${elapsed}ms, timeout=${entry.timeoutMs}ms`);
|
|
2002
|
-
entry.pending.reject(
|
|
2116
|
+
entry.pending.reject(entry.background && this._rateLimitRemainingMs() > 0
|
|
2117
|
+
? this._rateLimitError()
|
|
2118
|
+
: new TimeoutError(`rpc timeout before send: ${entry.method}`, { retryable: true }));
|
|
2003
2119
|
continue;
|
|
2004
2120
|
}
|
|
2005
2121
|
this._pending.set(entry.rpcId, entry.pending);
|
|
@@ -2012,16 +2128,36 @@ export class RPCTransport {
|
|
|
2012
2128
|
});
|
|
2013
2129
|
if (entry.background) {
|
|
2014
2130
|
this._pendingBackground.add(entry.rpcId);
|
|
2131
|
+
if (entry.background === 'event')
|
|
2132
|
+
this._pendingEvent.add(entry.rpcId);
|
|
2133
|
+
if (entry.background === 'pull')
|
|
2134
|
+
this._pendingPull.add(entry.rpcId);
|
|
2015
2135
|
}
|
|
2136
|
+
let deferredForRateLimit = false;
|
|
2016
2137
|
this._sendText(entry.payload, `rpc ${entry.method}`, () => {
|
|
2017
2138
|
if (this._pending.get(entry.rpcId) !== entry.pending)
|
|
2018
2139
|
return false;
|
|
2140
|
+
if (Date.now() - entry.tStart >= entry.timeoutMs) {
|
|
2141
|
+
this._removeRpc(entry.rpcId, entry.pending);
|
|
2142
|
+
entry.pending.reject(new TimeoutError(`rpc timeout before send: ${entry.method}`, { retryable: true }));
|
|
2143
|
+
return false;
|
|
2144
|
+
}
|
|
2145
|
+
if (entry.background && this._rateLimitRemainingMs() > 0) {
|
|
2146
|
+
deferredForRateLimit = true;
|
|
2147
|
+
this._removeRpc(entry.rpcId, entry.pending);
|
|
2148
|
+
this._backgroundRpcQueue.push(entry);
|
|
2149
|
+
this._drainRpcQueue();
|
|
2150
|
+
return false;
|
|
2151
|
+
}
|
|
2019
2152
|
this._requestCheck?.(`rpc:${entry.method}`);
|
|
2153
|
+
entry.pending.sent = true;
|
|
2020
2154
|
return true;
|
|
2021
2155
|
}, this._isRiskControlMethod(entry.method) ? 3 : entry.priority).then(() => {
|
|
2022
2156
|
entry.logger.debug(`RPC request sent: method=${entry.method}, id=${entry.rpcId}, background=${entry.background}`);
|
|
2023
2157
|
return entry.onSent?.();
|
|
2024
2158
|
}).catch((err) => {
|
|
2159
|
+
if (deferredForRateLimit)
|
|
2160
|
+
return;
|
|
2025
2161
|
if (this._pending.get(entry.rpcId) !== entry.pending)
|
|
2026
2162
|
return;
|
|
2027
2163
|
this._removeRpc(entry.rpcId, entry.pending);
|
|
@@ -2035,6 +2171,13 @@ export class RPCTransport {
|
|
|
2035
2171
|
}
|
|
2036
2172
|
finally {
|
|
2037
2173
|
this._drainingRpcQueue = false;
|
|
2174
|
+
if (this._rateLimitTimer !== null)
|
|
2175
|
+
clearTimeout(this._rateLimitTimer);
|
|
2176
|
+
this._rateLimitTimer = null;
|
|
2177
|
+
const remaining = this._rateLimitRemainingMs();
|
|
2178
|
+
if (!this._closed && this._backgroundRpcQueue.length && remaining > 0) {
|
|
2179
|
+
this._rateLimitTimer = setTimeout(() => { this._rateLimitTimer = null; this._drainRpcQueue(); }, Math.min(remaining, 2_147_483_647));
|
|
2180
|
+
}
|
|
2038
2181
|
if (foregroundDrained)
|
|
2039
2182
|
this._onForegroundDrained?.();
|
|
2040
2183
|
}
|
|
@@ -2086,6 +2229,11 @@ export class RPCTransport {
|
|
|
2086
2229
|
this._stopWebSocketHeartbeat(ws);
|
|
2087
2230
|
const wasClosed = this._closed;
|
|
2088
2231
|
this._closed = true;
|
|
2232
|
+
for (const wake of this._rateLimitWaiters)
|
|
2233
|
+
wake();
|
|
2234
|
+
if (this._rateLimitTimer !== null)
|
|
2235
|
+
clearTimeout(this._rateLimitTimer);
|
|
2236
|
+
this._rateLimitTimer = null;
|
|
2089
2237
|
this._ws = null;
|
|
2090
2238
|
this._lastCloseCode = Number.isFinite(code) ? code : null;
|
|
2091
2239
|
this._logger.debug(`WebSocket closed: code=${code}, intentional close=${wasClosed}`);
|
|
@@ -2097,6 +2245,8 @@ export class RPCTransport {
|
|
|
2097
2245
|
this._pending.clear();
|
|
2098
2246
|
this._pendingMeta.clear();
|
|
2099
2247
|
this._pendingBackground.clear();
|
|
2248
|
+
this._pendingEvent.clear();
|
|
2249
|
+
this._pendingPull.clear();
|
|
2100
2250
|
for (const queued of this._rpcQueue) {
|
|
2101
2251
|
clearTimeout(queued.pending.timer);
|
|
2102
2252
|
queued.pending.reject(err);
|
|
@@ -2229,12 +2379,16 @@ export class RPCTransport {
|
|
|
2229
2379
|
this._receiveRiskControl(state);
|
|
2230
2380
|
delete error.data.risk_state;
|
|
2231
2381
|
}
|
|
2382
|
+
if (isJsonObject(error))
|
|
2383
|
+
this._observeRateLimit(error);
|
|
2232
2384
|
const rpcId = String(message.id);
|
|
2233
2385
|
const pending = this._pending.get(rpcId);
|
|
2234
2386
|
if (pending) {
|
|
2235
2387
|
this._pending.delete(rpcId);
|
|
2236
2388
|
this._pendingMeta.delete(rpcId);
|
|
2237
2389
|
this._pendingBackground.delete(rpcId);
|
|
2390
|
+
this._pendingEvent.delete(rpcId);
|
|
2391
|
+
this._pendingPull.delete(rpcId);
|
|
2238
2392
|
pending.resolve(message);
|
|
2239
2393
|
this._drainRpcQueue();
|
|
2240
2394
|
this._onRpcResponse?.();
|
|
@@ -2424,6 +2578,12 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
|
|
|
2424
2578
|
parentPort.on('message', async (command) => {
|
|
2425
2579
|
const id = command.id;
|
|
2426
2580
|
try {
|
|
2581
|
+
if (command.type === 'rate_limit') {
|
|
2582
|
+
if (Number.isFinite(command.rateLimitUntil))
|
|
2583
|
+
actor['_rateLimitUntil'] = Math.max(actor['_rateLimitUntil'], command.rateLimitUntil);
|
|
2584
|
+
actor['_drainRpcQueue']();
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2427
2587
|
if (command.type === 'risk_release') {
|
|
2428
2588
|
if (command.generation === bridgeGeneration())
|
|
2429
2589
|
actor['_finishRiskDelivery']();
|
|
@@ -2457,12 +2617,14 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
|
|
|
2457
2617
|
break;
|
|
2458
2618
|
}
|
|
2459
2619
|
case 'call': {
|
|
2620
|
+
if (Number.isFinite(command.rateLimitUntil))
|
|
2621
|
+
actor['_rateLimitUntil'] = Math.max(actor['_rateLimitUntil'], command.rateLimitUntil);
|
|
2460
2622
|
const request = (command.trackSent
|
|
2461
2623
|
? actor['_callWithSent'](String(command.method ?? ''), command.params ?? undefined, async () => {
|
|
2462
2624
|
if (id)
|
|
2463
2625
|
parentPort.postMessage({ type: 'sent', id, generation: bridgeGeneration() });
|
|
2464
|
-
}, command.timeout, command.trace,
|
|
2465
|
-
: actor.call(String(command.method ?? ''), command.params ?? undefined, command.timeout, command.trace,
|
|
2626
|
+
}, command.timeout, command.trace, normalizeRpcBackground(command.background))
|
|
2627
|
+
: actor.call(String(command.method ?? ''), command.params ?? undefined, command.timeout, command.trace, normalizeRpcBackground(command.background)));
|
|
2466
2628
|
if (id)
|
|
2467
2629
|
active.set(id, request);
|
|
2468
2630
|
result = await request;
|
|
@@ -2470,6 +2632,9 @@ if (!isMainThread && Boolean(workerData?.aunTransportWorker) && parentPort) {
|
|
|
2470
2632
|
active.delete(id);
|
|
2471
2633
|
break;
|
|
2472
2634
|
}
|
|
2635
|
+
case 'event_backpressure':
|
|
2636
|
+
result = await actor._eventBackpressure();
|
|
2637
|
+
break;
|
|
2473
2638
|
case 'notify':
|
|
2474
2639
|
result = await actor.notify(String(command.method ?? ''), command.params);
|
|
2475
2640
|
break;
|