from __future__ import annotations import time from collections import OrderedDict DEFAULT_CACHE_TTL_S = 3600.0 DEFAULT_MAX_ENTRIES = 2048 class SentMessageCache: def __init__(self, max_entries: int = DEFAULT_MAX_ENTRIES, ttl_s: float = DEFAULT_CACHE_TTL_S): self._cache: OrderedDict[str, tuple[str, float]] = OrderedDict() self._max_entries = max_entries self._ttl = ttl_s def put(self, key: str, thread_ts: str) -> None: self._evict_expired() if key in self._cache: self._cache.move_to_end(key) elif len(self._cache) >= self._max_entries: self._cache.popitem(last=False) self._cache[key] = (thread_ts, time.monotonic()) def get(self, key: str) -> str | None: self._evict_expired() entry = self._cache.get(key) if entry is None: return None ts, stored_at = entry if time.monotonic() - stored_at > self._ttl: self._cache.pop(key, None) return None self._cache.move_to_end(key) return ts def clear(self) -> None: self._cache.clear() def _evict_expired(self) -> None: now = time.monotonic() expired = [k for k, (_, t) in self._cache.items() if now - t > self._ttl] for k in expired: self._cache.pop(k, None) @property def size(self) -> int: self._evict_expired() return len(self._cache)