# Session Server

Сессионный сервер для автоматической регистрации на основном API сервере.

## Описание

Session Server - это приложение, которое автоматически регистрируется на основном сервере (`stream.graff.tech`) и периодически обновляет свою информацию. Это позволяет основному серверу знать о доступных сессионных серверах для распределения нагрузки.

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

- 🚀 Автоматическая регистрация при запуске
- 🔄 Периодическое обновление информации о сервере (по умолчанию каждые 30 секунд после завершения предыдущего запроса)
- 🎮 Автоматическое определение и обновление свободной GPU памяти через nvidia-smi (по умолчанию каждую секунду после завершения предыдущего запроса)
- 🎯 Автоматическое управление игровыми сессиями
  - Запуск приложений для сессий со статусом "starting"
  - Остановка приложений для сессий со статусом "ending"
  - Отслеживание PID запущенных процессов
  - Автоматическое обновление статусов сессий на главном сервере
- 🌐 Автоматическое определение локального IP адреса
- 💻 Автоматическое определение hostname
- ⚙️ Гибкая конфигурация через переменные окружения
- 🔁 Автоматические повторные попытки при ошибках
- 📝 Подробное логирование
- ⚡ Защита от наложения запросов для всех операций (рекурсивный вызов через setTimeout)

## Установка

```bash
# Установка зависимостей
bun install
```

## Конфигурация

Создайте файл `.env` в корне проекта на основе `.env.example`:

```bash
# URL основного API сервера
API_URL=http://localhost:3000

# Тип сервера: stream или local
SERVER_TYPE=stream

# Расположение сервера (ОБЯЗАТЕЛЬНО для stream серверов)
# Возможные значения: ru1, uae1
SERVER_LOCATION=ru1

# Уровень сервера (только для stream серверов)
# Возможные значения: demo, prod
SERVER_TIER=demo

# ID филиала (ОБЯЗАТЕЛЬНО для local серверов)
BRANCH_ID=00000000-0000-0000-0000-000000000000

# Локальный IP адрес (опционально, определяется автоматически)
# LOCAL_IP=192.168.1.100

# Hostname сервера (опционально, определяется автоматически)
# HOSTNAME=my-session-server

# Интервал регистрации в миллисекундах (по умолчанию 30000 = 30 секунд)
REGISTER_INTERVAL_MS=30000

# Интервал обновления GPU памяти в миллисекундах (по умолчанию 1000 = 1 секунда)
GPU_UPDATE_INTERVAL_MS=1000

# Интервал проверки сессий в миллисекундах (по умолчанию 5000 = 5 секунд)
SESSION_CHECK_INTERVAL_MS=5000
```

### Переменные окружения

| Переменная | Описание | Обязательна | По умолчанию |
|------------|----------|-------------|--------------|
| `API_URL` | URL основного API сервера | Нет | `http://localhost:3000` |
| `SERVER_TYPE` | Тип сервера (`stream` или `local`) | Нет | `stream` |
| `SERVER_LOCATION` | Расположение (`ru1`, `uae1`) - **обязательно для `stream`** | Да (для stream) | - |
| `SERVER_TIER` | Уровень (`demo`, `prod`) - только для `stream` | Нет | `demo` (для stream) |
| `BRANCH_ID` | ID филиала - **обязательно для `local`** | Да (для local) | - |
| `LOCAL_IP` | Локальный IP адрес | Нет | Определяется автоматически |
| `HOSTNAME` | Hostname сервера | Нет | Определяется автоматически |
| `REGISTER_INTERVAL_MS` | Интервал регистрации в мс | Нет | `30000` |
| `GPU_UPDATE_INTERVAL_MS` | Интервал обновления GPU памяти в мс | Нет | `1000` |
| `SESSION_CHECK_INTERVAL_MS` | Интервал проверки сессий в мс | Нет | `5000` |

