Изменение логики медленного режима

This commit is contained in:
2025-10-19 17:37:52 +03:00
parent b7f09ae719
commit c4400fc244
3 changed files with 177 additions and 4 deletions

View File

@@ -1,5 +1,5 @@
## changed at Sun Oct 19 13:23:17 MSK 2025 ## changed at Sun Oct 19 17:30:33 MSK 2025
#Sun Oct 19 13:23:17 MSK 2025 #Sun Oct 19 17:30:33 MSK 2025
com.gigaide.elements.ext.marker.solution.BeanMarkedPsi.shouldMark=true com.gigaide.elements.ext.marker.solution.BeanMarkedPsi.shouldMark=true
com.gigaide.elements.ext.marker.solution.ConfigMarkedPsi.shouldMark=true com.gigaide.elements.ext.marker.solution.ConfigMarkedPsi.shouldMark=true
com.gigaide.elements.ext.marker.solution.DataMarkedPsi.shouldMark=true com.gigaide.elements.ext.marker.solution.DataMarkedPsi.shouldMark=true

View File

@@ -16,6 +16,8 @@ from action_reporter import init_action_reporter
from config import MODULES_DIR from config import MODULES_DIR
from message_queue import init_message_queue, add_to_queue
# Загружаем токен бота из .env # Загружаем токен бота из .env
load_dotenv() load_dotenv()
@@ -143,7 +145,24 @@ class UserUpdateMiddleware(BaseMiddleware):
can_send, remaining_time = check_slow_mode(message.from_user.id, message.chat.id, user_karma) can_send, remaining_time = check_slow_mode(message.from_user.id, message.chat.id, user_karma)
if not can_send: if not can_send:
# Удаляем сообщение # Сохраняем текст сообщения перед удалением
message_text = message.text
# Добавляем сообщение в очередь для отправки после задержки
try:
add_to_queue(
chat_id=message.chat.id,
user_id=message.from_user.id,
user_name=message.from_user.first_name,
text=message_text,
delay_seconds=remaining_time,
thread_id=message.message_thread_id
)
logger.info(f"[SLOW MODE] Сообщение от {message.from_user.id} добавлено в очередь на {remaining_time}с")
except Exception as e:
logger.error(f"Ошибка добавления сообщения в очередь: {e}")
# Удаляем оригинальное сообщение
try: try:
await self.bot.delete_message(message.chat.id, message.message_id) await self.bot.delete_message(message.chat.id, message.message_id)
logger.info(f"[SLOW MODE] Удалено сообщение от {message.from_user.id} (карма: {user_karma}, осталось ждать: {remaining_time}с)") logger.info(f"[SLOW MODE] Удалено сообщение от {message.from_user.id} (карма: {user_karma}, осталось ждать: {remaining_time}с)")
@@ -154,7 +173,7 @@ class UserUpdateMiddleware(BaseMiddleware):
try: try:
notification = await self.bot.send_message( notification = await self.bot.send_message(
chat_id=message.chat.id, chat_id=message.chat.id,
text=f"⏱ <b>{message.from_user.first_name}</b>, подождите ещё <b>{format_time(remaining_time)}</b> перед отправкой следующего сообщения.\n\n" text=f"⏱ <b>{message.from_user.first_name}</b>, ваше сообщение будет отправлено через <b>{format_time(remaining_time)}</b>.\n\n"
f"💡 Ваша карма: <b>{user_karma}</b>. Повышайте карму, чтобы уменьшить задержку!", f"💡 Ваша карма: <b>{user_karma}</b>. Повышайте карму, чтобы уменьшить задержку!",
message_thread_id=message.message_thread_id, message_thread_id=message.message_thread_id,
) )
@@ -283,6 +302,10 @@ async def main():
# Устанавливаем команды бота # Устанавливаем команды бота
await setup_bot_commands() await setup_bot_commands()
# Инициализируем систему очереди сообщений
init_message_queue(bot)
logger.info("Система очереди сообщений инициализирована")
# Запускаем бота с обработкой реакций # Запускаем бота с обработкой реакций
logger.info("Запуск бота с allowed_updates: message, message_reaction, chat_member") logger.info("Запуск бота с allowed_updates: message, message_reaction, chat_member")
await bot.infinity_polling(allowed_updates=['message', 'message_reaction', 'chat_member']) await bot.infinity_polling(allowed_updates=['message', 'message_reaction', 'chat_member'])

