ForcePilot/backend/package/yuxi/channels/adapters/mattermost/debounce.py
Kris 002d601d1b feat(mattermost): 实现完整的 Mattermost 适配器模块
新增 Mattermost 渠道完整实现,包含适配器核心、消息处理、交互回调、命令支持、安全校验、多账号管理等功能,支持机器人消息发送、交互按钮、命令注册、投票功能以及配置动态修改等特性。
2026-05-12 00:46:12 +08:00

46 lines
1.5 KiB
Python

from __future__ import annotations
import hashlib
import time
class InboundDebouncer:
"""入站消息防抖 — 按 channel + thread key 去重。
防止 Mattermost WebSocket 重复推送导致的多次触发。
"""
def __init__(self, ttl_ms: int = 1000, max_entries: int = 2000):
self._ttl_ms = ttl_ms
self._max_entries = max_entries
self._entries: dict[str, float] = {}
def should_process(self, channel_id: str, thread_id: str, content: str) -> bool:
key = self._build_key(channel_id, thread_id, content)
now = time.monotonic()
if key in self._entries:
if now - self._entries[key] < self._ttl_ms / 1000:
return False
self._entries[key] = now
self._prune(now)
return True
def _build_key(self, channel_id: str, thread_id: str, content: str) -> str:
raw = f"{channel_id}:{thread_id}:{content[:100]}"
return hashlib.md5(raw.encode()).hexdigest()
def _prune(self, now: float) -> None:
if len(self._entries) > self._max_entries:
cutoff = now - self._ttl_ms / 1000
self._entries = {k: v for k, v in self._entries.items() if v > cutoff}
if len(self._entries) > self._max_entries:
overflow = len(self._entries) - self._max_entries
keys = sorted(self._entries, key=lambda k: self._entries[k])[:overflow]
for k in keys:
del self._entries[k]
def clear(self) -> None:
self._entries.clear()