334 lines
11 KiB
Markdown
334 lines
11 KiB
Markdown
# API для разработчиков: Технические запросы
|
||
|
||
Этот файл описывает технические WebSocket-запросы, которые нужны для служебной работы клиента с сервером. Часть операций доступна без авторизации, часть требует успешной авторизованной сессии.
|
||
|
||
Сейчас здесь шесть методов:
|
||
|
||
- `Ping` — keep-alive запрос для поддержания живого WebSocket-соединения;
|
||
- `GetServerInfo` — запрос базовой публичной информации о сервере для выбора узла в децентрализованной сети;
|
||
- `GetCallIceConfig` — выдача STUN/TURN конфигурации для звонков;
|
||
- `ClientErrorLog` — отправка клиентской ошибки в серверный лог;
|
||
- `ClientDebugLog` — отправка клиентского debug-события в серверный буфер;
|
||
- `CallDeliveryReport` — диагностический отчёт клиента о доставке/установке звонка.
|
||
|
||
Логика раздела такая:
|
||
|
||
- `Ping` нужен для регулярной проверки, что соединение всё ещё живо;
|
||
- `GetServerInfo` нужен до авторизации и до работы с данными, чтобы клиент понял, что сервер доступен, и показал пользователю краткую карточку этого узла.
|
||
|
||
Ниже сначала описаны назначение методов, затем точные форматы запросов и ответов.
|
||
|
||
## 1. `Ping`
|
||
|
||
### Назначение
|
||
|
||
Служебный keep-alive запрос.
|
||
|
||
Клиент может отправлять его периодически, чтобы:
|
||
|
||
- поддерживать активное WebSocket-соединение;
|
||
- понимать, что сервер отвечает;
|
||
- при необходимости получать текущее серверное время.
|
||
|
||
### Запрос
|
||
|
||
```json
|
||
{
|
||
"op": "Ping",
|
||
"requestId": "ping-001",
|
||
"payload": {
|
||
"ts": 1774700000123
|
||
}
|
||
}
|
||
```
|
||
|
||
Поле `ts` в запросе необязательно для логики сервера. Сервер его не валидирует и не использует для принятия решения.
|
||
|
||
### Успешный ответ
|
||
|
||
```json
|
||
{
|
||
"op": "Ping",
|
||
"requestId": "ping-001",
|
||
"status": 200,
|
||
"ok": true,
|
||
"payload": {
|
||
"ts": 1774700000456
|
||
}
|
||
}
|
||
```
|
||
|
||
### Специфические коды ошибок `Ping`
|
||
|
||
- У `Ping` нет специальных прикладных ошибок.
|
||
- Если произойдёт непредвиденная проблема, сервер вернёт общую ошибку из раздела `00`, обычно `500 / INTERNAL_ERROR`.
|
||
|
||
---
|
||
|
||
## 2. `GetServerInfo`
|
||
|
||
### Назначение
|
||
|
||
Запрос публичной информации о сервере.
|
||
|
||
Он нужен клиенту для выбора сервера в децентрализованной сети. По этому запросу клиент может:
|
||
|
||
- проверить, что сервер вообще доступен;
|
||
- показать URL и версию сервера;
|
||
- показать физический регион или адрес размещения;
|
||
- показать описание сервера;
|
||
- показать поле `origin` как комментарий о природе этого узла;
|
||
- показать дополнительную текстовую информацию.
|
||
|
||
Этот запрос доступен без авторизации.
|
||
|
||
### Источник данных
|
||
|
||
- `version` берётся из Gradle build и подставляется в `application.properties`;
|
||
- остальные поля читаются из настроек сервера;
|
||
- если значение в конфиге не задано, сервер возвращает пустую строку.
|
||
|
||
### Запрос
|
||
|
||
```json
|
||
{
|
||
"op": "GetServerInfo",
|
||
"requestId": "srv-001",
|
||
"payload": {
|
||
}
|
||
}
|
||
```
|
||
|
||
### Успешный ответ
|
||
|
||
```json
|
||
{
|
||
"op": "GetServerInfo",
|
||
"requestId": "srv-001",
|
||
"status": 200,
|
||
"ok": true,
|
||
"payload": {
|
||
"url": "wss://node.example.org/ws",
|
||
"version": "1.0",
|
||
"physicalRegion": "Грузия, Тбилиси",
|
||
"description": "Public community SHiNE node",
|
||
"origin": "Community-operated node",
|
||
"extraInfo": "IPv4 + IPv6; test federation enabled"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Поля ответа
|
||
|
||
- `url` — публичный URL сервера.
|
||
- `version` — версия сервера из Gradle build.
|
||
- `physicalRegion` — физический регион или адрес размещения сервера.
|
||
- `description` — человекочитаемое описание сервера.
|
||
- `origin` — комментарий о том, какой это сервер.
|
||
- `extraInfo` — любая дополнительная информация о сервере.
|
||
|
||
### Специфические коды ошибок `GetServerInfo`
|
||
|
||
- У `GetServerInfo` нет специальных прикладных ошибок при штатной работе.
|
||
- Если произойдёт непредвиденная проблема, сервер вернёт общую ошибку из раздела `00`, обычно `500 / INTERNAL_ERROR`.
|
||
|
||
---
|
||
|
||
## 3. `GetCallIceConfig`
|
||
|
||
Доступно только после успешной авторизации.
|
||
|
||
### Запрос
|
||
|
||
```json
|
||
{
|
||
"op": "GetCallIceConfig",
|
||
"requestId": "ice-001",
|
||
"payload": {
|
||
}
|
||
}
|
||
```
|
||
|
||
### Успешный ответ
|
||
|
||
```json
|
||
{
|
||
"op": "GetCallIceConfig",
|
||
"requestId": "ice-001",
|
||
"status": 200,
|
||
"ok": true,
|
||
"payload": {
|
||
"stunUrls": ["stun:stun.example.org:3478"],
|
||
"turnUrls": ["turn:turn.example.org:3478?transport=udp"],
|
||
"turnUsername": "user",
|
||
"turnPassword": "password",
|
||
"turnServers": [
|
||
{
|
||
"id": "primary",
|
||
"urls": ["turn:turn.example.org:3478?transport=udp"],
|
||
"username": "user",
|
||
"password": "password"
|
||
}
|
||
],
|
||
"turnEnabled": true,
|
||
"generatedAtMs": 1774700000123,
|
||
"expiresAtMs": 1774700300123,
|
||
"ttlSec": 300
|
||
}
|
||
}
|
||
```
|
||
|
||
### Специфические коды ошибок `GetCallIceConfig`
|
||
|
||
- `422 / NOT_AUTHENTICATED` — требуется авторизация.
|
||
|
||
---
|
||
|
||
## 4. `ClientErrorLog`
|
||
|
||
### Запрос
|
||
|
||
```json
|
||
{
|
||
"op": "ClientErrorLog",
|
||
"requestId": "err-001",
|
||
"payload": {
|
||
"kind": "global_error",
|
||
"message": "TypeError: failed",
|
||
"stack": "...",
|
||
"sourceUrl": "https://shineup.me/app.js",
|
||
"lineNumber": 10,
|
||
"columnNumber": 20,
|
||
"route": "#/channel-view/own-0",
|
||
"href": "https://shineup.me/#/channel-view/own-0",
|
||
"userAgent": "...",
|
||
"clientTs": 1774700000123,
|
||
"requestOp": "GetChannelMessages",
|
||
"requestIdRef": "GetChannelMessages-123",
|
||
"contextJson": "{\"screen\":\"channels\"}"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Успешный ответ
|
||
|
||
```json
|
||
{
|
||
"op": "ClientErrorLog",
|
||
"requestId": "err-001",
|
||
"status": 200,
|
||
"ok": true,
|
||
"payload": {
|
||
"serverTs": 1774700000456,
|
||
"accepted": true
|
||
}
|
||
}
|
||
```
|
||
|
||
### Специфические коды ошибок `ClientErrorLog`
|
||
|
||
- `400 / BAD_FIELDS` — обязательные поля ошибки не заполнены.
|
||
|
||
---
|
||
|
||
## 5. `ClientDebugLog`
|
||
|
||
### Запрос
|
||
|
||
```json
|
||
{
|
||
"op": "ClientDebugLog",
|
||
"requestId": "dbg-001",
|
||
"payload": {
|
||
"runId": "ui-run-1",
|
||
"level": "info",
|
||
"message": "opened channels tab",
|
||
"details": "{\"route\":\"#/channels\"}"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Успешный ответ
|
||
|
||
```json
|
||
{
|
||
"op": "ClientDebugLog",
|
||
"requestId": "dbg-001",
|
||
"status": 200,
|
||
"ok": true,
|
||
"payload": {
|
||
"accepted": true,
|
||
"serverTs": 1774700000456
|
||
}
|
||
}
|
||
```
|
||
|
||
### Специфические коды ошибок `ClientDebugLog`
|
||
|
||
- `400 / BAD_FIELDS` — поле `message` не заполнено.
|
||
|
||
---
|
||
|
||
## 6. `CallDeliveryReport`
|
||
|
||
### Запрос
|
||
|
||
```json
|
||
{
|
||
"op": "CallDeliveryReport",
|
||
"requestId": "call-report-001",
|
||
"payload": {
|
||
"type": "outgoing_failed",
|
||
"value": "{\"reason\":\"ice_failed\",\"callId\":\"call-1\"}"
|
||
}
|
||
}
|
||
```
|
||
|
||
### Успешный ответ
|
||
|
||
```json
|
||
{
|
||
"op": "CallDeliveryReport",
|
||
"requestId": "call-report-001",
|
||
"status": 200,
|
||
"ok": true,
|
||
"payload": {
|
||
"serverTs": 1774700000456,
|
||
"accepted": true
|
||
}
|
||
}
|
||
```
|
||
|
||
### Специфические коды ошибок `CallDeliveryReport`
|
||
|
||
- `400 / BAD_FIELDS` — поле `type` не заполнено.
|
||
|
||
---
|
||
|
||
## 7. Короткое резюме
|
||
|
||
- `Ping` нужен для keep-alive и проверки, что WebSocket-соединение живо.
|
||
- `GetServerInfo` нужен для выбора сервера в сети и показа публичной информации об узле.
|
||
- `GetCallIceConfig` нужен для WebRTC-звонков и требует авторизации.
|
||
- `ClientErrorLog`, `ClientDebugLog`, `CallDeliveryReport` используются для диагностики клиента и звонков.
|
||
|
||
|
||
## 8. Прямое техническое сообщение в конкретную сессию
|
||
|
||
На текущий момент в публичном JSON API этого документа **нет отдельного RPC** для отправки произвольного технического сообщения в конкретную сессию пользователя (по `sessionId`).
|
||
|
||
Что уже есть в системе:
|
||
|
||
- сервер хранит `sessionId` активной сессии;
|
||
- есть `ListSessions`, чтобы клиент получил список sessionId своего пользователя;
|
||
- у сервера есть внутренний реестр активных WS-подключений по `sessionId`.
|
||
|
||
Чего не хватает для полноценной фичи «direct tech message by sessionId»:
|
||
|
||
1. отдельная API-операция (например, `SendSessionTechMessage`);
|
||
2. правило авторизации (кто имеет право писать в чужую/свою сессию);
|
||
3. унифицированный формат payload и события доставки;
|
||
4. коды ошибок (`SESSION_OFFLINE`, `SESSION_NOT_FOUND`, `FORBIDDEN` и т.п.).
|
||
|
||
Итог: как инфраструктурная база это почти готово, но нужен отдельный RPC-слой и политика доступа.
|