From 10c968cf0105ed08e1a4412c3f142ac455ce3036 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Thu, 21 May 2026 22:55:42 +0700 Subject: [PATCH] feat: add file_hash column and related index to files table; refactor Telegram API utilities for improved file handling --- schema.sql | 1 + src/routes/files.ts | 2 +- src/routes/upload.ts | 13 +++------- src/utils/telegram.ts | 48 ++++++++----------------------------- test/telegram.test.ts | 55 +++++++------------------------------------ 5 files changed, 24 insertions(+), 95 deletions(-) diff --git a/schema.sql b/schema.sql index 015a77f..fe17f61 100644 --- a/schema.sql +++ b/schema.sql @@ -19,5 +19,6 @@ ALTER TABLE files ADD COLUMN IF NOT EXISTS file_hash VARCHAR; CREATE INDEX IF NOT EXISTS idx_files_public_id ON files(public_id); CREATE INDEX IF NOT EXISTS idx_files_telegram_file_id ON files(telegram_file_id); +CREATE INDEX IF NOT EXISTS idx_files_file_hash ON files(file_hash); CREATE INDEX IF NOT EXISTS idx_files_uploader_id ON files(uploader_id); CREATE INDEX IF NOT EXISTS idx_files_created_at ON files(created_at DESC); \ No newline at end of file diff --git a/src/routes/files.ts b/src/routes/files.ts index 48259ca..f7143ed 100644 --- a/src/routes/files.ts +++ b/src/routes/files.ts @@ -2,6 +2,7 @@ import { findFileByPublicId } from '../db/files'; import { formatCreatedAt, getErrorMessage } from '../utils/file'; import logger from '../utils/logger'; import { checkRateLimit } from '../utils/rateLimit'; +import { getBot } from '../utils/telegram'; type RequestWithParams = Request & { params?: { @@ -25,7 +26,6 @@ export const handleFileRedirect = async (req: RequestWithParams): Promise new Telegraf(token)); -const TELEGRAM_API_URL = `https://api.telegram.org/bot${config.botToken}/`; let currentBotIndex = 0; @@ -69,20 +68,6 @@ interface TelegramFileInfo { file_path: string; } -interface TelegramGetFileResponse { - ok: boolean; - description?: string; - result: { - file_id: string; - }; -} - -interface TelegramGetInfoResponse { - ok: boolean; - description?: string; - result: TelegramFileInfo; -} - interface UploadedTelegramFile { file_id?: string; file_unique_id?: string; @@ -256,32 +241,17 @@ export const forwardMediaGroupToStorage = async ( export const getFileInfo = async ( telegramFileId: string, - telegramFileUniqueId: string, ): Promise => { try { - const result = await fetch(`${TELEGRAM_API_URL}getFile`); - const data = (await result.json()) as TelegramGetFileResponse; - - if (!data.ok) { - throw new Error(data.description || 'Telegram API error'); - } - - const fileId = data.result.file_id === telegramFileId ? telegramFileId : telegramFileUniqueId; - const fileResult = await fetch(`${TELEGRAM_API_URL}getInfo`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ file_id: fileId }), - }); - const fileInfo = (await fileResult.json()) as TelegramGetInfoResponse; - - if (!fileInfo.ok) { - throw new Error(fileInfo.description || 'Telegram info error'); - } + const result = await executeWithBotRetry((activeBot) => + activeBot.telegram.getFile(telegramFileId), + ); + const fileData = result as unknown as TelegramFileInfo; return { - file_size: fileInfo.result.file_size, - mime_type: fileInfo.result.mime_type, - file_path: fileInfo.result.file_path, + file_size: fileData.file_size || 0, + mime_type: fileData.mime_type || 'application/octet-stream', + file_path: fileData.file_path || '', }; } catch (error: unknown) { logger.error('Failed to get file info', { @@ -291,4 +261,6 @@ export const getFileInfo = async ( } }; -export const getBot = (): Telegraf => bots[0]; +export const getBot = (): Telegraf => bots[currentBotIndex]; + +export const getCurrentBotIndex = (): number => currentBotIndex; diff --git a/test/telegram.test.ts b/test/telegram.test.ts index e3c3209..6690c60 100644 --- a/test/telegram.test.ts +++ b/test/telegram.test.ts @@ -46,6 +46,14 @@ mock.module('telegraf', () => { }, }), ), + getFile: mock(() => + Promise.resolve({ + file_id: 'some_file_id', + file_size: 98765, + mime_type: 'image/jpeg', + file_path: 'photos/file_0.jpg', + }), + ), }; } }, @@ -169,34 +177,7 @@ describe('Telegram API Utilities', () => { describe('getFileInfo', () => { it('should fetch file details successfully', async () => { - global.fetch = mock((url, _init) => { - if (url.endsWith('getFile')) { - return Promise.resolve( - new Response( - JSON.stringify({ - ok: true, - result: { file_id: 'some_file_id' }, - }), - ), - ); - } else if (url.endsWith('getInfo')) { - return Promise.resolve( - new Response( - JSON.stringify({ - ok: true, - result: { - file_size: 98765, - mime_type: 'image/jpeg', - file_path: 'photos/file_0.jpg', - }, - }), - ), - ); - } - return Promise.reject(new Error('Unknown URL')); - }); - - const result = await getFileInfo('some_file_id', 'some_unique_id'); + const result = await getFileInfo('some_file_id'); expect(result).toEqual({ file_size: 98765, @@ -204,23 +185,5 @@ describe('Telegram API Utilities', () => { file_path: 'photos/file_0.jpg', }); }); - - it('should handle error when getFile fails', async () => { - global.fetch = mock(() => - Promise.resolve( - new Response( - JSON.stringify({ - ok: false, - description: 'Bad Request: file_id invalid', - }), - ), - ), - ); - - await expect(getFileInfo('invalid_file_id', 'invalid_unique_id')).rejects.toThrow( - 'Bad Request: file_id invalid', - ); - expect(errorSpy).toHaveBeenCalled(); - }); }); });