# API для разработчиков: Технические запросы Этот файл описывает технические WebSocket-запросы, которые нужны для служебной работы клиента с сервером. Часть операций доступна без авторизации, часть требует успешной авторизованной сессии. Сейчас здесь семь методов: - `Ping` — keep-alive запрос для поддержания живого WebSocket-соединения; - `GetServerInfo` — запрос базовой публичной информации о сервере для выбора узла в децентрализованной сети; - `ListBlockchainHeads` — краткая сводка по всем локальным блокчейнам сервера для межсерверной синхронизации; - `GetCallIceConfig` — выдача STUN/TURN конфигурации для звонков; - `ClientErrorLog` — отправка клиентской ошибки в серверный лог; - `ClientDebugLog` — отправка клиентского debug-события в серверный буфер; - `CallDeliveryReport` — диагностический отчёт клиента о доставке/установке звонка. Логика раздела такая: - `Ping` нужен для регулярной проверки, что соединение всё ещё живо; - `GetServerInfo` нужен до авторизации и до работы с данными, чтобы клиент понял, что сервер доступен, и показал пользователю краткую карточку этого узла. - `ListBlockchainHeads` нужен для сервер-сервер сверки: партнёр получает список heads по всем цепочкам, сравнивает его со своим состоянием и затем добирает недостающие блоки по диапазону. Ниже сначала описаны назначение методов, затем точные форматы запросов и ответов. ## 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. `ListBlockchainHeads` ### Назначение Запрос краткой сводки по всем локальным блокчейнам сервера. Нужен для межсерверной синхронизации. Партнёр может: - получить список всех блокчейнов; - сравнить `lastBlockNumber` и `lastBlockHash` со своими значениями; - понять, какие цепочки нужно догонять; - затем отдельно запросить недостающие блоки по диапазону. Этот запрос доступен без авторизации. ### Запрос ```json { "op": "ListBlockchainHeads", "requestId": "heads-001", "payload": {} } ``` ### Успешный ответ ```json { "op": "ListBlockchainHeads", "requestId": "heads-001", "status": 200, "ok": true, "payload": { "blockchains": [ { "blockchainName": "alice_main", "lastBlockNumber": 124, "lastBlockHash": "aabbccdd00112233445566778899aabbccddeeff00112233445566778899aabb", "fileSizeBytes": 58720 } ] } } ``` ### Поля ответа - `blockchains` — массив текущих heads всех цепочек сервера. - `blockchainName` — имя блокчейна. - `lastBlockNumber` — последний номер блока в этой цепочке. - `lastBlockHash` — последний хэш блока в HEX-формате `64` символа. - `fileSizeBytes` — текущий размер файла блокчейна в байтах. ### Специфические коды ошибок `ListBlockchainHeads` - У `ListBlockchainHeads` нет специальных прикладных ошибок при штатной работе. - Если произойдёт непредвиденная проблема, сервер вернёт общую ошибку из раздела `00`, обычно `500 / INTERNAL_ERROR`. --- ## 4. `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` — требуется авторизация. --- ## 5. `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` — обязательные поля ошибки не заполнены. --- ## 6. `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` не заполнено. --- ## 7. `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-слой и политика доступа.