<!-- Bothost docs | HTML: https://bothost.ru/docs/api-reference | Markdown: https://bothost.ru/docs/api-reference.md | Index: https://bothost.ru/llms.txt -->

# Bothost API Reference

Документация по API для разработчиков ботов на платформе Bothost.

## Содержание

- [Переменные окружения](#переменные-окружения)
- [API для управления ботом](#api-для-управления-ботом)
- [Примеры использования](#примеры-использования)

---

## Переменные окружения

Каждый бот получает следующие переменные окружения:

### Основные переменные

| Переменная | Описание | Пример |
|------------|----------|--------|
| `BOT_ID` | Уникальный ID бота | `bot_1764482446_5595_proxyrp` |
| `BOT_TOKEN` | Токен бота (основной) | `8424863414:AAF1Plz...` |
| `USER_ID` | ID пользователя (владельца) | `username123` |
| `DOMAIN` | Доменное имя бота (если назначено) | `mybot.bothost.ru` |
| `TEMPLATE` | Шаблон бота | `discord`, `telegram`, `n8n` |
| `PORT` | Внутренний порт | `3000` |

### Токены (для совместимости)

Для разных библиотек доступны альтернативные имена:

- `BOT_TOKEN` - основной (рекомендуется)
- `DISCORD_TOKEN` / `DISCORD_BOT_TOKEN` - для Discord ботов
- `TELEGRAM_BOT_TOKEN` - для Telegram ботов
- `TOKEN` - универсальное имя
- `API_TOKEN` - альтернативное имя

### Как получить переменные в коде

**Python:**
```python
import os

BOT_ID = os.getenv('BOT_ID')
BOT_TOKEN = os.getenv('BOT_TOKEN')

if not BOT_TOKEN:
    print("❌ Токен не найден!")
    exit(1)
```

**Node.js:**
```javascript
const BOT_ID = process.env.BOT_ID;
const BOT_TOKEN = process.env.BOT_TOKEN;

if (!BOT_TOKEN) {
    console.error('❌ Токен не найден!');
    process.exit(1);
}
```

---

## API для управления ботом

### ⚠️ Важно: Безопасность

API агента доступен только из внутренней сети Docker. Бот может управлять только самим собой, используя свой `BOT_ID`.

### Базовый URL

API агента доступен по адресу:
- **Из контейнера бота:** `http://agent:8000` (внутренняя сеть Docker)
- **Извне:** `http://agent.bothost.ru` или `http://msk1.bothost.ru` (зависит от ноды)

**Рекомендация:** Используйте переменную окружения или определяйте URL автоматически.

### Endpoints

#### 1. Перезапуск бота (самоперезапуск) ⭐ Рекомендуется

**Endpoint:** `POST /api/bots/self/restart`

**Описание:** Безопасный endpoint для самоперезапуска бота. Бот может перезапустить только сам себя.

**Заголовки:**
```
X-Bot-ID: bot_1764482446_5595_proxyrp
```

**Или:** Бот может не передавать заголовок - система автоматически определит `BOT_ID` из имени контейнера.

**Запрос:**
```http
POST /api/bots/self/restart
X-Bot-ID: bot_1764482446_5595_proxyrp
```

**Ответ (успех):**
```json
{
  "ok": true,
  "message": "Бот bot_1764482446_5595_proxyrp перезапущен"
}
```

**Ответ (ошибка):**
```json
{
  "ok": false,
  "msg": "BOT_ID не найден. Передайте его в заголовке X-Bot-ID"
}
```

**Пример использования:**
```python
import os
import aiohttp

BOT_ID = os.getenv('BOT_ID')
AGENT_URL = os.getenv('BOTHOST_AGENT_URL', 'http://agent:8000')

async with aiohttp.ClientSession() as session:
    async with session.post(
        f"{AGENT_URL}/api/bots/self/restart",
        headers={'X-Bot-ID': BOT_ID}
    ) as response:
        result = await response.json()
        print(result)
```

#### 2. Перезапуск бота (стандартный)

**Endpoint:** `POST /api/bots/restart`

**Описание:** Перезапускает контейнер бота (требует bot_id и user_id).

**Запрос:**
```json
{
  "bot_id": "bot_1764482446_5595_proxyrp",
  "user_id": "username123"
}
```

**Ответ (успех):**
```json
{
  "ok": true,
  "message": "Бот bot_1764482446_5595_proxyrp перезапущен"
}
```

**Ответ (ошибка):**
```json
{
  "ok": false,
  "msg": "Ошибка перезапуска бота: ..."
}
```

#### 2. Остановка бота

**Endpoint:** `POST /api/bots/stop`

**Запрос:**
```json
{
  "bot_id": "bot_1764482446_5595_proxyrp",
  "user_id": "username123"
}
```

#### 3. Запуск бота

**Endpoint:** `POST /api/bots/start`

**Запрос:**
```json
{
  "bot_id": "bot_1764482446_5595_proxyrp",
  "user_id": "username123"
}
```

#### 4. Получение логов

**Endpoint:** `POST /api/bots/logs`

**Запрос:**
```json
{
  "bot_id": "bot_1764482446_5595_proxyrp",
  "lines": 100
}
```

**Ответ:**
```json
{
  "ok": true,
  "logs": "Логи бота..."
}
```

#### 5. Получение статистики

**Endpoint:** `GET /api/bots/{bot_id}/stats`

**Ответ:**
```json
{
  "ok": true,
  "stats": {
    "cpu_percent": 15.5,
    "memory_usage": "125MB",
    "memory_percent": 12.3,
    "uptime": "2h 30m"
  }
}
```

---

## Примеры использования

### Python (discord.py) - Перезапуск бота

```python
import os
import aiohttp
import discord
from discord.ext import commands

BOT_ID = os.getenv('BOT_ID')
AGENT_URL = os.getenv('BOTHOST_AGENT_URL', 'http://agent:8000')
USER_ID = os.getenv('USER_ID')

bot = commands.Bot(command_prefix='!', intents=discord.Intents.default())

@bot.command(name='restart')
async def restart_command(ctx):
    """Перезапустить бота через API"""
    if not BOT_ID:
        await ctx.send("❌ BOT_ID не найден в переменных окружения")
        return
    
    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(
                f"{AGENT_URL}/api/bots/restart",
                json={
                    "bot_id": BOT_ID,
                    "user_id": USER_ID
                },
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                result = await response.json()
                
                if result.get('ok'):
                    await ctx.send(f"✅ {result.get('message', 'Бот перезапущен')}")
                else:
                    await ctx.send(f"❌ Ошибка: {result.get('msg', 'Неизвестная ошибка')}")
        except Exception as e:
            await ctx.send(f"❌ Ошибка подключения к API: {str(e)}")

bot.run(os.getenv('BOT_TOKEN'))
```

### Python (aiogram) - Перезапуск бота

```python
import os
import aiohttp
from aiogram import Bot, Dispatcher, types
from aiogram.filters import Command

BOT_ID = os.getenv('BOT_ID')
AGENT_URL = os.getenv('BOTHOST_AGENT_URL', 'http://agent:8000')
USER_ID = os.getenv('USER_ID')

bot = Bot(token=os.getenv('BOT_TOKEN'))
dp = Dispatcher()

@dp.message(Command("restart"))
async def restart_command(message: types.Message):
    """Перезапустить бота через API"""
    if not BOT_ID:
        await message.answer("❌ BOT_ID не найден")
        return
    
    async with aiohttp.ClientSession() as session:
        try:
            async with session.post(
                f"{AGENT_URL}/api/bots/restart",
                json={"bot_id": BOT_ID, "user_id": USER_ID},
                timeout=aiohttp.ClientTimeout(total=10)
            ) as response:
                result = await response.json()
                
                if result.get('ok'):
                    await message.answer(f"✅ {result.get('message')}")
                else:
                    await message.answer(f"❌ {result.get('msg')}")
        except Exception as e:
            await message.answer(f"❌ Ошибка: {str(e)}")

if __name__ == '__main__':
    import asyncio
    asyncio.run(dp.start_polling(bot))
```

### Node.js (discord.js) - Перезапуск бота

```javascript
const { Client, GatewayIntentBits } = require('discord.js');
const axios = require('axios');

const BOT_ID = process.env.BOT_ID;
const AGENT_URL = process.env.BOTHOST_AGENT_URL || 'http://agent:8000';
const USER_ID = process.env.USER_ID;

const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.on('ready', () => {
    console.log(`✅ Бот ${client.user.tag} запущен!`);
});

client.on('messageCreate', async (message) => {
    if (message.content === '!restart') {
        if (!BOT_ID) {
            return message.reply('❌ BOT_ID не найден');
        }
        
        try {
            const response = await axios.post(
                `${AGENT_URL}/api/bots/restart`,
                {
                    bot_id: BOT_ID,
                    user_id: USER_ID
                },
                { timeout: 10000 }
            );
            
            if (response.data.ok) {
                message.reply(`✅ ${response.data.message}`);
            } else {
                message.reply(`❌ ${response.data.msg}`);
            }
        } catch (error) {
            message.reply(`❌ Ошибка: ${error.message}`);
        }
    }
});

client.login(process.env.BOT_TOKEN);
```

---

## Определение URL агента

### Автоматическое определение

Бот может автоматически определить URL агента:

**Python:**
```python
import os
import socket

def get_agent_url():
    """Определяет URL агента автоматически"""
    # Пробуем подключиться к внутренней сети Docker
    try:
        socket.create_connection(('agent', 8000), timeout=1)
        return 'http://agent:8000'
    except:
        # Fallback на внешний URL
        return os.getenv('BOTHOST_AGENT_URL', 'http://agent.bothost.ru')
```

### Через переменную окружения

Можно установить переменную `BOTHOST_AGENT_URL` в настройках бота:
- `http://agent:8000` - для внутренней сети Docker (рекомендуется)
- `http://agent.bothost.ru` - для внешнего доступа
- `http://msk1.bothost.ru` - для второй ноды

---

## Обработка ошибок

### Типичные ошибки

1. **Контейнер не найден**
   ```json
   {"ok": false, "msg": "Контейнер не найден"}
   ```
   **Решение:** Убедитесь, что бот запущен

2. **Таймаут**
   ```json
   {"ok": false, "msg": "Таймаут при перезапуске"}
   ```
   **Решение:** Увеличьте timeout или повторите запрос

3. **Ошибка подключения**
   - Проверьте доступность агента
   - Убедитесь, что используете правильный URL
   - Проверьте сетевые настройки Docker

---

## Безопасность

### ⚠️ Важные моменты

1. **Бот может управлять только самим собой**
   - Используйте `BOT_ID` из переменных окружения
   - Не передавайте чужие `bot_id` в запросах

2. **Внутренняя сеть Docker**
   - API доступен только из контейнеров
   - Внешний доступ ограничен

3. **Валидация**
   - Всегда проверяйте наличие `BOT_ID` перед вызовом API
   - Обрабатывайте ошибки корректно

---

## Дополнительные ресурсы

- [Переменные окружения](./ENVIRONMENT_VARIABLES.md)
- [Примеры ботов](./EXAMPLES.md)
- [Troubleshooting](./TROUBLESHOOTING.md)

---

**Версия документации:** 1.0  
**Последнее обновление:** 2025-01-XX