**Примечание:** Свободная память GPU (`gpuFreeMb`) автоматически определяется через `nvidia-smi` при каждой регистрации и обновляется каждую секунду (или согласно `GPU_UPDATE_INTERVAL_MS`) после завершения предыдущего запроса. Это предотвращает наложение запросов. Если `nvidia-smi` недоступен, сервер завершит работу с ошибкой.

## Управление сессиями

Session Server автоматически управляет игровыми сессиями на этом сервере:

### Как это работает

1. **Проверка сессий**: Каждую секунду (или согласно `SESSION_CHECK_INTERVAL_MS`) сервер запрашивает у основного API список сессий для этого сервера
2. **Запуск приложений**: Для сессий со статусом `starting`:
   - ⏰ Проверяется время `startAt` - приложение запускается только если это время уже наступило
   - **Timezone**: Все время хранится в UTC, сравнение корректно работает независимо от часового пояса сервера
   - Запланированные сессии (с будущим `startAt`) логируются с информацией о времени до запуска
   - 🎯 **Централизованное назначение сервера** (для stream-сессий):
     - **Main server** автоматически назначает серверы каждые 5 секунд
     - Выбирается сервер с максимальной свободной GPU памятью
     - Учитываются требования приложения к GPU памяти (`gpuLimitMb`)
     - Session-server просто проверяет, что сессия назначена ему
   - Запускается соответствующее приложение
   - Отслеживается PID процесса
   - Статус сессии обновляется на `started` на главном сервере
3. **Остановка приложений**: Для сессий со статусом `ending`:
   - Используется `taskkill /pid {PID} /T /F` для завершения всего дерева процессов
   - `/T` - завершает указанный процесс и ВСЕ дочерние процессы
   - `/F` - принудительное завершение
   - Решает проблему с UE5 и другими приложениями, создающими дочерние процессы
   - Статус сессии обновляется на `ended` на главном сервере
4. **Автоматическая очистка**: Процессы для неактивных сессий автоматически останавливаются

### API endpoints для управления сессиями

Session Server взаимодействует с основным сервером через следующие endpoints:

- `GET /servers/:id/sessions` - получить список сессий для сервера
- `PATCH /sessions/:id/status` - обновить статус сессии (публичный endpoint)

### Запуск приложений

Session Server автоматически запускает `.exe` приложения по стандартному пути:

```
C:\apps\{appName}\{appName}.exe
```

Где `{appName}` - это значение поля `name` из таблицы `apps`.

#### Структура директорий

Все приложения должны быть размещены в следующей структуре:
```
C:\apps\
├── minecraft\
│   └── minecraft.exe
├── fortnite\
│   └── fortnite.exe
└── cyberpunk\
    └── cyberpunk.exe
```

#### Особенности запуска и остановки

