"""Middleware аналитики: события ``message`` и ``command`` приходят с транспорта.""" from __future__ import annotations import logging from collections.abc import Awaitable, Callable from typing import Any from aiogram import BaseMiddleware from aiogram.types import Message, TelegramObject from common.analytics import EventType, record, remember_user from common.analytics.messages import describe_command, describe_message from common.config import get_settings logger = logging.getLogger(__name__) class AnalyticsMiddleware(BaseMiddleware): """Логирует сообщения и команды основного чата. Текст сообщения не сохраняется — только метаданные (см. ``docs/events.md``). Аналитика не должна мешать обработке: любые сбои логируются и глушатся. """ async def __call__( self, handler: Callable[[TelegramObject, dict[str, Any]], Awaitable[Any]], event: TelegramObject, data: dict[str, Any], ) -> Any: if isinstance(event, Message): self._log_message(event) return await handler(event, data) @staticmethod def _log_message(message: Message) -> None: user = message.from_user if user is None or user.is_bot: return if message.chat.id != get_settings().chat_id: return try: remember_user(user.id, user.username) record( EventType.MESSAGE, user_id=user.id, username=user.username, chat_id=message.chat.id, payload=describe_message(message), ) command = describe_command(message) if command is not None: record( EventType.COMMAND, user_id=user.id, username=user.username, chat_id=message.chat.id, payload=command, ) except Exception: # аналитика не должна ломать обработку сообщения logger.exception("Не удалось записать события сообщения в аналитику") __all__ = ["AnalyticsMiddleware"]