""" Сервис для отправки сообщений """ from typing import Optional, Union from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup, ReplyKeyboardMarkup from aiogram import Bot from services.infrastructure.logger import get_logger from services.rate_limiting.rate_limit_service import RateLimitService from services.infrastructure.logging_decorators import log_function_call, log_business_event logger = get_logger(__name__) class MessageService: """Сервис для отправки сообщений""" def __init__(self, rate_limit_service: Optional[RateLimitService] = None): self.rate_limit_service = rate_limit_service @log_business_event("send_message", log_params=True, log_result=True) async def send_message( self, target: Union[Message, CallbackQuery, Bot], text: str, reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None, parse_mode: str = "HTML" ) -> bool: """ Отправка сообщения Args: target: Целевой объект (Message, CallbackQuery или Bot) text: Текст сообщения reply_markup: Клавиатура parse_mode: Режим парсинга Returns: True если успешно отправлено """ try: logger.info(f"📤 Отправка сообщения с клавиатурой: {type(reply_markup).__name__ if reply_markup else 'None'}") if isinstance(target, Message): await target.answer(text, reply_markup=reply_markup, parse_mode=parse_mode) elif isinstance(target, CallbackQuery): await target.message.answer(text, reply_markup=reply_markup, parse_mode=parse_mode) elif isinstance(target, Bot): # Для Bot нужен chat_id, который должен быть передан отдельно logger.error("Для Bot нужен chat_id") return False return True except Exception as e: logger.error(f"Ошибка при отправке сообщения: {e}") return False @log_business_event("edit_message", log_params=True, log_result=True) async def edit_message( self, target: Union[Message, CallbackQuery], text: str, reply_markup: Optional[InlineKeyboardMarkup] = None, parse_mode: str = "HTML" ) -> bool: """ Редактирование сообщения Args: target: Целевой объект (Message или CallbackQuery) text: Новый текст сообщения reply_markup: Новая клавиатура parse_mode: Режим парсинга Returns: True если успешно отредактировано """ try: if isinstance(target, Message): await target.edit_text(text, reply_markup=reply_markup, parse_mode=parse_mode) elif isinstance(target, CallbackQuery): await target.message.edit_text(text, reply_markup=reply_markup, parse_mode=parse_mode) return True except Exception as e: logger.error(f"Ошибка при редактировании сообщения: {e}") return False @log_function_call(log_params=True, log_result=True) async def send_callback_answer( self, callback: CallbackQuery, text: Optional[str] = None, show_alert: bool = False ) -> bool: """ Отправка ответа на callback query Args: callback: CallbackQuery объект text: Текст ответа show_alert: Показывать ли alert Returns: True если успешно отправлено """ try: await callback.answer(text, show_alert=show_alert) return True except Exception as e: logger.error(f"Ошибка при отправке callback answer: {e}") return False @log_business_event("send_bot_message", log_params=True, log_result=True) async def send_bot_message( self, bot: Bot, chat_id: int, text: str, reply_markup: Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup]] = None, parse_mode: str = "HTML" ) -> bool: """ Отправка сообщения через бота с rate limiting Args: bot: Экземпляр бота chat_id: ID чата text: Текст сообщения reply_markup: Клавиатура parse_mode: Режим парсинга Returns: True если успешно отправлено """ try: if self.rate_limit_service: # Используем rate limiting await self.rate_limit_service.send_with_rate_limit( bot.send_message, chat_id, text=text, reply_markup=reply_markup, parse_mode=parse_mode ) else: # Отправляем без rate limiting await bot.send_message( chat_id=chat_id, text=text, reply_markup=reply_markup, parse_mode=parse_mode ) return True except Exception as e: logger.error(f"Ошибка при отправке сообщения через бота в чат {chat_id}: {e}") return False @log_business_event("send_notification", log_params=True, log_result=True) async def send_notification( self, bot: Bot, user_id: int, title: str, message: str, reply_markup: Optional[InlineKeyboardMarkup] = None ) -> bool: """ Отправка уведомления пользователю с rate limiting Args: bot: Экземпляр бота user_id: ID пользователя title: Заголовок уведомления message: Текст уведомления reply_markup: Клавиатура Returns: True если успешно отправлено """ try: notification_text = f"🔔 {title}\n\n{message}" if self.rate_limit_service: # Используем rate limiting await self.rate_limit_service.send_with_rate_limit( bot.send_message, user_id, text=notification_text, reply_markup=reply_markup, parse_mode="HTML" ) else: # Отправляем без rate limiting await bot.send_message( chat_id=user_id, text=notification_text, reply_markup=reply_markup, parse_mode="HTML" ) logger.info(f"Уведомление отправлено пользователю {user_id}") return True except Exception as e: logger.error(f"Ошибка при отправке уведомления пользователю {user_id}: {e}") return False @log_business_event("send_error_message", log_params=True, log_result=True) async def send_error_message( self, target: Union[Message, CallbackQuery], error_text: str = "❌ Произошла ошибка. Попробуйте позже." ) -> bool: """ Отправка сообщения об ошибке Args: target: Целевой объект error_text: Текст ошибки Returns: True если успешно отправлено """ try: if isinstance(target, CallbackQuery): await target.answer(error_text, show_alert=True) else: await self.send_message(target, error_text) return True except Exception as e: logger.error(f"Ошибка при отправке сообщения об ошибке: {e}") return False