from __future__ import annotations import time from collections import OrderedDict DEFAULT_TTL = 3600 class ExpiredDict: def __init__(self, ttl: int = DEFAULT_TTL): self._ttl = ttl self._data: OrderedDict[str, tuple[object, float]] = OrderedDict() def __contains__(self, key: str) -> bool: self._cleanup_expired() return key in self._data def add(self, key: str, value: object = True) -> None: self._cleanup_expired() self._data[key] = (value, time.time() + self._ttl) self._data.move_to_end(key) def _cleanup_expired(self) -> None: now = time.time() while self._data: _, (_, expires) = next(iter(self._data.items())) if expires > now: break self._data.popitem(last=False) class DingTalkDeduplicator: def __init__(self, ttl: int = DEFAULT_TTL, hot_reload: bool = False): self._received = ExpiredDict(ttl) self._hot_reload = hot_reload self._start_time = time.time() def is_duplicate(self, msg_id: str, create_time: float | None = None) -> bool: if msg_id in self._received: return True if self._hot_reload and create_time: if create_time < self._start_time - 60: return True self._received.add(msg_id) return False def is_my_msg(self, msg) -> bool: return getattr(msg, "my_msg", False)