diff --git a/src/routes/files.ts b/src/routes/files.ts index c1234a8..d7144ec 100644 --- a/src/routes/files.ts +++ b/src/routes/files.ts @@ -16,7 +16,7 @@ type RequestWithParams = Request & { const getTelegramFileInfo = async (telegramFileId: string, public_id: string) => { const cacheKey = `file_info_${telegramFileId}`; - let fileInfo = fileInfoCache.get(cacheKey); + let fileInfo = fileInfoCache.get(cacheKey) as any; if (!fileInfo) { fileInfo = await getFileInfo(telegramFileId); @@ -26,7 +26,7 @@ const getTelegramFileInfo = async (telegramFileId: string, public_id: string) => logger.debug('File info from cache', { public_id, cacheKey }); } - return fileInfo; + return fileInfo as { file_size: number; mime_type: string; file_path: string; bot_token: string }; }; const buildTelegramFileUrl = (filePath: string, botToken: string): string => diff --git a/src/utils/telegram.ts b/src/utils/telegram.ts index 6ed37ef..bea4d52 100644 --- a/src/utils/telegram.ts +++ b/src/utils/telegram.ts @@ -241,27 +241,35 @@ export const forwardMediaGroupToStorage = async ( }; export const getFileInfo = async (telegramFileId: string): Promise => { - try { - const { result, botToken } = await executeWithBotRetry( - async (activeBot, activeToken) => ({ - result: await activeBot.telegram.getFile(telegramFileId), - botToken: activeToken, - }), - ); - - const fileData = result as unknown as TelegramFileInfo; - return { - file_size: fileData.file_size || 0, - mime_type: fileData.mime_type || 'application/octet-stream', - file_path: fileData.file_path || '', - bot_token: botToken, - }; - } catch (error: unknown) { - logger.error('Failed to get file info', { - error: error instanceof Error ? error.message : String(error), - }); - throw error; + let lastError: unknown; + for (const activeBot of bots) { + try { + const result = await activeBot.telegram.getFile(telegramFileId); + const fileData = result as unknown as Omit; + return { + file_size: fileData.file_size || 0, + mime_type: fileData.mime_type || 'application/octet-stream', + file_path: fileData.file_path || '', + bot_token: activeBot.telegram.token, + }; + } catch (error: unknown) { + lastError = error; + const errorStr = error instanceof Error ? error.message : String(error); + if ( + errorStr.includes('wrong file_id') || + errorStr.includes('file is temporarily unavailable') || + errorStr.includes('retry after') + ) { + continue; + } + throw error; + } } + + logger.error('Failed to get file info from any bot', { + error: lastError instanceof Error ? lastError.message : String(lastError), + }); + throw lastError; }; export const getBot = (): Telegraf => bots[nextBotIndex]; diff --git a/src/utils/zip.ts b/src/utils/zip.ts index 73f662b..6791972 100644 --- a/src/utils/zip.ts +++ b/src/utils/zip.ts @@ -1,4 +1,6 @@ +import { once } from 'node:events'; import { createReadStream, createWriteStream } from 'node:fs'; +import { finished } from 'node:stream/promises'; import { open, stat } from 'node:fs/promises'; import { basename } from 'node:path'; import { nanoid } from 'nanoid'; @@ -65,18 +67,13 @@ const writeChunk = async ( chunk: Buffer, ): Promise => { if (!writer.write(chunk)) { - await new Promise((resolve, reject) => { - writer.once('drain', resolve); - writer.once('error', reject); - }); + await once(writer, 'drain'); } }; const finishWriter = async (writer: ReturnType): Promise => { - await new Promise((resolve, reject) => { - writer.end(() => resolve()); - writer.once('error', reject); - }); + writer.end(); + await finished(writer); }; export const sanitizeZipEntryName = (fileName: string, usedNames = new Set()): string => { @@ -102,16 +99,10 @@ export const sanitizeZipEntryName = (fileName: string, usedNames = new Set => { let crc = 0xffffffff; - - await new Promise((resolve, reject) => { - const reader = createReadStream(tempPath); - reader.on('data', (chunk: Buffer) => { - crc = updateCrc32(crc, chunk); - }); - reader.once('end', resolve); - reader.once('error', reject); - }); - + const reader = createReadStream(tempPath); + for await (const chunk of reader) { + crc = updateCrc32(crc, chunk as Buffer); + } return (crc ^ 0xffffffff) >>> 0; }; @@ -154,14 +145,10 @@ export const createZip = async (files: ZipInputFile[]): Promise => { ]); await writeHashed(localHeader); - await new Promise((resolve, reject) => { - const reader = createReadStream(file.tempPath); - reader.on('data', (chunk: Buffer) => { - void writeHashed(chunk).catch(reject); - }); - reader.once('end', resolve); - reader.once('error', reject); - }); + const reader = createReadStream(file.tempPath); + for await (const chunk of reader) { + await writeHashed(chunk as Buffer); + } entries.push({ fileName: file.fileName,