65 lines
2.4 KiB
Python
65 lines
2.4 KiB
Python
|
import asyncio
|
|||
|
import logging
|
|||
|
|
|||
|
from aiogram_dialog import DialogManager
|
|||
|
from aiogram.exceptions import TelegramRetryAfter, TelegramForbiddenError, TelegramAPIError
|
|||
|
from sqlalchemy import select
|
|||
|
from sqlalchemy.exc import SQLAlchemyError
|
|||
|
|
|||
|
from bot.database.db import async_session
|
|||
|
from bot.database.models import UserModel
|
|||
|
|
|||
|
|
|||
|
async def _send_message_with_retry(bot, user_id: int, message_text: str, max_retries=3, delay=1) -> bool:
|
|||
|
for attempt in range(max_retries):
|
|||
|
try:
|
|||
|
await bot.send_message(user_id, message_text)
|
|||
|
return True
|
|||
|
except TelegramRetryAfter as e:
|
|||
|
logging.warning(f"Retry after {e.retry_after} for user {user_id}, attempt {attempt + 1}")
|
|||
|
await asyncio.sleep(e.retry_after)
|
|||
|
except TelegramForbiddenError:
|
|||
|
logging.warning(f"User {user_id} blocked bot")
|
|||
|
return False
|
|||
|
except TelegramAPIError as e:
|
|||
|
logging.error(f"Error sending message to user {user_id}: {e}")
|
|||
|
return False
|
|||
|
logging.error(f"Max retries exceeded for user {user_id}")
|
|||
|
return False
|
|||
|
|
|||
|
|
|||
|
async def broadcast_message(dialog_manager: DialogManager, **kwargs):
|
|||
|
message_text = dialog_manager.find("message_input").get_value()
|
|||
|
|
|||
|
bot = dialog_manager.event.bot
|
|||
|
try:
|
|||
|
async with async_session() as session:
|
|||
|
async with session.begin():
|
|||
|
result = await session.execute(select(UserModel.tg_id))
|
|||
|
user_ids = [row[0] for row in result]
|
|||
|
total_users = len(user_ids)
|
|||
|
tasks = [
|
|||
|
_send_message_with_retry(bot, user_id, message_text)
|
|||
|
for user_id in user_ids
|
|||
|
]
|
|||
|
results = await asyncio.gather(*tasks)
|
|||
|
|
|||
|
total_sent = sum(results)
|
|||
|
total_failed = total_users - total_sent
|
|||
|
|
|||
|
except SQLAlchemyError as e:
|
|||
|
logging.error(f"Database error: {e}")
|
|||
|
return {
|
|||
|
"progress": f"❌ Ошибка при работе с базой данных: {e}"
|
|||
|
}
|
|||
|
except Exception as e:
|
|||
|
logging.error(f"An unexpected error occurred: {e}")
|
|||
|
return {
|
|||
|
"progress": f"❌ Непредвиденная ошибка: {e}"
|
|||
|
}
|
|||
|
|
|||
|
return {
|
|||
|
"progress": f"✅ Рассылка завершена!\n"
|
|||
|
f"📨 Всего отправлено: {total_sent}/{total_users}\n"
|
|||
|
f"❌ Ошибок: {total_failed}"
|
|||
|
}
|