Merge branch 'dev' into freekassa-codex

This commit is contained in:
machka pasla
2025-10-14 09:38:39 +03:00
committed by GitHub
5 changed files with 78 additions and 14 deletions
+64 -9
View File
@@ -334,11 +334,18 @@ async def confirm_broadcast_callback_handler(
await session.rollback() await session.rollback()
logging.error(f"Error committing broadcast logs: {e_commit}") logging.error(f"Error committing broadcast logs: {e_commit}")
# Get queue stats for detailed report # Prepare queue stats presentation
queue_stats = queue_manager.get_queue_stats() queue_stats = queue_manager.get_queue_stats()
back_keyboard = get_back_to_admin_panel_keyboard(current_lang, i18n)
initial_user_failed = queue_stats.get("user_failed_messages", 0)
initial_group_failed = queue_stats.get("group_failed_messages", 0)
result_message = ( def build_queue_status(stats: dict) -> str:
_( dynamic_failed = max(
0, stats.get("user_failed_messages", 0) - initial_user_failed
) + max(0, stats.get("group_failed_messages", 0) - initial_group_failed)
total_failed = failed_count + dynamic_failed
return _(
"broadcast_queue_result", "broadcast_queue_result",
default=( default=(
"🚀 Рассылка поставлена в очередь!\n" "🚀 Рассылка поставлена в очередь!\n"
@@ -350,16 +357,64 @@ async def confirm_broadcast_callback_handler(
"ℹ️ Сообщения будут отправлены автоматически с соблюдением лимитов Telegram." "ℹ️ Сообщения будут отправлены автоматически с соблюдением лимитов Telegram."
), ),
sent_count=sent_count, sent_count=sent_count,
failed_count=failed_count, failed_count=total_failed,
user_queue_size=queue_stats["user_queue_size"], user_queue_size=stats["user_queue_size"],
group_queue_size=queue_stats["group_queue_size"], group_queue_size=stats["group_queue_size"],
) )
)
await callback.message.answer( result_message = build_queue_status(queue_stats)
status_message = await callback.message.answer(
result_message, result_message,
reply_markup=get_back_to_admin_panel_keyboard(current_lang, i18n), reply_markup=back_keyboard,
) )
async def auto_update_queue_status() -> None:
"""Refresh queue stats message twice per second via message edit."""
last_text = result_message
# Update for up to 2 minutes (240 iterations at 0.5s intervals)
max_iterations = 240
for _ in range(max_iterations):
await asyncio.sleep(0.5)
stats = queue_manager.get_queue_stats()
new_text = build_queue_status(stats)
queues_drained = (
stats["user_queue_size"] == 0
and stats["group_queue_size"] == 0
and not stats.get("user_queue_processing")
and not stats.get("group_queue_processing")
)
if new_text != last_text:
try:
await status_message.edit_text(
new_text,
reply_markup=back_keyboard,
)
last_text = new_text
except TelegramBadRequest as e:
if "message is not modified" in str(e):
last_text = new_text
else:
logging.debug(
"Broadcast queue auto-update stopped: %s", e
)
break
except Exception as e:
logging.debug(
"Broadcast queue auto-update unexpected error: %s", e
)
break
if queues_drained:
# Final refresh already attempted; exit loop.
break
else:
logging.debug("Broadcast queue auto-update reached time limit.")
asyncio.create_task(auto_update_queue_status())
elif action == "cancel": elif action == "cancel":
await callback.message.edit_text( await callback.message.edit_text(
_("admin_broadcast_cancelled"), _("admin_broadcast_cancelled"),
+1 -1
View File
@@ -390,7 +390,7 @@ class FreeKassaService:
await notification_service.notify_payment_received( await notification_service.notify_payment_received(
user_id=payment.user_id, user_id=payment.user_id,
amount=float(payment.amount), amount=float(payment.amount),
currency=self.default_currency or self.settings.DEFAULT_CURRENCY_SYMBOL, currency=self.default_currency,
months=months, months=months,
payment_provider="freekassa", payment_provider="freekassa",
username=db_user.username if db_user else None, username=db_user.username if db_user else None,
+9 -1
View File
@@ -26,6 +26,8 @@ class MessageQueue:
self.last_send_times: deque[datetime] = deque() self.last_send_times: deque[datetime] = deque()
self.is_processing = False self.is_processing = False
self.delay_between_messages = 1.0 / messages_per_second self.delay_between_messages = 1.0 / messages_per_second
self.total_sent = 0
self.total_failed = 0
async def add_message(self, message: QueuedMessage) -> None: async def add_message(self, message: QueuedMessage) -> None:
"""Add message to queue""" """Add message to queue"""
@@ -50,6 +52,7 @@ class MessageQueue:
try: try:
await self._send_message(message) await self._send_message(message)
self.last_send_times.append(datetime.now()) self.last_send_times.append(datetime.now())
self.total_sent += 1
# Keep only recent send times (last minute) # Keep only recent send times (last minute)
cutoff_time = datetime.now() - timedelta(seconds=60) cutoff_time = datetime.now() - timedelta(seconds=60)
@@ -57,6 +60,7 @@ class MessageQueue:
self.last_send_times.popleft() self.last_send_times.popleft()
except Exception as e: except Exception as e:
self.total_failed += 1
logging.error(f"Failed to send queued message to {message.chat_id}: {e}") logging.error(f"Failed to send queued message to {message.chat_id}: {e}")
finally: finally:
@@ -233,7 +237,11 @@ class MessageQueueManager:
"group_queue_processing": self.group_queue.is_processing, "group_queue_processing": self.group_queue.is_processing,
"user_queue_processing": self.user_queue.is_processing, "user_queue_processing": self.user_queue.is_processing,
"group_recent_sends": len(self.group_queue.last_send_times), "group_recent_sends": len(self.group_queue.last_send_times),
"user_recent_sends": len(self.user_queue.last_send_times) "user_recent_sends": len(self.user_queue.last_send_times),
"group_failed_messages": self.group_queue.total_failed,
"user_failed_messages": self.user_queue.total_failed,
"group_sent_messages": self.group_queue.total_sent,
"user_sent_messages": self.user_queue.total_sent,
} }
+1 -1
View File
@@ -4,7 +4,7 @@
"menu_activate_trial_button": "🆓 Free Trial", "menu_activate_trial_button": "🆓 Free Trial",
"menu_subscribe_inline": "🚀 Purchase", "menu_subscribe_inline": "🚀 Purchase",
"menu_my_subscription_inline": "🔐 My Subscription", "menu_my_subscription_inline": "🔐 My Subscription",
"no_subscription options available": "Subscription issuance is not configured by the bot administrator", "no_subscription_options_available": "Subscription issuance is not configured by the bot administrator",
"menu_referral_inline": "🎁 Referrals", "menu_referral_inline": "🎁 Referrals",
"referral_no_bonuses_configured": "Sorry, the referral program is currently disabled", "referral_no_bonuses_configured": "Sorry, the referral program is currently disabled",
"menu_apply_promo_button": "🎟 Promo Code", "menu_apply_promo_button": "🎟 Promo Code",
+1
View File
@@ -127,6 +127,7 @@
"admin_broadcast_cancelled": "Рассылка отменена.", "admin_broadcast_cancelled": "Рассылка отменена.",
"admin_broadcast_cancelled_alert": "Рассылка отменена!", "admin_broadcast_cancelled_alert": "Рассылка отменена!",
"admin_broadcast_cancelled_nav_back": "Рассылка отменена. Вы возвращены в админ-панель.", "admin_broadcast_cancelled_nav_back": "Рассылка отменена. Вы возвращены в админ-панель.",
"broadcast_queue_result": "🚀 Рассылка поставлена в очередь!\n📤 В очередь добавлено: {sent_count}\n❌ Ошибок: {failed_count}\n\n📊 Статус очередей:\n👥 Очередь пользователей: {user_queue_size} сообщений\n📢 Очередь групп: {group_queue_size} сообщений\n\nℹ️ Сообщения будут отправлены автоматически с соблюдением лимитов Telegram.",
"admin_promo_invalid_code_format": "Код должен быть от 3 до 30 символов и содержать только буквы и цифры.", "admin_promo_invalid_code_format": "Код должен быть от 3 до 30 символов и содержать только буквы и цифры.",
"admin_promo_invalid_bonus_days": "Количество бонусных дней должно быть положительным числом.", "admin_promo_invalid_bonus_days": "Количество бонусных дней должно быть положительным числом.",
"admin_promo_invalid_max_activations": "Максимальное количество активаций должно быть положительным числом.", "admin_promo_invalid_max_activations": "Максимальное количество активаций должно быть положительным числом.",