Files
Solo_bot/middlewares/user.py
T

72 lines
2.5 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 sqlalchemy.ext.asyncio import AsyncSession
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")
if isinstance(session, AsyncSession):
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: AsyncSession) -> dict | None:
uid = user.id
fingerprint = self._fingerprint(user)
now = monotonic()
cached = self._cache.get(uid)
if cached:
cached_fingerprint, ts, cached_db_user = cached
if fingerprint == cached_fingerprint 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] = (fingerprint, 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",
])