(
taskId: string,
options: BackupCallbacks,
signal?: AbortSignal
)
| 928 | |
| 929 | try { |
| 930 | throwIfAborted(signal); |
| 931 | // 获取消息总数 |
| 932 | const messages = await safeGetMessages(client, task.sourceId, { limit: 1 }); |
| 933 | const totalCount = (messages as any).total || 0; |
| 934 | task.totalMessages = totalCount; |
| 935 | |
| 936 | if (task.reverse) { |
| 937 | // ===== 正序模式:两阶段 ===== |
| 938 | // Phase 1: 收集所有消息 ID(API 返回顺序:新→旧) |
| 939 | const allIds: number[] = []; |
| 940 | let collectOffset = 0; |
| 941 | let collecting = true; |
| 942 | |
| 943 | while (collecting) { |
| 944 | throwIfAborted(signal); |
| 945 | const batch = await safeGetMessages(client, task.sourceId, { |
| 946 | limit: batchSize, |
| 947 | offsetId: collectOffset, |
| 948 | }); |
| 949 | |
| 950 | if (batch.length === 0) { |
| 951 | collecting = false; |
| 952 | break; |
| 953 | } |
| 954 | |
| 955 | for (const msg of batch) { |
| 956 | allIds.push(msg.id); |
| 957 | } |
| 958 | collectOffset = batch[batch.length - 1].id; |
| 959 | |
| 960 | // 收集阶段进度(每 200 条报告一次) |
| 961 | if (options.onProgress && allIds.length % 200 === 0) { |
| 962 | await options.onProgress(0, totalCount); |
| 963 | } |
| 964 | } |
| 965 | |
| 966 | // 反转:旧→新(正序) |
| 967 | allIds.reverse(); |
| 968 | task.totalMessages = allIds.length; |
| 969 | |
| 970 | // Phase 2: 按正序逐条转发 |
| 971 | const startIndex = task.lastMessageId |
| 972 | ? allIds.indexOf(task.lastMessageId) + 1 |
| 973 | : 0; |
| 974 | |
| 975 | for (let i = startIndex; i < allIds.length; i++) { |
| 976 | if (task.status !== "running") break; |
| 977 | |
| 978 | try { |
| 979 | throwIfAborted(signal); |
| 980 | await this.rateLimiter.throttle(signal); |
| 981 | throwIfAborted(signal); |
| 982 | |
| 983 | await client.forwardMessages(task.targetId, { |
| 984 | messages: [allIds[i]], |
| 985 | fromPeer: task.sourceId, |
| 986 | }); |
| 987 |
no test coverage detected