mirror of
https://github.com/IS1DI/x0gp.git
synced 2026-07-16 20:47:55 +00:00
This commit captures the full server code accumulated across
several development sessions. It includes the following layers,
applied in roughly this order during development:
1. Base infrastructure
- cmd/poc-server HTTP+WebSocket server, /health, /stats
- internal/transport wire types (Envelope + all message types)
- internal/catalog, internal/realtime, internal/stats
- internal/storage/postgres with migrations 001-004
- .env, .env.example, docker-compose, Dockerfile, scripts/
2. Swagger documentation
- go get github.com/swaggo/http-swagger
- swag init produces docs/docs.go
- /swagger/index.html UI, /swagger/doc.json spec
- annotations on health/stats/ws and catalog handlers
3. Races API
- internal/races/{store,service,keyset,types}.go
- migration 005_races.sql: finished_races, race_plans, race_queue
- GET /api/races with keyset pagination, status filter
- GET /api/races/upcoming
- POST /api/races/queue/join, GET, DELETE
- POST/GET /api/races/plans, DELETE /{id}
- lobby.RaceMeta simplification (no host_id/host_name)
4. Races seeder
- internal/races/seed with deterministic generator
- --seed-races / --reset CLI flags in main.go
- 30 finished + 5 live + 5 plans + 4 queue entries
5. Drivers and clans
- internal/drivers, internal/clans (CRUD, validation)
- migration 008_drivers_clans.sql
- /api/clans and /api/drivers endpoints
- 3-letter uppercase nickname/tag validation
- lobby.DriverMeta: Nickname, AvatarURL, ClanID, ClanTag
6. Podium
- internal/transport.RacePodiumEntry
- lobby.SetDriverProfile for in-memory metadata sync
- migration 007_podium.sql (podium JSONB column)
- seeder populates top-3 per finished race
7. Live races persistence
- migration 009_live_persistence.sql: live_races,
live_race_drivers, lobby_drivers
- internal/races/live_store.go: LiveStore with write-side
mirror for lobby.Service mutations
- Service.collectLive and Upcoming read from Postgres
- main.go RestoreFromDB rehydrates lobby on startup
8. Unify live + finished into one races table
- migration 010_unify_races.sql: rename finished_races to
races, expand status CHECK, merge live rows
- PgStore now hosts both write paths; LiveStore is a
thin facade implementing lobby.Persistence
- seeder resetAll drops only finished/cancelled rows and
race_plans / race_queue / lobby_drivers
Each layer is consistent on its own; cross-layer changes are
visible in the file history. A future refactor may split this
commit into the per-stage boundaries listed above.
106 lines
3.5 KiB
HTML
106 lines
3.5 KiB
HTML
<!doctype html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
<title>x0gp · PoC client</title>
|
|
<link rel="stylesheet" href="style.css" />
|
|
</head>
|
|
<body>
|
|
<header class="topbar">
|
|
<div class="brand">
|
|
<span class="logo">x0gp</span>
|
|
<span class="tag">PoC client</span>
|
|
</div>
|
|
<div class="conn" id="connState">disconnected</div>
|
|
<div class="hud-top" id="hudTop">
|
|
<span>tick: <b id="tickHz">--</b> Hz</span>
|
|
<span>rtt: <b id="rtt">--</b> ms</span>
|
|
<span>seq: <b id="seq">0</b></span>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="layout">
|
|
<!-- Левая колонка: трасса -->
|
|
<section class="track-wrap">
|
|
<canvas id="track" width="640" height="420"></canvas>
|
|
<div class="legend">
|
|
<span><i class="dot me"></i> вы</span>
|
|
<span><i class="dot other"></i> другие</span>
|
|
<span><i class="dot ghost"></i> correction (если будет)</span>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Правая колонка: управление и телеметрия -->
|
|
<aside class="controls">
|
|
<div class="card">
|
|
<h3>Подключение</h3>
|
|
<label>WS URL
|
|
<input id="wsUrl" type="text" value="ws://localhost:8080/ws" />
|
|
</label>
|
|
<label>Ник / driver_id
|
|
<input id="driverId" type="text" placeholder="driver-1" value="driver-1" />
|
|
</label>
|
|
<label>Race ID
|
|
<input id="raceId" type="text" value="demo-race" />
|
|
</label>
|
|
<div class="btn-row">
|
|
<button id="btnConnect" class="btn primary">Connect</button>
|
|
<button id="btnDisconnect" class="btn" disabled>Disconnect</button>
|
|
</div>
|
|
<div class="btn-row">
|
|
<button id="btnJoin" class="btn" disabled>Join race</button>
|
|
<button id="btnLeave" class="btn" disabled>Leave race</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>Управление</h3>
|
|
<p class="hint">
|
|
W/S — газ/тормоз, A/D — руль, Space — ручник, R — сброс позиции (debug)
|
|
</p>
|
|
<div class="pedals">
|
|
<div class="bar">
|
|
<span>throttle</span>
|
|
<div class="bar-track"><div id="barThrottle" class="bar-fill green"></div></div>
|
|
<b id="lblThrottle">0.00</b>
|
|
</div>
|
|
<div class="bar">
|
|
<span>brake</span>
|
|
<div class="bar-track"><div id="barBrake" class="bar-fill red"></div></div>
|
|
<b id="lblBrake">0.00</b>
|
|
</div>
|
|
<div class="bar">
|
|
<span>steer</span>
|
|
<div class="bar-track"><div id="barSteer" class="bar-fill blue"></div></div>
|
|
<b id="lblSteer">0.00</b>
|
|
</div>
|
|
</div>
|
|
<div class="wheel">
|
|
<div class="wheel-disc" id="wheelDisc"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<h3>Телеметрия</h3>
|
|
<dl class="tel">
|
|
<dt>speed</dt><dd id="tSpeed">0.00 m/s</dd>
|
|
<dt>heading</dt><dd id="tHeading">0.0°</dd>
|
|
<dt>lap</dt><dd id="tLap">0</dd>
|
|
<dt>sector</dt><dd id="tSector">-</dd>
|
|
<dt>pos</dt><dd id="tPos">(0.00, 0.00)</dd>
|
|
<dt>server_time</dt><dd id="tTsm">--</dd>
|
|
<dt>cars in race</dt><dd id="tCars">0</dd>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="card log-card">
|
|
<h3>Лог</h3>
|
|
<pre id="log" class="log"></pre>
|
|
</div>
|
|
</aside>
|
|
</main>
|
|
|
|
<script src="main.js"></script>
|
|
</body>
|
|
</html> |