mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-09-21 05:21:43 +00:00
feat(worker): native TDLib forward from source to destination channel
This commit is contained in:
@@ -0,0 +1,39 @@
|
|||||||
|
import { describe, it, expect, vi } from "vitest";
|
||||||
|
import { forwardArchiveToChannel } from "./forward.js";
|
||||||
|
|
||||||
|
function fakeClient(response: unknown) {
|
||||||
|
return { invoke: vi.fn(async () => response) } as never;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("forwardArchiveToChannel", () => {
|
||||||
|
it("sorts message ids ascending and sends them via forwardMessages", async () => {
|
||||||
|
const invoke = vi.fn(async (req: { message_ids: number[] }) => ({
|
||||||
|
messages: req.message_ids.map((id) => ({ id: id + 1000 })),
|
||||||
|
}));
|
||||||
|
const client = { invoke } as never;
|
||||||
|
|
||||||
|
const result = await forwardArchiveToChannel(client, 111n, 222n, [30n, 10n, 20n]);
|
||||||
|
|
||||||
|
expect(invoke).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
_: "forwardMessages",
|
||||||
|
chat_id: 222,
|
||||||
|
from_chat_id: 111,
|
||||||
|
message_ids: [10, 20, 30],
|
||||||
|
send_copy: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(result.messageId).toBe(1010n);
|
||||||
|
expect(result.messageIds).toEqual([1010n, 1020n, 1030n]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws when Telegram returns null for a message (can't be forwarded)", async () => {
|
||||||
|
const client = fakeClient({ messages: [{ id: 1001 }, null] });
|
||||||
|
await expect(forwardArchiveToChannel(client, 111n, 222n, [10n, 20n])).rejects.toThrow(/could not forward/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("throws when the response has the wrong number of messages", async () => {
|
||||||
|
const client = fakeClient({ messages: [{ id: 1001 }] });
|
||||||
|
await expect(forwardArchiveToChannel(client, 111n, 222n, [10n, 20n])).rejects.toThrow(/expected 2/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import type { Client } from "tdl";
|
||||||
|
import { childLogger } from "../util/logger.js";
|
||||||
|
import { withFloodWait } from "../util/retry.js";
|
||||||
|
|
||||||
|
const log = childLogger("forward");
|
||||||
|
|
||||||
|
export interface ForwardResult {
|
||||||
|
messageId: bigint;
|
||||||
|
messageIds: bigint[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forward all parts of an archive set from the source chat directly to the
|
||||||
|
* destination chat via TDLib's forwardMessages — no download, no re-upload.
|
||||||
|
* Only usable when the source channel allows forwarding
|
||||||
|
* (TelegramChannel.allowsForwarding); the caller is responsible for that
|
||||||
|
* check. message_ids must be in strictly increasing order per the TDLib API,
|
||||||
|
* so this always sorts them regardless of the order they're passed in.
|
||||||
|
*/
|
||||||
|
export async function forwardArchiveToChannel(
|
||||||
|
client: Client,
|
||||||
|
fromChatId: bigint,
|
||||||
|
toChatId: bigint,
|
||||||
|
sourceMessageIds: bigint[],
|
||||||
|
): Promise<ForwardResult> {
|
||||||
|
const sortedIds = [...sourceMessageIds].sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
||||||
|
const numericIds = sortedIds.map((id) => Number(id));
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
{ fromChatId: Number(fromChatId), toChatId: Number(toChatId), count: numericIds.length },
|
||||||
|
"Forwarding archive to destination channel"
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = (await withFloodWait(
|
||||||
|
() =>
|
||||||
|
client.invoke({
|
||||||
|
_: "forwardMessages",
|
||||||
|
chat_id: Number(toChatId),
|
||||||
|
topic_id: null,
|
||||||
|
from_chat_id: Number(fromChatId),
|
||||||
|
message_ids: numericIds,
|
||||||
|
options: null,
|
||||||
|
send_copy: false,
|
||||||
|
remove_caption: false,
|
||||||
|
} as never),
|
||||||
|
"forwardMessages"
|
||||||
|
)) as { messages: ({ id: number } | null)[] };
|
||||||
|
|
||||||
|
const forwarded = result.messages;
|
||||||
|
if (!forwarded || forwarded.length !== numericIds.length) {
|
||||||
|
throw new Error(
|
||||||
|
`forwardMessages returned ${forwarded?.length ?? 0} messages, expected ${numericIds.length}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageIds: bigint[] = [];
|
||||||
|
for (let i = 0; i < forwarded.length; i++) {
|
||||||
|
const msg = forwarded[i];
|
||||||
|
if (!msg) {
|
||||||
|
throw new Error(
|
||||||
|
`forwardMessages could not forward source message ${sortedIds[i]} (Telegram returned null — message may not be forwardable)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
messageIds.push(BigInt(msg.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
{ fromChatId: Number(fromChatId), toChatId: Number(toChatId), messageIds: messageIds.map(Number) },
|
||||||
|
"Forward confirmed by Telegram"
|
||||||
|
);
|
||||||
|
|
||||||
|
return { messageId: messageIds[0], messageIds };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user