Metadata-Version: 2.4
Name: diserve
Version: 0.1.2
Summary: Async Discord bot framework without discord.py
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: aiohttp>=3.9.0

# diserve

`diserve` — асинхронная Python-библиотека для создания Discord-ботов без `discord.py` и других SDK-обёрток. Фреймворк работает напрямую с Discord Gateway и Discord REST API через `aiohttp`.

## Возможности

- Полностью асинхронная архитектура на `asyncio`
- Префиксные команды через `@bot.command()`
- Slash-команды через `@bot.slash_command()` с авто-генерацией options по сигнатуре
- События `@bot.event` (`on_ready`, `on_message`, `on_command_error` и другие)
- Контекст команд `ctx` с `reply`, `send`, `defer`, `followup`
- Встроенные модели `User`, `Message`, `Channel`, `Guild`
- Embed-система
- UI-компоненты: кнопки, select menu, action row
- Modal и text input
- Intents, Activity, Color
- Система расширений (cogs/extensions)
- CLI: `diserve init`, `diserve run`, `diserve version`

## Установка

### Вариант 1: локально из исходников

```bash
pip install -e .
```

### Вариант 2: как зависимость проекта

```bash
pip install aiohttp
```

Далее добавьте пакет `diserve` в ваш проект.

## Быстрый старт через CLI

### 1. Инициализировать проект

```bash
diserve init --name bottable --prefix "." --token "TOKEN"
```

Будет создана папка `bottable/` с базовым `bot.py` и `pyproject.toml`.

### 2. Запуск

```bash
cd bottable
diserve run
```

### 3. Версия CLI

```bash
diserve version
```

Ожидаемый формат:

```text
diserve  v0.1.2
```

## Полный пример бота

```python
import diserve
from diserve import Bot, Command, Embed, Color

bot = diserve.Bot(
    prefix="!",
    intents=diserve.Intents.all(),
    activity=diserve.Activity(
        type=diserve.ActivityType.watching,
        name="the world burn",
    ),
)

@bot.command()
async def ping(ctx: Command):
    await ctx.reply("Pong!")

@bot.slash_command(name="hello", description="Says hello to the user")
async def hello(ctx: Command):
    await ctx.reply(f"Hello, {ctx.author.mention}!")

@bot.slash_command(name="sum", description="Складывает два числа")
async def sum(ctx: Command, a: int, b: int):
    await ctx.reply(f"{a} + {b} = {a + b}")

@bot.slash_command(name="embed", description="Sends an embed message")
async def embed(ctx: Command):
    emb = Embed(
        title="This is an embed",
        description="This is the description of the embed",
        color=Color.blue(),
    )
    emb.add_field(name="Field 1", value="Value 1", inline=False)
    emb.set_footer(text="Footer text")
    await ctx.reply(embed=emb)

@bot.command()
async def clear(ctx: Command, amount: int):
    await ctx.channel.purge(limit=amount)

@bot.event
async def on_ready():
    print(f"Logged in as {bot.user.username} (ID: {bot.user.id})")
    print(f"Guilds: {bot.guild_count} | Commands: {len(bot.commands)}")
    print(f"Latency: {bot.latency * 1000:.0f}ms")

@bot.event
async def on_command_error(ctx, error):
    if ctx is not None:
        await ctx.reply(f"Ошибка: {error}")

bot.run("TOKEN")
```

## Архитектура проекта

```text
diserve/
├── client/
│   ├── bot.py
│   ├── gateway.py
│   └── http.py
├── models/
│   ├── user.py
│   ├── guild.py
│   ├── message.py
│   └── channel.py
├── commands/
│   ├── command.py
│   ├── slash.py
│   └── context.py
├── ui/
│   ├── embed.py
│   ├── modal.py
│   └── components.py
├── utils/
│   ├── color.py
│   ├── intents.py
│   └── activity.py
├── ext/
│   └── cogs.py
└── cli/
    └── main.py
```

## Подробно: как создать бота на базе diserve

