91 lines
4.3 KiB
Python
91 lines
4.3 KiB
Python
# -*- 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) |