70 lines
2.3 KiB
Python
70 lines
2.3 KiB
Python
from collections.abc import Awaitable, Callable
|
|
from time import monotonic
|
|
from typing import Any
|
|
|
|
from aiogram import BaseMiddleware
|
|
from aiogram.types import TelegramObject, User
|
|
|
|
from database import upsert_user
|
|
from logger import logger
|
|
|
|
|
|
class UserMiddleware(BaseMiddleware):
|
|
def __init__(self, debounce_sec: float = 60.0) -> None:
|
|
self._debounce = float(debounce_sec)
|
|
self._cache: dict[int, tuple[str, float, dict | None]] = {}
|
|
|
|
async def __call__(
|
|
self,
|
|
handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]],
|
|
event: TelegramObject,
|
|
data: dict[str, Any],
|
|
) -> Any:
|
|
try:
|
|
user: User | None = data.get("event_from_user")
|
|
if user and not user.is_bot:
|
|
session = data.get("session")
|
|
db_user = await self._process_user(user, session)
|
|
if db_user:
|
|
data["user"] = db_user
|
|
except Exception as e:
|
|
logger.error(f"Ошибка при обработке пользователя: {e}")
|
|
return await handler(event, data)
|
|
|
|
async def _process_user(self, user: User, session: Any = None) -> dict | None:
|
|
uid = user.id
|
|
fp = self._fingerprint(user)
|
|
now = monotonic()
|
|
|
|
cached = self._cache.get(uid)
|
|
if cached:
|
|
cached_fp, ts, cached_db_user = cached
|
|
if fp == cached_fp and now - ts < self._debounce:
|
|
return cached_db_user
|
|
|
|
logger.debug(f"Обработка пользователя: {uid}")
|
|
db_user = await upsert_user(
|
|
tg_id=uid,
|
|
username=user.username,
|
|
first_name=user.first_name,
|
|
last_name=user.last_name,
|
|
language_code=user.language_code,
|
|
is_bot=user.is_bot,
|
|
session=session,
|
|
only_if_exists=True,
|
|
)
|
|
self._cache[uid] = (fp, now, db_user)
|
|
if db_user:
|
|
logger.debug(f"Получены данные пользователя из БД: {uid}")
|
|
return db_user
|
|
|
|
def _fingerprint(self, user: User) -> str:
|
|
return "|".join([
|
|
str(user.id),
|
|
user.username or "",
|
|
user.first_name or "",
|
|
user.last_name or "",
|
|
user.language_code or "",
|
|
"1" if user.is_bot else "0",
|
|
])
|