mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-19 19:32:10 +00:00
149 lines
6.0 KiB
Python
149 lines
6.0 KiB
Python
import logging
|
|
from typing import Callable, Dict, Any, Awaitable
|
|
from aiogram import BaseMiddleware
|
|
from aiogram.types import TelegramObject, CallbackQuery, Message
|
|
from aiogram.exceptions import TelegramBadRequest
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class GlobalErrorMiddleware(BaseMiddleware):
|
|
|
|
async def __call__(
|
|
self,
|
|
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
|
|
event: TelegramObject,
|
|
data: Dict[str, Any]
|
|
) -> Any:
|
|
try:
|
|
return await handler(event, data)
|
|
except TelegramBadRequest as e:
|
|
return await self._handle_telegram_error(event, e)
|
|
except Exception as e:
|
|
logger.error(f"Неожиданная ошибка в GlobalErrorMiddleware: {e}", exc_info=True)
|
|
raise
|
|
|
|
async def _handle_telegram_error(self, event: TelegramObject, error: TelegramBadRequest):
|
|
error_message = str(error).lower()
|
|
|
|
if self._is_old_query_error(error_message):
|
|
return await self._handle_old_query(event, error)
|
|
elif self._is_message_not_modified_error(error_message):
|
|
return await self._handle_message_not_modified(event, error)
|
|
elif self._is_bad_request_error(error_message):
|
|
return await self._handle_bad_request(event, error)
|
|
else:
|
|
logger.error(f"Неизвестная Telegram API ошибка: {error}")
|
|
raise error
|
|
|
|
def _is_old_query_error(self, error_message: str) -> bool:
|
|
return any(phrase in error_message for phrase in [
|
|
"query is too old",
|
|
"query id is invalid",
|
|
"response timeout expired"
|
|
])
|
|
|
|
def _is_message_not_modified_error(self, error_message: str) -> bool:
|
|
return "message is not modified" in error_message
|
|
|
|
def _is_bad_request_error(self, error_message: str) -> bool:
|
|
return any(phrase in error_message for phrase in [
|
|
"message not found",
|
|
"chat not found",
|
|
"bot was blocked by the user",
|
|
"user is deactivated"
|
|
])
|
|
|
|
async def _handle_old_query(self, event: TelegramObject, error: TelegramBadRequest):
|
|
if isinstance(event, CallbackQuery):
|
|
user_info = self._get_user_info(event)
|
|
logger.warning(f"🕐 [GlobalErrorMiddleware] Игнорируем устаревший callback '{event.data}' от {user_info}")
|
|
else:
|
|
logger.warning(f"🕐 [GlobalErrorMiddleware] Игнорируем устаревший запрос: {error}")
|
|
|
|
return None
|
|
|
|
async def _handle_message_not_modified(self, event: TelegramObject, error: TelegramBadRequest):
|
|
logger.debug(f"📝 [GlobalErrorMiddleware] Сообщение не было изменено: {error}")
|
|
|
|
if isinstance(event, CallbackQuery):
|
|
try:
|
|
await event.answer()
|
|
logger.debug("✅ Успешно ответили на callback после 'message not modified'")
|
|
except TelegramBadRequest as answer_error:
|
|
if not self._is_old_query_error(str(answer_error).lower()):
|
|
logger.error(f"❌ Ошибка при ответе на callback: {answer_error}")
|
|
|
|
return None
|
|
|
|
async def _handle_bad_request(self, event: TelegramObject, error: TelegramBadRequest):
|
|
error_message = str(error).lower()
|
|
|
|
if "bot was blocked" in error_message:
|
|
user_info = self._get_user_info(event) if hasattr(event, 'from_user') else "Unknown"
|
|
logger.info(f"🚫 [GlobalErrorMiddleware] Бот заблокирован пользователем {user_info}")
|
|
return None
|
|
elif "user is deactivated" in error_message:
|
|
user_info = self._get_user_info(event) if hasattr(event, 'from_user') else "Unknown"
|
|
logger.info(f"👻 [GlobalErrorMiddleware] Пользователь деактивирован {user_info}")
|
|
return None
|
|
elif "chat not found" in error_message or "message not found" in error_message:
|
|
logger.warning(f"🔍 [GlobalErrorMiddleware] Чат или сообщение не найдено: {error}")
|
|
return None
|
|
else:
|
|
logger.error(f"❌ [GlobalErrorMiddleware] Неизвестная bad request ошибка: {error}")
|
|
raise error
|
|
|
|
def _get_user_info(self, event: TelegramObject) -> str:
|
|
if hasattr(event, 'from_user') and event.from_user:
|
|
if event.from_user.username:
|
|
return f"@{event.from_user.username}"
|
|
else:
|
|
return f"ID:{event.from_user.id}"
|
|
return "Unknown"
|
|
|
|
|
|
class ErrorStatisticsMiddleware(BaseMiddleware):
|
|
|
|
def __init__(self):
|
|
self.error_counts = {
|
|
'old_queries': 0,
|
|
'message_not_modified': 0,
|
|
'bot_blocked': 0,
|
|
'user_deactivated': 0,
|
|
'other_errors': 0
|
|
}
|
|
|
|
async def __call__(
|
|
self,
|
|
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
|
|
event: TelegramObject,
|
|
data: Dict[str, Any]
|
|
) -> Any:
|
|
try:
|
|
return await handler(event, data)
|
|
except TelegramBadRequest as e:
|
|
self._count_error(e)
|
|
raise
|
|
|
|
def _count_error(self, error: TelegramBadRequest):
|
|
error_message = str(error).lower()
|
|
|
|
if "query is too old" in error_message:
|
|
self.error_counts['old_queries'] += 1
|
|
elif "message is not modified" in error_message:
|
|
self.error_counts['message_not_modified'] += 1
|
|
elif "bot was blocked" in error_message:
|
|
self.error_counts['bot_blocked'] += 1
|
|
elif "user is deactivated" in error_message:
|
|
self.error_counts['user_deactivated'] += 1
|
|
else:
|
|
self.error_counts['other_errors'] += 1
|
|
|
|
def get_statistics(self) -> dict:
|
|
return self.error_counts.copy()
|
|
|
|
def reset_statistics(self):
|
|
for key in self.error_counts:
|
|
self.error_counts[key] = 0
|