74 lines
2.2 KiB
Python
74 lines
2.2 KiB
Python
|
|
import asyncio
|
||
|
|
import logging
|
||
|
|
import time
|
||
|
|
from dataclasses import dataclass, field
|
||
|
|
|
||
|
|
logger = logging.getLogger(__name__)
|
||
|
|
|
||
|
|
MAX_RETRY = 3
|
||
|
|
WAIT_WINDOW_SEC = 4.0
|
||
|
|
POLL_INTERVAL_SEC = 0.1
|
||
|
|
|
||
|
|
_passive_state: "PassiveReplyState | None" = None
|
||
|
|
|
||
|
|
|
||
|
|
def _get_passive_state() -> "PassiveReplyState":
|
||
|
|
global _passive_state
|
||
|
|
if _passive_state is None:
|
||
|
|
_passive_state = PassiveReplyState()
|
||
|
|
return _passive_state
|
||
|
|
|
||
|
|
|
||
|
|
def _reset_passive_state() -> None:
|
||
|
|
global _passive_state
|
||
|
|
_passive_state = None
|
||
|
|
|
||
|
|
|
||
|
|
@dataclass
|
||
|
|
class PassiveReplyState:
|
||
|
|
cache: dict[str, list[tuple[str, str]]] = field(default_factory=dict)
|
||
|
|
running: set[str] = field(default_factory=set)
|
||
|
|
request_cnt: dict[str, int] = field(default_factory=dict)
|
||
|
|
|
||
|
|
def is_new_request(self, from_user: str, message_id: str, content: str) -> bool:
|
||
|
|
has_cache = from_user in self.cache and bool(self.cache[from_user])
|
||
|
|
is_running = from_user in self.running
|
||
|
|
is_command = content.startswith("#")
|
||
|
|
is_new_msg = message_id not in self.request_cnt
|
||
|
|
return (not has_cache and not is_running) or (is_command and is_new_msg)
|
||
|
|
|
||
|
|
def mark_running(self, from_user: str):
|
||
|
|
self.running.add(from_user)
|
||
|
|
|
||
|
|
def mark_done(self, from_user: str):
|
||
|
|
self.running.discard(from_user)
|
||
|
|
|
||
|
|
def incr_request(self, message_id: str):
|
||
|
|
self.request_cnt[message_id] = self.request_cnt.get(message_id, 0) + 1
|
||
|
|
|
||
|
|
def is_done(self, from_user: str) -> bool:
|
||
|
|
return from_user not in self.running
|
||
|
|
|
||
|
|
def reap(self, from_user: str) -> tuple[str, str] | None:
|
||
|
|
entries = self.cache.get(from_user)
|
||
|
|
if not entries:
|
||
|
|
return None
|
||
|
|
result = entries.pop(0)
|
||
|
|
if not entries:
|
||
|
|
del self.cache[from_user]
|
||
|
|
return result
|
||
|
|
|
||
|
|
def add_cache(self, from_user: str, reply_type: str, content: str):
|
||
|
|
if from_user not in self.cache:
|
||
|
|
self.cache[from_user] = []
|
||
|
|
self.cache[from_user].append((reply_type, content))
|
||
|
|
|
||
|
|
def cleanup_user(self, from_user: str):
|
||
|
|
self.cache.pop(from_user, None)
|
||
|
|
self.running.discard(from_user)
|
||
|
|
|
||
|
|
def reset(self):
|
||
|
|
self.cache.clear()
|
||
|
|
self.running.clear()
|
||
|
|
self.request_cnt.clear()
|