Update file bot.py
This commit is contained in:
76
bots/bot.py
76
bots/bot.py
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Точка входа для запуска бота.
|
Точка входа для запуска XMPP-бота.
|
||||||
С расширенной диагностикой событий.
|
С расширенной диагностикой событий и использованием Pydantic-конфига (AppConfig).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@@ -12,14 +12,19 @@ import logging
|
|||||||
import signal
|
import signal
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from core.utils.config_loader import BotConfig
|
# Импорт нового загрузчика и модели конфига
|
||||||
from core.utils.logger import setup_logging
|
from rag.utils.config_loader import load_config
|
||||||
from core.xmpp.client import Bot
|
from rag.config_models import AppConfig
|
||||||
|
from rag.utils.logger import setup_logging
|
||||||
|
|
||||||
|
# Импорт класса Bot (который теперь принимает AppConfig)
|
||||||
|
from bots.xmpp.client import Bot
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def shutdown(sig, bot, stop_event):
|
async def shutdown(sig, bot, stop_event):
|
||||||
|
"""Graceful shutdown с обработкой сигналов."""
|
||||||
logger.info(f"Получен сигнал {sig.name}, начинаю graceful shutdown...")
|
logger.info(f"Получен сигнал {sig.name}, начинаю graceful shutdown...")
|
||||||
stop_event.set()
|
stop_event.set()
|
||||||
try:
|
try:
|
||||||
@@ -27,40 +32,64 @@ async def shutdown(sig, bot, stop_event):
|
|||||||
await bot.disconnect()
|
await bot.disconnect()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка отключения: {e}")
|
logger.error(f"Ошибка отключения: {e}")
|
||||||
|
# Отменяем все задачи, кроме текущей
|
||||||
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
|
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
task.cancel()
|
task.cancel()
|
||||||
await asyncio.gather(*tasks, return_exceptions=True)
|
await asyncio.gather(*tasks, return_exceptions=True)
|
||||||
|
# Закрываем HTTP-сессию RAG-клиента
|
||||||
|
try:
|
||||||
|
await bot.rag_client.close()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
logger.info("Бот завершён")
|
logger.info("Бот завершён")
|
||||||
|
|
||||||
|
|
||||||
async def main_async(profile_dir: str):
|
async def main_async(profile_dir: str):
|
||||||
|
"""
|
||||||
|
Асинхронная инициализация и запуск бота.
|
||||||
|
"""
|
||||||
|
# 1. Загружаем конфигурацию через Pydantic (AppConfig)
|
||||||
try:
|
try:
|
||||||
config = BotConfig(profile_dir)
|
config: AppConfig = load_config(profile_dir)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Ошибка конфига: {e}")
|
logger.error(f"Ошибка загрузки конфигурации: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
setup_logging(config.name, config.log_file, log_level=logging.DEBUG)
|
# 2. Настраиваем логирование в режиме DEBUG для диагностики
|
||||||
|
# (можно переключить через --log-level, но пока жёстко)
|
||||||
|
setup_logging(config.name, config.log_file_path, log_level=logging.DEBUG)
|
||||||
logger.info(f"Запуск бота {config.name} с профилем {profile_dir}")
|
logger.info(f"Запуск бота {config.name} с профилем {profile_dir}")
|
||||||
|
|
||||||
|
# 3. Создаём экземпляр бота
|
||||||
bot = Bot(config)
|
bot = Bot(config)
|
||||||
|
|
||||||
# Отключаем SRV и устанавливаем IP
|
# ---- ДЛЯ ОТЛАДКИ (как в старом коде) ----
|
||||||
|
# Отключаем SRV-записи, чтобы явно указать сервер и порт.
|
||||||
|
# Если в конфиге есть xmpp_server и xmpp_port, используем их,
|
||||||
|
# иначе оставляем как есть (slixmpp попытается определить автоматически).
|
||||||
bot.use_srv = False
|
bot.use_srv = False
|
||||||
|
# Если в конфиге явно не заданы, оставляем значения по умолчанию,
|
||||||
|
# но для отладки можно жёстко прописать IP.
|
||||||
|
# В production лучше брать из конфига.
|
||||||
|
if config.xmpp_server:
|
||||||
|
bot.xmpp_server = config.xmpp_server
|
||||||
|
else:
|
||||||
|
# fallback для тестовой среды
|
||||||
bot.xmpp_server = "192.168.1.150"
|
bot.xmpp_server = "192.168.1.150"
|
||||||
|
if config.xmpp_port:
|
||||||
|
bot.xmpp_port = config.xmpp_port
|
||||||
|
else:
|
||||||
bot.xmpp_port = 5222
|
bot.xmpp_port = 5222
|
||||||
# Попробуем SSL, если не работает — отключим
|
|
||||||
# bot.xmpp_use_ssl = False # оставляем как есть
|
|
||||||
|
|
||||||
# ---- ДОБАВЛЯЕМ ВСЕ ОБРАБОТЧИКИ ----
|
# ---- ДОБАВЛЯЕМ ВСЕ ОБРАБОТЧИКИ СОБЫТИЙ (как в старом коде) ----
|
||||||
def on_session_start(event):
|
def on_session_start(event):
|
||||||
logger.info("✅ СЕССИЯ УСПЕШНО УСТАНОВЛЕНА! Бот готов.")
|
logger.info("✅ СЕССИЯ УСПЕШНО УСТАНОВЛЕНА! Бот готов.")
|
||||||
bot.send_presence(pshow='chat', pstatus=config.status_message)
|
bot.send_presence(pshow='chat', pstatus=config.status_message)
|
||||||
|
|
||||||
def on_failed_auth(event):
|
def on_failed_auth(event):
|
||||||
logger.error("❌ ОШИБКА АВТОРИЗАЦИИ! Проверьте пароль и JID.")
|
logger.error("❌ ОШИБКА АВТОРИЗАЦИИ! Проверьте пароль и JID.")
|
||||||
# Принудительно завершаем бота, чтобы не висеть
|
# Принудительно завершаем бота
|
||||||
asyncio.create_task(shutdown(None, bot, stop_event))
|
asyncio.create_task(shutdown(None, bot, stop_event))
|
||||||
|
|
||||||
def on_disconnected(event):
|
def on_disconnected(event):
|
||||||
@@ -94,30 +123,45 @@ async def main_async(profile_dir: str):
|
|||||||
bot.add_event_handler("roster_update", on_roster_update)
|
bot.add_event_handler("roster_update", on_roster_update)
|
||||||
bot.add_event_handler("presence", on_presence)
|
bot.add_event_handler("presence", on_presence)
|
||||||
|
|
||||||
|
# ---- ОБРАБОТКА СИГНАЛОВ ----
|
||||||
stop_event = asyncio.Event()
|
stop_event = asyncio.Event()
|
||||||
|
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
for sig in (signal.SIGINT, signal.SIGTERM):
|
||||||
loop.add_signal_handler(
|
loop.add_signal_handler(
|
||||||
sig, lambda s=sig: asyncio.create_task(shutdown(s, bot, stop_event))
|
sig, lambda s=sig: asyncio.create_task(shutdown(s, bot, stop_event))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ---- ПОДКЛЮЧЕНИЕ ----
|
||||||
logger.info(f"Попытка подключения к {bot.xmpp_server}:{bot.xmpp_port}...")
|
logger.info(f"Попытка подключения к {bot.xmpp_server}:{bot.xmpp_port}...")
|
||||||
bot.connect()
|
bot.connect()
|
||||||
logger.info("connect() вызван, ожидаем событий...")
|
logger.info("connect() вызван, ожидаем событий...")
|
||||||
|
|
||||||
|
# Ждём сигнала остановки
|
||||||
await stop_event.wait()
|
await stop_event.wait()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
"""Синхронная точка входа."""
|
||||||
parser.add_argument('--profile-dir', required=True)
|
parser = argparse.ArgumentParser(description="Запуск XMPP-бота")
|
||||||
|
parser.add_argument(
|
||||||
|
'--profile-dir',
|
||||||
|
required=True,
|
||||||
|
help="Путь к директории профиля бота (например, /usr/local/etc/bots/metabot)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--log-level",
|
||||||
|
default="debug",
|
||||||
|
choices=["debug", "info", "warning", "error", "critical"],
|
||||||
|
help="Уровень логирования (по умолчанию debug)"
|
||||||
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
profile_dir = Path(args.profile_dir).resolve()
|
profile_dir = Path(args.profile_dir).resolve()
|
||||||
if not profile_dir.exists():
|
if not profile_dir.exists():
|
||||||
print(f"Ошибка: директория {profile_dir} не существует")
|
print(f"Ошибка: директория {profile_dir} не существует")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Создаём событийный цикл
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user