Files
..
2026-06-22 22:01:09 +04:00
2026-06-22 22:01:09 +04:00
2026-06-22 22:01:09 +04:00

x0gp server (PoC)

Минимальный Go-сервер для сквозной проверки идеи x0gp: WebSocket-клиент (браузер) отправляет команды руля/газа, сервер гоняет упрощённую authoritative-физику на 60 Hz и шлёт снапшоты обратно.

Это PoC. Без биллинга, без CV, без агента на машинке. WebSocket + race engine + Postgres (каталог tracks / cars) + Redis pub/sub.


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

browser -- WS(JSON) --> poc-server -- in-process --> RaceEngine (60 Hz tick)
                                              \-> Snapshot fan-out via Hub

См. ARCHITECTURE.md и PLAN.md для общей картины и будущих фаз.


Структура

server/
  cmd/poc-server/main.go    # точка входа, HTTP + WS, race engine tick
  internal/
    config/                  # env-конфиг
    transport/               # JSON-codec (PoC), envelope, типы сообщений
    control/                 # authoritative race engine (tick 60 Hz, физика)
    realtime/                # WebSocket hub, fan-out, backpressure
    catalog/                 # tracks + cars, интерфейс Store + in-memory cache
      seeddefs/              # Go-определения seed-данных (общие с SQL seed)
    storage/postgres/        # pgx pool, embedded миграции, PgStore
      migrations/            # 001_init.sql, 002_seed.sql
  scripts/genseed/           # утилита для перегенерации 002_seed.sql
  proto/                     # формальная спецификация (proto3)
    client_server.proto
    server_agent.proto
    buf.yaml, buf.gen.yaml
  web/                       # минимальный vanilla-JS клиент
    index.html, main.js, style.css
  Dockerfile                 # multi-stage, linux/arm64 для Orange Pi 5 Pro
  docker-compose.yml         # dev stack: postgres+timescale, redis, prom, grafana
  Makefile                   # build, run, proto, test, docker, compose
  .gitignore
  go.mod

Быстрый старт (на Orange Pi 5 Pro)

1. Подготовка

# Установить Go 1.26+ (если ещё не стоит).
wget https://go.dev/dl/go1.26.4.linux-arm64.tar.gz
sudo tar -C /usr/local -xzf go1.26.4.linux-arm64.tar.gz
export PATH=$PATH:/usr/local/go/bin
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
go version   # должно быть go1.26.x

2. Клонирование и сборка

git clone https://github.com/<you>/x0gp.git
cd x0gp/server

# Тянем зависимости и собираем бинарь под arm64.
make tidy
make build           # -> bin/poc-server-linux-arm64

3. Запуск (минимальный)

X0GP_DEV_MODE=true ./bin/poc-server-linux-arm64

Открыть в браузере на той же машине: http://localhost:8080/. Подключиться через web-интерфейс — увидишь виртуальные машинки, которые гоняют по сцене, реагируя на команды.

4. Запуск полного dev-стека (через docker compose)

make compose-up      # поднимает postgres, redis, prometheus, grafana, api-gateway
# api-gateway будет на http://localhost:8080
# grafana: http://localhost:3000 (admin/admin)
make compose-down    # остановить

5. Деплой в Coolify

(см. ../ops/HOME_SERVER.md)

  • Push репо на GitHub/Gitea.
  • В Coolify: New Resource → Application → подключить репо.
  • Build Pack: Dockerfile.
  • Port: 8080.
  • Env vars: X0GP_DEV_MODE=true для PoC.
  • Healthcheck path: /health.

Конфигурация (env vars)

Variable Default Описание
X0GP_HTTP_ADDR :8080 Адрес HTTP-сервера
X0GP_TICK_RATE 60 Race engine tick (Гц)
X0GP_SNAPSHOT_RATE 30 Snapshot fan-out (Гц)
X0GP_MAX_CLIENTS 100 Лимит одновременных WS
X0GP_LOG_LEVEL info debug/info/warn/error
X0GP_DEV_MODE true PoC-режим: без auth, несколько клиентов
DATABASE_URL обязательно. Строка подключения к Postgres (например postgres://x0gp:x0gp@localhost:5432/x0gp?sslmode=disable). Сервер не стартует без неё.

WebSocket протокол

Все кадры — JSON-объекты с полями type, seq, ts_ms, payload.

См. proto/client_server.proto — формальная спецификация для будущего бинарного protobuf-формата (MVP/prod).

Пример: подключиться и поуправлять машинкой (из консоли)

# Через websocat (apt install websocat).
websocat ws://localhost:8080/ws

# Ввести:
{"type":"client_hello","payload":{"version":"0.1"}}
{"type":"join_race","payload":{"car_slot":0,"car_name":"alice"}}
{"type":"input_state","payload":{"steering":0.5,"throttle":0.8,"brake":0}}
# ... крутить рулём и газом

Сервер сразу же начнёт присылать race_snapshot (30 Гц) с позициями всех машинок.


Метрики и логи

  • /health — healthcheck (JSON).
  • /stats — текущие connection count, snapshot drops, race phase.
  • /metrics — Prometheus metrics (будет в S1).
  • Логи: JSON в stdout (slog), удобно для Loki/Promtail.

Хранилище (Postgres + TimescaleDB)

Каталог (tracks / cars) хранится в Postgres. Миграции лежат в internal/storage/postgres/migrations/*.sql, встроены через //go:embed и применяются автоматически при старте сервера (см. internal/storage/postgres/postgres.go:Migrate). Уже применённые миграции отслеживаются в таблице schema_migrations.

  • 001_init.sql — схема: tracks, track_waypoints, track_tags, cars, плюс CREATE EXTENSION timescaledb (для будущего телеметрического hypertable в S2).
  • 002_seed.sql — system-данные: 3 трассы (oval-classic, figure-eight, sprint-straight) и 2 машины (compact-1-27-touring, compact-1-27-formula). Сидовые Go-определения лежат в internal/catalog/seeddefs; чтобы перегенерировать SQL, см. scripts/genseed.

Локальный стек поднимается через make compose-up (см. docker-compose.yml). Сервер стартует fail-fast: если DATABASE_URL не задан или БД недоступна, процесс завершается с ошибкой и кодом 1 — без БД каталог работать не будет.

Команды разработки

make tidy         # go mod tidy
make build        # сборка
make run          # локальный запуск (dev)
make test         # go test ./...
make lint         # go vet + golangci-lint
make proto        # регенерация proto/gen/ (через Docker buf)
make docker       # собрать api-gateway image
make compose-up   # поднять dev стек
make compose-down # опустить dev стек
make clean        # rm -rf bin/

Что дальше

См. PLAN.md и ../ARCHITECTURE.md:

  • S1 (MVP): добавить Postgres, Redis, JWT-auth, лобби.
  • S2: overhead-CV на NPU Orange Pi, телеметрия в TimescaleDB.
  • S3: биллинг через ЮKassa.
  • S4: турниры.

Лицензия

TBD (предлагается Apache 2.0).