- ✅ Автоматическая проверка существования exe файла
- ✅ Рабочая директория устанавливается в папку приложения (`C:\apps\{appName}\`)
- ✅ Окно консоли скрывается (`windowsHide: true`)
- ✅ PID процесса отслеживается и передается на main server
- ✅ Автоматическое обновление статуса при завершении процесса
- ✅ **Корректное завершение дочерних процессов** - использует `taskkill /T` для завершения всего дерева процессов
- ✅ Решает проблему с UE5 приложениями, которые создают множественные процессы

#### Логи запуска

```
[2025-10-06T10:00:00.000Z] 🚀 Запуск приложения "minecraft" для сессии abc-123
[2025-10-06T10:00:00.050Z] 📂 Путь к приложению: C:\apps\minecraft\minecraft.exe
[2025-10-06T10:00:01.000Z] ✅ Приложение запущено с PID 12345
[2025-10-06T10:00:01.100Z] ✅ Статус сессии abc-123 обновлен на "started"
```

#### Обработка ошибок

Если exe файл не найден:
```
❌ Файл приложения не найден: C:\apps\minecraft\minecraft.exe. Убедитесь, что приложение установлено.
```

### Примеры логов

Запланированная сессия:
```
[2025-10-06T10:00:00.000Z] ⏰ Сессия 123e4567-e89b-12d3-a456-426614174000 (minecraft) запланирована через 120 сек
```

Запуск сессии:
```
[2025-10-06T10:02:00.000Z] 🚀 Запуск приложения "minecraft" для сессии 123e4567-e89b-12d3-a456-426614174000
[2025-10-06T10:02:01.000Z] ✅ Приложение запущено с PID 12345
[2025-10-06T10:02:01.100Z] ✅ Статус сессии 123e4567-e89b-12d3-a456-426614174000 обновлен на "started"
```

Остановка сессии:
```
[2025-10-06T10:32:00.000Z] 🛑 Остановка приложения для сессии 123e4567-e89b-12d3-a456-426614174000 (PID: 12345)
[2025-10-06T10:32:00.500Z] ✅ Дерево процессов для PID 12345 успешно завершено
[2025-10-06T10:32:00.600Z] ✅ Приложение и все дочерние процессы остановлены для сессии 123e4567-e89b-12d3-a456-426614174000
[2025-10-06T10:32:00.700Z] ✅ Статус сессии 123e4567-e89b-12d3-a456-426614174000 обновлен на "ended"
```

## Отладка проблем (Troubleshooting)

Если приложение запускается и сразу завершается с ошибкой, см. подробное руководство по диагностике:
- **[TROUBLESHOOTING.md](./TROUBLESHOOTING.md)**

### Новые возможности логирования

После обновления вы увидите:
- 🔴 **STDERR логи** для диагностики ошибок приложений
- 📊 **Счётчик активных процессов** при запуске/завершении
- ⚠️ **Детальная информация** о кодах выхода и сигналах

Пример логов с ошибкой:
```
[10:51:56.498Z] 🚀 Запуск приложения "ShishimGorka" для сессии abc (активных процессов: 1)
[10:51:56.563Z] ✅ Приложение запущено с PID 84112 (всего активных: 2)
[10:51:57.500Z] 🔴 STDERR [abc]: Error: Port 8888 is already in use
[10:51:57.894Z] 🛑 Приложение для сессии abc завершилось с кодом 1
[10:51:57.894Z] ⚠️ Приложение завершилось с ошибкой! Код выхода: 1
```

## Работа с часовыми поясами (Timezone)

Session Server корректно работает с разными часовыми поясами:

### Как это работает

1. **База данных**: PostgreSQL хранит все timestamp с timezone в UTC
2. **API**: Основной сервер возвращает время в формате ISO 8601 с timezone (например, `2025-10-06T10:00:00.000Z`)
3. **Session Server**: JavaScript автоматически парсит ISO 8601 строки в UTC
4. **Сравнение**: Все сравнения времени происходят в UTC, независимо от локального часового пояса сервера

### Миграция базы данных

⚠️ **Важно**: Если вы обновляете существующую систему, необходимо выполнить миграцию для добавления timezone в поля `startAt` и `endAt`:

```bash
# Из директории server/
psql -d $DATABASE_URL -f timezone_migration.sql
```

См. `server/TIMEZONE_MIGRATION.md` для подробностей.

### Примеры

Если сервер в России создаёт сессию на 14:00 по московскому времени (UTC+3):
- В БД сохранится: `2025-10-06T11:00:00.000Z` (UTC)
- Сервер в ОАЭ (UTC+4) увидит: 15:00 по местному времени
- Session Server запустит приложение ровно в 11:00 UTC, независимо от локального времени

## Запуск

### Development режим

```bash
bun run dev
```

### Production режим

```bash
# Собрать проект
bun run build

# Запустить собранное приложение
bun run start
```

## Примеры использования

### Stream сервер в России (демо)

```env
API_URL=https://api.stream.graff.tech
SERVER_TYPE=stream
SERVER_LOCATION=ru1
SERVER_TIER=demo
REGISTER_INTERVAL_MS=30000
```

### Stream сервер в ОАЭ (продакшн)

```env
API_URL=https://api.stream.graff.tech
SERVER_TYPE=stream
SERVER_LOCATION=uae1
SERVER_TIER=prod
REGISTER_INTERVAL_MS=30000
```

### Local сервер для филиала

```env
API_URL=https://api.stream.graff.tech
SERVER_TYPE=local
BRANCH_ID=123e4567-e89b-12d3-a456-426614174000
REGISTER_INTERVAL_MS=60000
```

## Логирование

Сервер выводит подробную информацию о своей работе:

```text
============================================================
🚀 Запуск сессионного сервера
============================================================
Конфигурация:
  API URL: http://localhost:3000
  Hostname: DESKTOP-ABC123
  Local IP: 192.168.1.100
  Type: stream
  GPU Free MB: 8192 (читается из nvidia-smi)
  Location: ru1
  Tier: demo
  Register Interval: 30000ms
  GPU Update Interval: 1000ms
============================================================
[2025-10-06T12:00:00.000Z] Регистрация сервера...
Данные: {
  "localIp": "192.168.1.100",
  "hostname": "DESKTOP-ABC123",
  "type": "stream",
  "gpuFreeMb": 8192,
  "location": "ru1",
  "tier": "demo"
}
[2025-10-06T12:00:00.123Z] ✅ Сервер успешно зарегистрирован
ID сервера: 123e4567-e89b-12d3-a456-426614174000
[2025-10-06T12:00:01.000Z] 🎮 GPU память обновлена: 8150 MB
[2025-10-06T12:00:02.000Z] 🎮 GPU память обновлена: 8120 MB
[2025-10-06T12:00:03.000Z] 🎮 GPU память обновлена: 8100 MB
```

## Обработка ошибок

Сервер автоматически обрабатывает ошибки:

- **Валидация конфигурации**:
  - Stream-серверы: обязательно должен быть указан `SERVER_LOCATION`
  - Local-серверы: обязательно должен быть указан `BRANCH_ID`
  - При отсутствии обязательных полей сервер завершит работу с критической ошибкой
- **Сетевые ошибки**: Автоматические повторные попытки (до 3 раз)
- **Таймауты**: 10 секунд на запрос
- **Коды ошибок**: Повторная отправка при временных ошибках сервера (408, 429, 500, 502, 503, 504)
- **Ошибки GPU**: Если `nvidia-smi` недоступен или возвращает некорректные данные, сервер завершит работу с критической ошибкой
- **Критические ошибки**: Подробное логирование с завершением работы

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

```text
┌──────────────────────────────────┐
│        Session Server            │
│                                  │
│  Регистрация (рекурсивно):       │
│  1. Определение IP               │
│  2. Определение hostname         │
│  3. Запрос GPU (nvidia-smi)      │
│  4. POST /servers/register       │
│  5. setTimeout → повтор (30s)    │
│                                  │
│  Обновление GPU (рекурсивно):    │
│  1. Запрос GPU (nvidia-smi)      │
│  2. PATCH /servers/:id/gpu       │
│  3. setTimeout → повтор (1s)     │
└──────────┬───────────────────────┘
           │
           │ HTTP Requests
           │
           ▼
┌──────────────────────────────────┐
│       Main API Server            │
│                                  │
│  1. Проверка по hostname         │
│  2. Создание/обновление          │
│  3. Обновление GPU памяти        │
│  4. Возврат данных               │
└──────────────────────────────────┘
```

## Разработка

### Структура проекта

```text
session-server/
├── src/
│   └── index.ts        # Основной файл приложения
├── dist/               # Собранное приложение
├── package.json
├── tsconfig.json
├── bun.build.ts       # Конфигурация сборки
└── README.md
```

### Требования

- Bun >= 1.0
- Node.js >= 18 (опционально)
- TypeScript >= 5.0
- **NVIDIA GPU с установленным `nvidia-smi`** (обязательно)

## Лицензия

MIT
