ForcePilot/backend/package/yuxi/channels/adapters/telegram/debounce.py
Kris 71fec609bb feat(telegram-adapter): 实现完整的Telegram适配器基础代码
新增了Telegram适配器的全套基础模块,包括:
1.  核心适配器入口与会话工具
2.  账号管理、认证与配置系统
3.  连接相关的轮询、Webhook、更新偏移管理
4.  话题路由、管理与缓存系统
5.  消息反抖动、超时配置与工具类
6.  响应式UI与命令交互系统
7.  反应表情与通知系统
8.  审批与安全审计模块
9.  健康检查与状态监控
10. 贴纸缓存与视觉工具
11. 流式响应与协作功能
12. 群组迁移与目标归一化处理
2026-05-12 00:49:52 +08:00

74 lines
2.5 KiB
Python

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,
}