150
src/message_queue.py Normal file
View File

@@ -0,0 +1,150 @@
# Очередь отложенных сообщений для медленного режима
# Сохраняет сообщения и отправляет их после истечения задержки
import asyncio
import time
import logging
from typing import Dict, List, Optional
from dataclasses import dataclass
from collections import deque
logger = logging.getLogger(__name__)
@dataclass
class QueuedMessage:
"""Сообщение в очереди"""
chat_id: int
user_id: int
user_name: str
text: str
send_time: float # Unix timestamp когда нужно отправить
thread_id: Optional[int] = None
# Очередь сообщений для каждого чата
_message_queues: Dict[int, deque[QueuedMessage]] = {}
_processing_task: Optional[asyncio.Task] = None
_bot_instance = None
def init_message_queue(bot):
"""
Инициализирует систему очереди сообщений.
Args:
bot: Экземпляр бота для отправки сообщений
"""
global _bot_instance, _processing_task
_bot_instance = bot
# Запускаем фоновую задачу обработки очереди, если она ещё не запущена
if _processing_task is None or _processing_task.done():
_processing_task = asyncio.create_task(_process_queue())
logger.info("Система очереди сообщений инициализирована")
def add_to_queue(chat_id: int, user_id: int, user_name: str, text: str, delay_seconds: int, thread_id: Optional[int] = None):
"""
Добавляет сообщение в очередь для отправки после задержки.
Args:
chat_id: ID чата
user_id: ID пользователя
user_name: Имя пользователя
text: Текст сообщения
delay_seconds: Задержка в секундах перед отправкой
thread_id: ID топика (для супергрупп с топиками)
"""
send_time = time.time() + delay_seconds
message = QueuedMessage(
chat_id=chat_id,
user_id=user_id,
user_name=user_name,
text=text,
send_time=send_time,
thread_id=thread_id
)
# Добавляем очередь для чата, если её ещё нет
if chat_id not in _message_queues:
_message_queues[chat_id] = deque()
_message_queues[chat_id].append(message)
logger.info(f"[QUEUE] Сообщение от {user_name} ({user_id}) добавлено в очередь чата {chat_id}, отправка через {delay_seconds}с")
async def _process_queue():
"""
Фоновая задача для обработки очереди сообщений.
Проверяет каждую секунду, есть ли сообщения готовые к отправке.
"""
global _bot_instance
logger.info("[QUEUE] Запущена фоновая задача обработки очереди")
while True:
try:
current_time = time.time()
# Проходим по всем чатам
for chat_id in list(_message_queues.keys()):
queue = _message_queues[chat_id]
# Обрабатываем сообщения, которые готовы к отправке
while queue and queue[0].send_time <= current_time:
message = queue.popleft()
try:
# Отправляем сообщение
formatted_text = f"💬 <b>{message.user_name}</b>:\n{message.text}"
await _bot_instance.send_message(
chat_id=message.chat_id,
text=formatted_text,
message_thread_id=message.thread_id
)
logger.info(f"[QUEUE] Сообщение от {message.user_name} ({message.user_id}) отправлено в чат {message.chat_id}")
except Exception as e:
logger.error(f"[QUEUE] Ошибка отправки сообщения из очереди: {e}", exc_info=True)
# Удаляем пустые очереди
if not queue:
del _message_queues[chat_id]
# Ждём 1 секунду перед следующей проверкой
await asyncio.sleep(1)
except Exception as e:
logger.error(f"[QUEUE] Ошибка в обработке очереди: {e}", exc_info=True)
await asyncio.sleep(1)
def get_queue_size(chat_id: int) -> int:
"""
Возвращает количество сообщений в очереди для чата.
Args:
chat_id: ID чата
Returns:
Количество сообщений в очереди
"""
return len(_message_queues.get(chat_id, []))
def get_user_queue_position(chat_id: int, user_id: int) -> Optional[int]:
"""
Возвращает позицию пользователя в очереди (1-based).
Args:
chat_id: ID чата
user_id: ID пользователя
Returns:
Позиция в очереди или None если нет сообщений
"""
if chat_id not in _message_queues:
return None
queue = _message_queues[chat_id]
for i, msg in enumerate(queue):
if msg.user_id == user_id:
return i + 1
return None