implement alternative match-making approach with Lua scripts in Redis
This commit is contained in:
+38
-28
@@ -207,31 +207,37 @@ curl -X DELETE http://localhost:3000/api/logout \
|
||||
|
||||
---
|
||||
|
||||
### Поиск случайного соперника (Матчмейкинг)
|
||||
### Поиск соперника (Матчмейкинг)
|
||||
|
||||
Начинает поиск соперника. Работает в режиме **long-polling**: запрос зависает до 30 секунд, ожидая второго игрока.
|
||||
Поиск соперника происходит через **WebSocket** (`Action Cable`), а не через long-polling: HTTP-поток не блокируется, а результат доставляется сервером push-уведомлением, как только найден соперник.
|
||||
|
||||
**URL:** `POST /api/matchmaking`
|
||||
**URL подключения:** `ws://localhost:3000/cable?token=<JWT>`
|
||||
|
||||
**Auth:** требуется
|
||||
**Auth:** токен передаётся параметром `token` в query string (тот же JWT, что и для HTTP API).
|
||||
|
||||
**Параметры:** нет
|
||||
**Канал:** `MatchmakingChannel`
|
||||
|
||||
**Пример запроса:**
|
||||
#### Поток взаимодействия
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/api/matchmaking \
|
||||
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
|
||||
--max-time 35
|
||||
1. Подключиться к `/cable?token=...` и подписаться на канал `MatchmakingChannel`.
|
||||
2. Отправить команду начала поиска:
|
||||
|
||||
```json
|
||||
{ "action": "start", "rating": 1000 }
|
||||
```
|
||||
|
||||
**Успешный ответ (200 OK)** — когда найден соперник:
|
||||
Поле `rating` опционально (по умолчанию — `MATCHMAKING_DEFAULT_RATING`). Игроки подбираются по близости рейтинга; допуск расширяется с ростом времени ожидания.
|
||||
|
||||
3. Дождаться одного из сообщений:
|
||||
|
||||
**Матч найден:**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "matched",
|
||||
"match_id": "145575d6-3a4b-4c5d-9e6f-7a8b9c0d1e2f",
|
||||
"game_token": "eyJhbGciOiJIUzI1NiJ9.eyJtYXRjaF9pZCI6IjE...",
|
||||
"game_server": "ws://game-server.example.com:8080",
|
||||
"game_server": "ws://localhost:8080",
|
||||
"players": [1, 2]
|
||||
}
|
||||
```
|
||||
@@ -243,23 +249,19 @@ curl -X POST http://localhost:3000/api/matchmaking \
|
||||
| `game_server` | WebSocket-адрес игрового сервера |
|
||||
| `players` | ID обоих игроков `[player1_id, player2_id]` |
|
||||
|
||||
**Таймаут (408 Request Timeout)** — если соперник не найден за 30 секунд:
|
||||
**Таймаут поиска** (соперник не найден за `MATCHMAKING_QUEUE_TTL` секунд):
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "No opponent found. Try again."
|
||||
}
|
||||
{ "type": "timeout" }
|
||||
```
|
||||
|
||||
**Ошибка (401 Unauthorized):**
|
||||
4. Поиск отменяется автоматически при закрытии WebSocket-подписки. Также можно явно отправить:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Unauthorized"
|
||||
}
|
||||
{ "action": "stop" }
|
||||
```
|
||||
|
||||
**Примечание:** `game_token` содержит `match_id`, `player1_id`, `player2_id`, `game_server` и действителен **1 час**.
|
||||
**Примечание:** `game_token` содержит `match_id`, `player1_id`, `player2_id`, `game_server` и действителен `MATCHMAKING_TOKEN_TTL` секунд.
|
||||
|
||||
---
|
||||
|
||||
@@ -311,7 +313,6 @@ curl -X DELETE http://localhost:3000/api/matchmaking \
|
||||
| `200` | Успешный запрос |
|
||||
| `201` | Ресурс создан (регистрация) |
|
||||
| `401` | Неавторизован (отсутствует/невалиден токен) |
|
||||
| `408` | Таймаут матчмейкинга (соперник не найден) |
|
||||
| `422` | Ошибка валидации |
|
||||
| `500` | Внутренняя ошибка сервера |
|
||||
|
||||
@@ -321,8 +322,17 @@ curl -X DELETE http://localhost:3000/api/matchmaking \
|
||||
|
||||
| Переменная | По умолчанию | Описание |
|
||||
|------------|--------------|----------|
|
||||
| `REDIS_URL` | `redis://localhost:6379/0` | Подключение к Redis |
|
||||
| `GAME_SERVER_URL` | `ws://game-server.example.com:8080` | Адрес игрового сервера для матчмейкинга |
|
||||
| `REDIS_URL` | `redis://localhost:6380/0` | Подключение к Redis (матчмейкинг и pub/sub Action Cable) |
|
||||
| `GAME_SERVER_URL` | `ws://localhost:8080` | Адрес игрового сервера для матчмейкинга |
|
||||
| `MATCHMAKING_DEFAULT_RATING` | `1000` | Рейтинг по умолчанию для новых игроков |
|
||||
| `MATCHMAKING_QUEUE_TTL` | `60` | Время ожидания соперника до таймаута, сек |
|
||||
| `MATCHMAKING_PENDING_TTL` | `15` | Время ожидания финализации пары, сек |
|
||||
| `MATCHMAKING_MATCH_TTL` | `120` | Время жизни данных матча, сек |
|
||||
| `MATCHMAKING_TOKEN_TTL` | `120` | Время жизни `game_token`, сек |
|
||||
| `MATCHMAKING_BASE_RANGE` | `100` | Начальный допуск по рейтингу |
|
||||
| `MATCHMAKING_RANGE_PER_SECOND` | `50` | Рост допуска за секунду ожидания |
|
||||
| `MATCHMAKING_MAX_RANGE` | `1000` | Максимальный допуск по рейтингу |
|
||||
| `MATCHMAKING_SWEEP_INTERVAL` | `2` | Периодичность фоновой сверки очереди, сек |
|
||||
| `CORS_ORIGINS` | `*` | Разрешённые origins для CORS (через запятую) |
|
||||
| `SECRET_KEY_BASE` | из `credentials.yml.enc` | Секретный ключ для JWT |
|
||||
|
||||
@@ -341,8 +351,8 @@ TOKEN=$(curl -s -X POST http://localhost:3000/api/register \
|
||||
curl -s http://localhost:3000/api/me \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# 3. Поиск матча (long-polling)
|
||||
curl -s -X POST http://localhost:3000/api/matchmaking \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
--max-time 35 | jq .
|
||||
# 3. Поиск матча — WebSocket (например, через wscat):
|
||||
# wscat -c "ws://localhost:3000/cable?token=$TOKEN"
|
||||
# > {"command":"subscribe","identifier":"{\"channel\":\"MatchmakingChannel\"}"}
|
||||
# > {"command":"message","identifier":"{\"channel\":\"MatchmakingChannel\"}","data":"{\"action\":\"start\",\"rating\":1000}"}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user