# -*- coding: utf-8 -*- """ Обработчик MUC комнат (Multi-User Chat). - Автоматический вход по приглашению (даже если бот перезагружен – комната сохраняется в БД). - Периодическая проверка присутствия в комнатах и переподключение при необходимости. - Сохранение JID комнат в PostgreSQL для восстановления после рестарта. ВНИМАНИЕ: Все JID комнат должны храниться и сравниваться как строки (bare JID), чтобы избежать ошибок типов при работе с asyncpg и slixmpp. """ import logging import asyncio logger = logging.getLogger(__name__) class RoomHandler: """Управление комнатами: приглашения, реджоин, сохранение в БД.""" def __init__(self, bot): self.bot = bot async def accept_invite(self, inv): """ Обработчик события groupchat_invite. Автоматически входит в комнату, добавляет её в список rooms и сохраняет в БД. Аргументы: inv: объект приглашения (содержит атрибуты 'room' или 'from') """ room = inv.get('room', inv.get('from')) if not room: logger.warning("Приглашение не содержит идентификатора комнаты") return # Преобразуем в строку bare JID (без ресурса) if hasattr(room, 'bare'): room_str = room.bare else: room_str = str(room) logger.info(f"Приглашение в комнату {room_str}, входим.") # Если комната ещё не в списке бота – добавляем if room_str not in self.bot.rooms: self.bot.rooms.append(room_str) # Входим в MUC-комнату await self.bot.plugin['xep_0045'].join_muc(room_str, self.bot.boundjid.user) async def rejoin_loop(self): """ Бесконечный цикл переподключения к комнатам. Проверяет, в каких комнатах бот состоит, и если его нет – переподключается. """ while True: await asyncio.sleep(60) # Получаем список комнат, где бот присутствует joined_rooms = set() try: if hasattr(self.bot.plugin['xep_0045'], 'get_joined_rooms'): joined_rooms = set(self.bot.plugin['xep_0045'].get_joined_rooms()) else: joined_rooms = {str(r) for r in self.bot.plugin['xep_0045'].rooms.keys()} except Exception as e: logger.debug(f"Ошибка получения списка комнат: {e}") continue for room in self.bot.rooms: if room not in joined_rooms: logger.info(f"Попытка повторного входа в комнату {room}...") try: await self.bot.plugin['xep_0045'].join_muc(room, self.bot.boundjid.user) await asyncio.sleep(1) except Exception as e: logger.error(f"Ошибка входа в {room}: {e}") async def on_kicked(self, presence): """Обработчик события, когда бота исключают из комнаты.""" room = presence['from'].bare logger.info(f"Бот был исключён из комнаты {room}") if room in self.bot.rooms: self.bot.rooms.remove(room) async def on_banned(self, presence): """Обработчик события, когда бота банят в комнате.""" room = presence['from'].bare logger.info(f"Бот был забанен в комнате {room}") if room in self.bot.rooms: self.bot.rooms.remove(room)