48 lines
1.4 KiB
Python
48 lines
1.4 KiB
Python
from __future__ import annotations
|
||
import time
|
||
from dataclasses import dataclass, field
|
||
from typing import Any, Dict, Optional
|
||
|
||
|
||
DEFAULT_TTL = 60 * 60 # 1 час
|
||
|
||
|
||
@dataclass
|
||
class UserSession:
|
||
channel_id: Optional[int] = None
|
||
type: Optional[str] = None # text/photo/video/animation
|
||
parse_mode: Optional[str] = None # HTML/MarkdownV2
|
||
text: Optional[str] = None
|
||
media_file_id: Optional[str] = None
|
||
keyboard: Optional[dict] = None # {"rows": [[{"text","url"}], ...]}
|
||
last_activity: float = field(default_factory=time.time)
|
||
|
||
def touch(self) -> None:
|
||
self.last_activity = time.time()
|
||
|
||
|
||
class SessionStore:
|
||
"""Простое и быстрое in-memory хранилище с авто-очисткой."""
|
||
|
||
def __init__(self, ttl: int = DEFAULT_TTL) -> None:
|
||
self._data: Dict[int, UserSession] = {}
|
||
self._ttl = ttl
|
||
|
||
def get(self, uid: int) -> UserSession:
|
||
s = self._data.get(uid)
|
||
if not s:
|
||
s = UserSession()
|
||
self._data[uid] = s
|
||
s.touch()
|
||
self._cleanup()
|
||
return s
|
||
|
||
def drop(self, uid: int) -> None:
|
||
self._data.pop(uid, None)
|
||
|
||
def _cleanup(self) -> None:
|
||
now = time.time()
|
||
for uid in list(self._data.keys()):
|
||
if now - self._data[uid].last_activity > self._ttl:
|
||
del self._data[uid]
|