Философия Xioca

Xioca — это современный асинхронный Telegram-юзербот, построенный на Pyrogram. В его основе лежат три ключевых принципа:

  • Модульность: Вся функциональность разделена на независимые модули. Это позволяет легко добавлять, удалять и обновлять возможности юзербота на лету, без перезагрузки.
  • Автоматизация: Xioca берет на себя рутинные задачи. Автоматическая установка зависимостей и управление базой данных позволяют разработчику сосредоточиться на логике модуля, а не на его окружении.
  • Удобство для разработчика: Продуманная архитектура и набор утилит делают процесс создания модулей максимально простым и интуитивно понятным.

Анатомия модуля

Каждый модуль в Xioca представляет собой Python-класс, унаследованный от loader.Module. Для корректной загрузки название класса должно заканчиваться на суффикс Mod.

Python (e.g., MyModuleMod.py)
# required: requests emoji
# О зависимостях читайте в соответствующем разделе

import requests
import emoji
from .. import loader, utils

@loader.module(author="YourName", version="1.0.0")
class ExampleMod(loader.Module):
    """Краткое описание вашего модуля. Оно будет видно в .help"""
    
    # Код вашего модуля...

Декоратор @loader.module(...) является необязательным, но крайне рекомендуется. Он позволяет указать метаданные: автора (author) и версию (version), которые будут отображаться в списке модулей.

Жизненный цикл модуля

В модуле можно определить асинхронный метод on_load. Этот метод будет автоматически вызван один раз после успешной загрузки и инициализации модуля. Это идеальное место для выполнения подготовительных действий.

Python
class ExampleMod(loader.Module):
    """Пример модуля с on_load"""
    
    async def on_load(self):
        # Этот код выполнится один раз при загрузке модуля
        # Например, можно проверить API ключи или создать нужные записи в БД
        await self.db.set("launch_count", self.db.get("launch_count", 0) + 1)
        logging.info(f"Модуль ExampleMod загружен! Количество запусков: {await self.db.get('launch_count')}")

Управление зависимостями

Это одна из ключевых особенностей Xioca. Вам не нужно просить пользователя устанавливать библиотеки вручную через pip. Достаточно указать их в специальном комментарии в самом начале файла модуля.

Как это работает: Просто добавьте в начало файла строку # required: aiohttp pillow requests, перечислив нужные библиотеки через пробел. При загрузке модуля Xioca автоматически установит их, если они отсутствуют.
Python
# required: beautifulsoup4
from bs4 import BeautifulSoup
from .. import loader

@loader.module(author="YourName", version="1.0.0")
class ParserMod(loader.Module):
    """Этот модуль требует beautifulsoup4 для работы"""
    # ...

Создание команд

Команды — это основной способ взаимодействия с юзерботом. Чтобы создать команду, определите в классе асинхронный метод с суффиксом _cmd. Название метода без суффикса станет именем команды.

Python
async def ping_cmd(self, app, message, args):
    """Проверяет пинг до серверов Telegram.
    Использование: .ping"""
    # app: экземпляр pyrogram.Client
    # message: объект pyrogram.types.Message
    # args: строка с аргументами после команды
    
    await utils.answer(message, "🏓 Pong!")

Аргументы команды

Все, что пользователь напишет после команды, передается в метод в виде единой строки args. Для разделения аргументов удобно использовать utils.get_args_raw() или args.split().

Документация команд (Docstrings)

Содержимое docstring (строка документации) вашей команды автоматически используется для создания справки, доступной по команде .help <имя модуля>. Рекомендуется всегда описывать назначение команды и формат ее использования.

Обработчики событий

Помимо команд, модули могут реагировать на различные события в Telegram: новые сообщения, нажатия на инлайн-кнопки и т.д. Это позволяет создавать сложную интерактивную логику.

Обработчик сообщений (Message Handler)

Реагирует на сообщения, соответствующие определенным фильтрам. Метод должен иметь суффикс _message_handler. Используйте декоратор @loader.on_bot(...) с функцией-фильтром.

Python
from pyrogram import filters

