fix(telegram): move network fallback to resolver-scoped dispatchers (#40740)

Merged via squash.

Prepared head SHA: a4456d48b4
Co-authored-by: sircrumpet <4436535+sircrumpet@users.noreply.github.com>
Co-authored-by: obviyus <22031114+obviyus@users.noreply.github.com>
Reviewed-by: @obviyus
This commit is contained in:
Eugene
2026-03-10 15:58:51 +10:00
committed by GitHub
parent d1a59557b5
commit 45b74fb56c
23 changed files with 1641 additions and 390 deletions

View File

@@ -293,6 +293,62 @@ describe("resolveMedia getFile retry", () => {
expect(getFile).toHaveBeenCalledTimes(3);
expect(result).toBeNull();
});
it("uses caller-provided fetch impl for file downloads", async () => {
const getFile = vi.fn().mockResolvedValue({ file_path: "documents/file_42.pdf" });
const callerFetch = vi.fn() as unknown as typeof fetch;
fetchRemoteMedia.mockResolvedValueOnce({
buffer: Buffer.from("pdf-data"),
contentType: "application/pdf",
fileName: "file_42.pdf",
});
saveMediaBuffer.mockResolvedValueOnce({
path: "/tmp/file_42---uuid.pdf",
contentType: "application/pdf",
});
const result = await resolveMedia(
makeCtx("document", getFile),
MAX_MEDIA_BYTES,
BOT_TOKEN,
callerFetch,
);
expect(result).not.toBeNull();
expect(fetchRemoteMedia).toHaveBeenCalledWith(
expect.objectContaining({
fetchImpl: callerFetch,
}),
);
});
it("uses caller-provided fetch impl for sticker downloads", async () => {
const getFile = vi.fn().mockResolvedValue({ file_path: "stickers/file_0.webp" });
const callerFetch = vi.fn() as unknown as typeof fetch;
fetchRemoteMedia.mockResolvedValueOnce({
buffer: Buffer.from("sticker-data"),
contentType: "image/webp",
fileName: "file_0.webp",
});
saveMediaBuffer.mockResolvedValueOnce({
path: "/tmp/file_0.webp",
contentType: "image/webp",
});
const result = await resolveMedia(
makeCtx("sticker", getFile),
MAX_MEDIA_BYTES,
BOT_TOKEN,
callerFetch,
);
expect(result).not.toBeNull();
expect(fetchRemoteMedia).toHaveBeenCalledWith(
expect.objectContaining({
fetchImpl: callerFetch,
}),
);
});
});
describe("resolveMedia original filename preservation", () => {

View File

@@ -92,12 +92,20 @@ async function resolveTelegramFileWithRetry(
}
}
function resolveRequiredFetchImpl(proxyFetch?: typeof fetch): typeof fetch {
const fetchImpl = proxyFetch ?? globalThis.fetch;
if (!fetchImpl) {
function resolveRequiredFetchImpl(fetchImpl?: typeof fetch): typeof fetch {
const resolved = fetchImpl ?? globalThis.fetch;
if (!resolved) {
throw new Error("fetch is not available; set channels.telegram.proxy in config");
}
return fetchImpl;
return resolved;
}
function resolveOptionalFetchImpl(fetchImpl?: typeof fetch): typeof fetch | null {
try {
return resolveRequiredFetchImpl(fetchImpl);
} catch {
return null;
}
}
/** Default idle timeout for Telegram media downloads (30 seconds). */
@@ -134,7 +142,7 @@ async function resolveStickerMedia(params: {
ctx: TelegramContext;
maxBytes: number;
token: string;
proxyFetch?: typeof fetch;
fetchImpl?: typeof fetch;
}): Promise<
| {
path: string;
@@ -145,7 +153,7 @@ async function resolveStickerMedia(params: {
| null
| undefined
> {
const { msg, ctx, maxBytes, token, proxyFetch } = params;
const { msg, ctx, maxBytes, token, fetchImpl } = params;
if (!msg.sticker) {
return undefined;
}
@@ -165,15 +173,15 @@ async function resolveStickerMedia(params: {
logVerbose("telegram: getFile returned no file_path for sticker");
return null;
}
const fetchImpl = proxyFetch ?? globalThis.fetch;
if (!fetchImpl) {
const resolvedFetchImpl = resolveOptionalFetchImpl(fetchImpl);
if (!resolvedFetchImpl) {
logVerbose("telegram: fetch not available for sticker download");
return null;
}
const saved = await downloadAndSaveTelegramFile({
filePath: file.file_path,
token,
fetchImpl,
fetchImpl: resolvedFetchImpl,
maxBytes,
});
@@ -229,7 +237,7 @@ export async function resolveMedia(
ctx: TelegramContext,
maxBytes: number,
token: string,
proxyFetch?: typeof fetch,
fetchImpl?: typeof fetch,
): Promise<{
path: string;
contentType?: string;
@@ -242,7 +250,7 @@ export async function resolveMedia(
ctx,
maxBytes,
token,
proxyFetch,
fetchImpl,
});
if (stickerResolved !== undefined) {
return stickerResolved;
@@ -263,7 +271,7 @@ export async function resolveMedia(
const saved = await downloadAndSaveTelegramFile({
filePath: file.file_path,
token,
fetchImpl: resolveRequiredFetchImpl(proxyFetch),
fetchImpl: resolveRequiredFetchImpl(fetchImpl),
maxBytes,
telegramFileName: resolveTelegramFileName(msg),
});