From 8a078acaa6aa795e80346f7fef5ddf60b7aefc66 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Thu, 23 Apr 2026 14:19:41 +0530 Subject: [PATCH] perf(telegram): bound forum metadata cache --- extensions/telegram/src/bot/helpers.test.ts | 14 +++++++++ extensions/telegram/src/bot/helpers.ts | 34 ++++++++++++++++++--- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/extensions/telegram/src/bot/helpers.test.ts b/extensions/telegram/src/bot/helpers.test.ts index c78cb595cc0..12d0550fcb7 100644 --- a/extensions/telegram/src/bot/helpers.test.ts +++ b/extensions/telegram/src/bot/helpers.test.ts @@ -74,6 +74,20 @@ describe("resolveTelegramForumFlag", () => { expect(getChat).toHaveBeenCalledTimes(1); }); + it("refreshes cached forum metadata from explicit Telegram updates", async () => { + const getChat = vi.fn(async () => ({ is_forum: true })); + const params = { + chatId: -100654, + chatType: "supergroup" as const, + isGroup: true, + getChat, + }; + await expect(resolveTelegramForumFlag(params)).resolves.toBe(true); + await expect(resolveTelegramForumFlag({ ...params, isForum: false })).resolves.toBe(false); + await expect(resolveTelegramForumFlag(params)).resolves.toBe(false); + expect(getChat).toHaveBeenCalledTimes(1); + }); + it("returns false when forum lookup is unavailable", async () => { const getChat = vi.fn(async () => { throw new Error("lookup failed"); diff --git a/extensions/telegram/src/bot/helpers.ts b/extensions/telegram/src/bot/helpers.ts index 2a2f8effaed..89ddbff4518 100644 --- a/extensions/telegram/src/bot/helpers.ts +++ b/extensions/telegram/src/bot/helpers.ts @@ -40,7 +40,26 @@ export { }; const TELEGRAM_GENERAL_TOPIC_ID = 1; -const telegramForumFlagByChatId = new Map(); +const TELEGRAM_FORUM_FLAG_CACHE_MAX_CHATS = 1024; +const TELEGRAM_FORUM_FLAG_CACHE_TTL_MS = 10 * 60_000; +const telegramForumFlagByChatId = new Map(); + +function cacheTelegramForumFlag(chatId: string | number, isForum: boolean, nowMs = Date.now()) { + const cacheKey = String(chatId); + if ( + !telegramForumFlagByChatId.has(cacheKey) && + telegramForumFlagByChatId.size >= TELEGRAM_FORUM_FLAG_CACHE_MAX_CHATS + ) { + const oldestKey = telegramForumFlagByChatId.keys().next().value; + if (oldestKey !== undefined) { + telegramForumFlagByChatId.delete(oldestKey); + } + } + telegramForumFlagByChatId.set(cacheKey, { + expiresAtMs: nowMs + TELEGRAM_FORUM_FLAG_CACHE_TTL_MS, + isForum, + }); +} function hadUnsafeTelegramText(raw: unknown, sanitized: string): boolean { return typeof raw === "string" && raw.trim().length > 0 && sanitized.trim().length === 0; @@ -67,19 +86,26 @@ export async function resolveTelegramForumFlag(params: { getChat?: TelegramGetChat; }): Promise { if (typeof params.isForum === "boolean") { + if (params.isGroup && params.chatType === "supergroup") { + cacheTelegramForumFlag(params.chatId, params.isForum); + } return params.isForum; } if (!params.isGroup || params.chatType !== "supergroup" || !params.getChat) { return false; } const cacheKey = String(params.chatId); + const nowMs = Date.now(); const cached = telegramForumFlagByChatId.get(cacheKey); - if (cached !== undefined) { - return cached; + if (cached && cached.expiresAtMs > nowMs) { + return cached.isForum; + } + if (cached) { + telegramForumFlagByChatId.delete(cacheKey); } try { const resolved = extractTelegramForumFlag(await params.getChat(params.chatId)) === true; - telegramForumFlagByChatId.set(cacheKey, resolved); + cacheTelegramForumFlag(params.chatId, resolved, nowMs); return resolved; } catch { return false;