### Шаг 1. Создайте приложение в Discord Developer Portal

1. Откройте Discord Developer Portal
2. Нажмите `New Application`
3. Создайте `Bot`
4. Скопируйте токен
5. Включите необходимые Privileged Gateway Intents при необходимости
6. Сгенерируйте Invite URL с нужными scope/permissions

### Шаг 2. Подготовьте окружение

```bash
python -m venv .venv
source .venv/bin/activate
pip install -e .
```

### Шаг 3. Создайте файл `bot.py`

Минимум:

```python
import diserve

bot = diserve.Bot(prefix="!", intents=diserve.Intents.all())

@bot.command()
async def ping(ctx):
    await ctx.reply("Pong!")

bot.run("TOKEN")
```

### Шаг 4. Добавьте события

```python
@bot.event
async def on_ready():
    print("ready")

@bot.event
async def on_message(message):
    print(message.content)
```

### Шаг 5. Добавьте slash-команды

`diserve` регистрирует global slash-команды при запуске бота.

```python
@bot.slash_command(name="ban", description="Ban user")
async def ban(ctx, user_id: int, reason: str = "-"):
    await ctx.reply(f"Ban request for {user_id} with reason: {reason}")
```

Правила автогенерации типов аргументов:

- `str` -> STRING
- `int` -> INTEGER
- `bool` -> BOOLEAN
- `float` -> NUMBER

### Шаг 6. Работа с ctx

`ctx` содержит:

- `ctx.author`
- `ctx.channel`
- `ctx.guild`
- `ctx.message`
- `ctx.bot`

Методы:

- `await ctx.reply(...)`
- `await ctx.send(...)`
- `await ctx.defer(...)`
- `await ctx.followup(...)`

### Шаг 7. Embed

```python
embed = diserve.Embed(title="Статус", description="Все работает", color=diserve.Color.green())
embed.add_field(name="Shard", value="0")
embed.set_thumbnail("https://example.com/img.png")
await ctx.reply(embed=embed)
```

### Шаг 8. UI-компоненты

```python
from diserve import Button, SelectMenu, SelectOption, ActionRow

row = ActionRow(components=[
    Button(label="Нажми", custom_id="btn:click", style=1),
])

menu = SelectMenu(
    custom_id="menu:main",
    options=[
        SelectOption(label="A", value="a"),
        SelectOption(label="B", value="b"),
    ],
)
```

### Шаг 9. Modal

```python
from diserve import Modal, TextInput

modal = Modal(
    custom_id="feedback",
    title="Обратная связь",
    components=[
        TextInput(custom_id="text", label="Ваше сообщение", style=2),
    ],
)
```

### Шаг 10. Purge сообщений

```python
@bot.command()
async def clear(ctx, amount: int):
    await ctx.channel.purge(limit=amount)
```

### Шаг 11. Cogs/Extensions

```python
bot.load_extension("mybot.extensions.admin")
bot.unload_extension("mybot.extensions.admin")
```

Пример extension-модуля:

```python
def setup(bot):
    @bot.command()
    async def hi(ctx):
        await ctx.reply("hi")

def teardown(bot):
    pass
```

### Шаг 12. Обработка ошибок

```python
@bot.event
async def on_command_error(ctx, error):
    if ctx:
        await ctx.reply(f"Ошибка команды: {error}")
```

## Рекомендации для production

- Не храните токен в коде, используйте переменные окружения
- Ограничьте intents только нужными
- Логируйте исключения и события
- Добавляйте retry/backoff вокруг нестабильных сетевых операций
- Разделяйте команды по расширениям
- Проверяйте права пользователя перед опасными операциями

## Публичное API

```python
import diserve
from diserve import (
    Bot,
    Command,
    Embed,
    Color,
    Intents,
    Activity,
    ActivityType,
    Button,
    SelectMenu,
    SelectOption,
    ActionRow,
    Modal,
    TextInput,
)
```

## Лицензия

Проект распространяется по лицензии вашего репозитория.
