Редактировать room_handler.py

This commit is contained in:
Markov Andrey
2026-06-30 21:46:44 +00:00
parent 52b34a3790
commit 928ce0360e

View File

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