Files
AnonBot/services/business/message_service.py

238 lines
8.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Сервис для отправки сообщений
"""
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"🔔 <b>{title}</b>\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