






















@@ -1,3 +1,4 @@
1+import { setTimeout as sleep } from "node:timers/promises";
12import type {
23ChannelApprovalCapabilityHandlerContext,
34PendingApprovalView,
@@ -123,6 +124,9 @@ type MatrixPrepareTargetParams = {
123124rawTarget: MatrixRawApprovalTarget;
124125};
125126127+const MATRIX_APPROVAL_DELIVERY_ATTEMPTS = 3;
128+const MATRIX_APPROVAL_DELIVERY_RETRY_DELAY_MS = 250;
129+126130export type MatrixApprovalHandlerDeps = {
127131nowMs?: () => number;
128132sendMessage?: typeof sendMessageMatrix;
@@ -176,6 +180,25 @@ function isSingleMatrixMessageLimitError(error: unknown): boolean {
176180);
177181}
178182183+async function retryMatrixApprovalDelivery<T>(
184+operation: () => Promise<T>,
185+params: { shouldRetry?: (error: unknown) => boolean } = {},
186+): Promise<T> {
187+let lastError: unknown;
188+for (let attempt = 1; attempt <= MATRIX_APPROVAL_DELIVERY_ATTEMPTS; attempt += 1) {
189+try {
190+return await operation();
191+} catch (error) {
192+lastError = error;
193+if (attempt === MATRIX_APPROVAL_DELIVERY_ATTEMPTS || params.shouldRetry?.(error) === false) {
194+break;
195+}
196+await sleep(MATRIX_APPROVAL_DELIVERY_RETRY_DELAY_MS * attempt);
197+}
198+}
199+throw lastError;
200+}
201+179202async function prepareTarget(
180203params: MatrixPrepareTargetParams,
181204): Promise<PreparedMatrixTarget | null> {
@@ -194,11 +217,14 @@ async function prepareTarget(
194217accountId: resolved.accountId,
195218});
196219const repairDirectRooms = resolved.context.deps?.repairDirectRooms ?? repairMatrixDirectRooms;
197-const repaired = await repairDirectRooms({
198-client: resolved.context.client,
199-remoteUserId: target.id,
200-encrypted: account.config.encryption === true,
201-});
220+const repaired = await retryMatrixApprovalDelivery(
221+async () =>
222+await repairDirectRooms({
223+client: resolved.context.client,
224+remoteUserId: target.id,
225+encrypted: account.config.encryption === true,
226+}),
227+);
202228if (!repaired.activeRoomId) {
203229return null;
204230}
@@ -424,25 +450,32 @@ export const matrixApprovalNativeRuntime = createChannelApprovalNativeRuntimeAda
424450const reactMessage = resolved.context.deps?.reactMessage ?? reactMatrixMessage;
425451let result;
426452try {
427-result = await sendSingleTextMessage(preparedTarget.to, pendingPayload.text, {
428-cfg: cfg as CoreConfig,
429-accountId: resolved.accountId,
430-client: resolved.context.client,
431-threadId: preparedTarget.threadId,
432-extraContent: pendingPayload.extraContent,
433-});
453+result = await retryMatrixApprovalDelivery(
454+async () =>
455+await sendSingleTextMessage(preparedTarget.to, pendingPayload.text, {
456+cfg: cfg as CoreConfig,
457+accountId: resolved.accountId,
458+client: resolved.context.client,
459+threadId: preparedTarget.threadId,
460+extraContent: pendingPayload.extraContent,
461+}),
462+{ shouldRetry: (error) => !isSingleMatrixMessageLimitError(error) },
463+);
434464} catch (error) {
435465if (!isSingleMatrixMessageLimitError(error)) {
436466throw error;
437467}
438468const sendMessage = resolved.context.deps?.sendMessage ?? sendMessageMatrix;
439-result = await sendMessage(preparedTarget.to, pendingPayload.text, {
440-cfg: cfg as CoreConfig,
441-accountId: resolved.accountId,
442-client: resolved.context.client,
443-threadId: preparedTarget.threadId,
444-extraContent: pendingPayload.extraContent,
445-});
469+result = await retryMatrixApprovalDelivery(
470+async () =>
471+await sendMessage(preparedTarget.to, pendingPayload.text, {
472+cfg: cfg as CoreConfig,
473+accountId: resolved.accountId,
474+client: resolved.context.client,
475+threadId: preparedTarget.threadId,
476+extraContent: pendingPayload.extraContent,
477+}),
478+);
446479}
447480const receiptMessageIds = listMessageReceiptPlatformIds(result.receipt);
448481const platformMessageIds = receiptMessageIds.length
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。