diff --git a/scripts/telegram-bridge.js b/scripts/telegram-bridge.js index c51a5529a47..27d5d7ba4dc 100755 --- a/scripts/telegram-bridge.js +++ b/scripts/telegram-bridge.js @@ -41,6 +41,10 @@ if (!API_KEY) { console.error("NVIDIA_API_KEY required"); process.exit(1); } let offset = 0; const activeSessions = new Map(); // chatId → message history +const COOLDOWN_MS = 5000; +const lastMessageTime = new Map(); +const busyChats = new Set(); + // ── Telegram API helpers ────────────────────────────────────────── function tgApi(method, body) { @@ -198,6 +202,24 @@ async function poll() { continue; } + // Rate limiting: per-chat cooldown + const now = Date.now(); + const lastTime = lastMessageTime.get(chatId) || 0; + if (now - lastTime < COOLDOWN_MS) { + const wait = Math.ceil((COOLDOWN_MS - (now - lastTime)) / 1000); + await sendMessage(chatId, `Please wait ${wait}s before sending another message.`, msg.message_id); + continue; + } + + // Per-chat serialization: reject if this chat already has an active session + if (busyChats.has(chatId)) { + await sendMessage(chatId, "Still processing your previous message.", msg.message_id); + continue; + } + + lastMessageTime.set(chatId, now); + busyChats.add(chatId); + // Send typing indicator await sendTyping(chatId); @@ -212,6 +234,8 @@ async function poll() { } catch (err) { clearInterval(typingInterval); await sendMessage(chatId, `Error: ${err.message}`, msg.message_id); + } finally { + busyChats.delete(chatId); } } } @@ -219,8 +243,8 @@ async function poll() { console.error("Poll error:", err.message); } - // Continue polling - setTimeout(poll, 100); + // Continue polling (1s floor prevents tight-loop resource waste) + setTimeout(poll, 1000); } // ── Main ──────────────────────────────────────────────────────────