from __future__ import annotations import hashlib import time from collections import OrderedDict from typing import Any from yuxi.utils.logging_config import logger class MessageDebouncer: def __init__(self, max_entries: int = 1000, ttl_seconds: float = 300): self._cache: OrderedDict[str, float] = OrderedDict() self._max_entries = max_entries self._ttl_seconds = ttl_seconds def _cleanup(self, now: float) -> None: expired = [k for k, ts in self._cache.items() if now - ts > self._ttl_seconds] for k in expired: del self._cache[k] def build_debounce_key(self, update: dict[str, Any]) -> str | None: message = update.get("message") or update.get("edited_message") or update.get("channel_post") if not message: return None chat_id = message.get("chat", {}).get("id", "") message_id = message.get("message_id", "") text = message.get("text", "") or message.get("caption", "") components = f"{chat_id}|{message_id}|{text[:100]}" return hashlib.sha256(components.encode()).hexdigest()[:16] def is_duplicate(self, debounce_key: str) -> bool: now = time.monotonic() self._cleanup(now) if debounce_key in self._cache: logger.debug(f"[Telegram] Debounced duplicate message: {debounce_key}") return True if len(self._cache) >= self._max_entries: self._cache.popitem(last=False) self._cache[debounce_key] = now return False def clear_entry(self, debounce_key: str) -> None: self._cache.pop(debounce_key, None) def cache_size(self) -> int: return len(self._cache) class ConnectTimeoutConfig: def __init__(self, config: dict[str, Any] | None = None): cfg = config or {} self.connect_timeout = float(cfg.get("connect_timeout", 30)) self.read_timeout = float(cfg.get("read_timeout", 60)) self.write_timeout = float(cfg.get("write_timeout", 30)) self.pool_timeout = float(cfg.get("pool_timeout", 30)) def get_request_kwargs(self) -> dict[str, Any]: timeout_value = self.read_timeout if hasattr(self, "connect_timeout"): timeout_value = float(self.connect_timeout) return { "connect_timeout": self.connect_timeout, "read_timeout": self.read_timeout, "write_timeout": self.write_timeout, "pool_timeout": self.pool_timeout, }