# Фильтр: личные сообщения, содержащие "привет"
@loader.on_bot(filters.private & filters.regex(r"(?i)привет"))
async def hello_message_handler(self, app, message):
    """Отвечает на 'привет' в личных сообщениях"""
    await message.reply("И тебе привет! 👋")

Обработчик Callback-запросов (Inline Buttons)

Срабатывает при нажатии на инлайн-кнопку. Метод должен иметь суффикс _callback_handler. Фильтрация обычно происходит по полю call.data.

Python
# Фильтр: callback data начинается с 'example_'
@loader.on_bot(filters.create(lambda _, __, q: q.data.startswith("example_")))
async def example_callback_handler(self, app, call):
    """Обрабатывает нажатия на кнопки с префиксом 'example_'"""
    data_part = call.data.split("_")[1]
    await call.answer(f"Вы выбрали опцию: {data_part}!", show_alert=True)

Наблюдатели (Watchers)

Watchers — это особый тип обработчиков, которые срабатывают на **все** входящие и исходящие сообщения в чатах, где вы состоите. Они выполняются раньше команд и идеально подходят для фонового мониторинга, сбора статистики или AFK-модулей. Название метода-наблюдателя должно начинаться с префикса watcher.

Python
@loader.on(filters.mentioned)
async def watcher_mention(self, app, message):
    """Среагирует, если вас упомянули в чате"""
    await app.send_message("me", f"Вас упомянули в чате «{message.chat.title}»!")

Работа с базой данных

Xioca предоставляет каждому модулю свою собственную, изолированную key-value базу данных. Вам не нужно заботиться о ее создании или подключении — просто используйте методы объекта self.db. Система автоматически преобразует списки и словари в JSON для хранения.

Ключевая особенность: База данных для вашего модуля создается автоматически при первой попытке записи. Это "Zero-Config" подход.

Сохранение значения

Используйте метод self.db.set(key, value).

Python
# Сохранение строки
await self.db.set("api_key", "my-secret-key-123")

# Сохранение списка ID
await self.db.set("trusted_users", [12345, 54321])

# Сохранение словаря (конфигурации)
config = {"enabled": True, "level": "admin"}
await self.db.set("module_config", config)

Получение значения

Используйте метод self.db.get(key, default=None). Если ключ не найден, вернется значение по умолчанию.

Python
# Получение строки
api_key = await self.db.get("api_key")

# Получение списка (если его нет, вернется пустой список)
trusted_users = await self.db.get("trusted_users", [])

# Получение словаря
config = await self.db.get("module_config", {})

Удаление значения

Используйте метод self.db.delete(key).

Логирование и отладка

Вместо использования print() для отладки, используйте встроенный в Python модуль logging. Xioca перехватывает его вывод и направляет в специальный лог-чат в вашем Telegram-аккаунте.

Интерактивные отчеты об ошибках: Если в вашем модуле произойдет неперехваченное исключение, в лог-чат придет подробное сообщение об ошибке с инлайн-кнопкой "Full traceback". Это позволяет быстро диагностировать и исправлять проблемы.
Python
import logging

class DebugMod(loader.Module):
    async def debug_cmd(self, app, message, args):
        logging.info("Команда debug запущена.")
        
        if not args:
            logging.warning("Пользователь не ввел аргументы!")
            return await utils.answer(message, "⚠️ Аргументы не указаны.")
            
        try:
            result = 10 / 0
        except Exception:
            logging.error("Произошла ошибка деления на ноль!", exc_info=True)
            await utils.answer(message, "🚨 Произошла ошибка. Отчет отправлен в лог-чат.")

Полезные утилиты

Xioca поставляется с набором готовых функций-хелперов в модуле utils, которые упрощают рутинные задачи.

  • utils.answer(message, text, **kwargs)

    Это основной способ отправки ответов. Он "умный": если вы отвечаете на свое же сообщение, он его отредактирует. В противном случае — отправит новое сообщение в ответ на исходное. Поддерживает все аргументы Pyrogram send_message.

  • utils.get_args_raw(message)

    Возвращает строку с аргументами команды.

  • utils.get_chat_id(message)

    Надежный способ получить ID текущего чата.

Совет: Всегда используйте await asyncio.sleep() для асинхронных пауз вместо блокирующего time.sleep(), чтобы не останавливать работу всего юзербота.