SHA256
Документировать API и сервис агента-кодера
This commit is contained in:
@@ -123,7 +123,17 @@
|
||||
|
||||
---
|
||||
|
||||
## 8. Короткое резюме
|
||||
## 8. Источник истины по списку операций
|
||||
|
||||
Фактический список публичных WebSocket-операций берётся из:
|
||||
|
||||
- `shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java`.
|
||||
|
||||
Если операция зарегистрирована в `HANDLERS` и `REQUEST_TYPES`, она считается доступной через JSON/WebSocket API. Общий актуальный индекс таких операций поддерживается в `Dev_Docs/API/09_Operations_Index.md`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Короткое резюме
|
||||
|
||||
- Запросы всегда идут как `op + requestId + payload`.
|
||||
- Ответы всегда идут как `op + requestId + status + ok + payload`.
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
|
||||
Этот файл описывает временный раздел API, связанный с заведением пользователя на сервере и проверкой, существует ли пользователь.
|
||||
|
||||
Сейчас здесь два метода:
|
||||
Сейчас здесь три метода:
|
||||
|
||||
- `AddUser` — временная серверная регистрация пользователя;
|
||||
- `GetUser` — временная серверная проверка существования пользователя и чтение его базовых данных.
|
||||
- `GetUser` — временная серверная проверка существования пользователя и чтение его базовых данных;
|
||||
- `SearchUsers` — dev/test поиск логинов по префиксу.
|
||||
|
||||
Их логика пока вспомогательная и dev-oriented: сервер сам хранит эти данные локально и сам отвечает на existence-check. В будущем оба сценария должны быть заменены на нормальную работу напрямую через Solana, но пока этот контракт нужен клиентам для разработки и интеграции.
|
||||
|
||||
@@ -166,8 +167,49 @@
|
||||
|
||||
---
|
||||
|
||||
## 3. Короткое резюме
|
||||
## 3. Операция `SearchUsers`
|
||||
|
||||
### Назначение
|
||||
|
||||
Поиск пользователей по префиксу логина. Операция зарегистрирована в серверном API и используется как вспомогательная dev/test операция.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SearchUsers",
|
||||
"requestId": "search-001",
|
||||
"payload": {
|
||||
"prefix": "an"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SearchUsers",
|
||||
"requestId": "search-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"logins": ["anya", "andrey"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Специфические коды ошибок `SearchUsers`
|
||||
|
||||
- `400 / BAD_FIELDS` — некорректный или пустой `prefix`.
|
||||
- `501 / DB_ERROR` — ошибка БД при поиске.
|
||||
- `500 / INTERNAL_ERROR` — непредвиденная внутренняя ошибка сервера.
|
||||
|
||||
---
|
||||
|
||||
## 4. Короткое резюме
|
||||
|
||||
- `AddUser` — временная регистрация пользователя на сервере.
|
||||
- `GetUser` — временная проверка существования пользователя на сервере.
|
||||
- `SearchUsers` — временный поиск пользователей по префиксу.
|
||||
- И регистрация, и existence-check позже должны быть переведены на Solana.
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
# API для разработчиков: Технические запросы
|
||||
|
||||
Этот файл описывает технические запросы, которые не требуют авторизации и нужны для служебной работы клиента с сервером.
|
||||
Этот файл описывает технические WebSocket-запросы, которые нужны для служебной работы клиента с сервером. Часть операций доступна без авторизации, часть требует успешной авторизованной сессии.
|
||||
|
||||
Сейчас здесь два метода:
|
||||
Сейчас здесь шесть методов:
|
||||
|
||||
- `Ping` — keep-alive запрос для поддержания живого WebSocket-соединения;
|
||||
- `GetServerInfo` — запрос базовой публичной информации о сервере для выбора узла в децентрализованной сети.
|
||||
- `GetServerInfo` — запрос базовой публичной информации о сервере для выбора узла в децентрализованной сети;
|
||||
- `GetCallIceConfig` — выдача STUN/TURN конфигурации для звонков;
|
||||
- `ClientErrorLog` — отправка клиентской ошибки в серверный лог;
|
||||
- `ClientDebugLog` — отправка клиентского debug-события в серверный буфер;
|
||||
- `CallDeliveryReport` — диагностический отчёт клиента о доставке/установке звонка.
|
||||
|
||||
Логика раздела такая:
|
||||
|
||||
@@ -130,14 +134,186 @@
|
||||
|
||||
---
|
||||
|
||||
## 3. Короткое резюме
|
||||
## 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` используются для диагностики клиента и звонков.
|
||||
|
||||
|
||||
## 4. Прямое техническое сообщение в конкретную сессию
|
||||
## 8. Прямое техническое сообщение в конкретную сессию
|
||||
|
||||
На текущий момент в публичном JSON API этого документа **нет отдельного RPC** для отправки произвольного технического сообщения в конкретную сессию пользователя (по `sessionId`).
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# 06. Channels Read API
|
||||
|
||||
## Человеко-читаемое объяснение
|
||||
Эти 3 функции — это **чтение данных каналов** для UI:
|
||||
Эти функции — это **чтение данных каналов** для UI:
|
||||
|
||||
1. `ListSubscriptionsFeed` — отдает данные для экрана списка каналов:
|
||||
- ваши каналы (личный + созданные вами),
|
||||
@@ -14,6 +14,12 @@
|
||||
3. `GetMessageThread` — отдает дерево обсуждения вокруг конкретного сообщения:
|
||||
предки, фокус-сообщение, потомки.
|
||||
|
||||
4. `GetChannelsCounters` — отдает счетчики разделов каналов для пользователя.
|
||||
|
||||
5. `ListGroupChats200` — отдает список групповых чатов типа `200`.
|
||||
|
||||
6. `GetGroupDialog` — отдает сообщения конкретного группового чата типа `200`.
|
||||
|
||||
> На первом этапе мы **не используем курсоры** (`nextCursor`) и загружаем полные списки.
|
||||
|
||||
---
|
||||
@@ -198,6 +204,126 @@
|
||||
|
||||
---
|
||||
|
||||
## 4) GetChannelsCounters
|
||||
|
||||
### Request
|
||||
```json
|
||||
{
|
||||
"op": "GetChannelsCounters",
|
||||
"requestId": "req-4",
|
||||
"payload": {
|
||||
"login": "Alice"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response (success)
|
||||
```json
|
||||
{
|
||||
"op": "GetChannelsCounters",
|
||||
"requestId": "req-4",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"feedCount": 12,
|
||||
"dialogs100Count": 3,
|
||||
"groupChats200Count": 4,
|
||||
"myChannelsCount": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5) ListGroupChats200
|
||||
|
||||
### Request
|
||||
```json
|
||||
{
|
||||
"op": "ListGroupChats200",
|
||||
"requestId": "req-5",
|
||||
"payload": {
|
||||
"login": "Alice"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response (success)
|
||||
```json
|
||||
{
|
||||
"op": "ListGroupChats200",
|
||||
"requestId": "req-5",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"chats": [
|
||||
{
|
||||
"ownerLogin": "Alice",
|
||||
"ownerBlockchainName": "alice-001",
|
||||
"channelRootBlockNumber": 123,
|
||||
"channelRootBlockHash": "...",
|
||||
"channelName": "team",
|
||||
"chatTitle": "Team chat",
|
||||
"membersCount": 3,
|
||||
"updatedAtMs": 1760000000000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6) GetGroupDialog
|
||||
|
||||
### Request
|
||||
```json
|
||||
{
|
||||
"op": "GetGroupDialog",
|
||||
"requestId": "req-6",
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"group": {
|
||||
"ownerBlockchainName": "alice-001",
|
||||
"channelRootBlockNumber": 123
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response (success)
|
||||
```json
|
||||
{
|
||||
"op": "GetGroupDialog",
|
||||
"requestId": "req-6",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"group": {
|
||||
"ownerLogin": "Alice",
|
||||
"ownerBlockchainName": "alice-001",
|
||||
"channelRootBlockNumber": 123,
|
||||
"channelName": "team",
|
||||
"chatTitle": "Team chat"
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"authorLogin": "Bob",
|
||||
"authorBlockchainName": "bob-001",
|
||||
"blockNumber": 140,
|
||||
"blockHash": "...",
|
||||
"createdAtMs": 1760000000000,
|
||||
"text": "Привет"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reason codes
|
||||
- `bad_fields`
|
||||
- `user_not_found`
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# API для разработчиков: индекс операций
|
||||
|
||||
Этот файл фиксирует полный список публичных JSON/WebSocket операций, зарегистрированных в коде сервера.
|
||||
|
||||
Источник истины на момент актуализации:
|
||||
|
||||
- `shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java`.
|
||||
|
||||
Если операция есть в `HANDLERS` и `REQUEST_TYPES`, клиент может отправлять её как `op` в общем JSON-конверте из `00_Common_API_Format.md`.
|
||||
|
||||
## Актуальные операции
|
||||
|
||||
| Операция | Раздел документации | Кратко |
|
||||
| --- | --- | --- |
|
||||
| `AddUser` | `01_User_Registration_API.md` | временная регистрация пользователя |
|
||||
| `GetUser` | `01_User_Registration_API.md` | чтение/проверка пользователя |
|
||||
| `SearchUsers` | `01_User_Registration_API.md` | поиск логинов по префиксу |
|
||||
| `AuthChallenge` | `02_Authentication_API.md` | challenge для создания новой сессии |
|
||||
| `CreateAuthSession` | `02_Authentication_API.md` | создание новой авторизованной сессии |
|
||||
| `SessionChallenge` | `02_Authentication_API.md` | challenge для входа в существующую сессию |
|
||||
| `SessionLogin` | `02_Authentication_API.md` | вход в существующую сессию |
|
||||
| `ListSessions` | `03_Session_Management_API.md` | список активных сессий |
|
||||
| `CloseActiveSession` | `03_Session_Management_API.md` | закрытие активной сессии |
|
||||
| `AddBlock` | `04_Add_Block_to_Blockchain_API.md` | добавление блока в блокчейн |
|
||||
| `Ping` | `05_Technical_Requests_API.md` | keep-alive |
|
||||
| `GetServerInfo` | `05_Technical_Requests_API.md` | публичная информация о сервере |
|
||||
| `GetCallIceConfig` | `05_Technical_Requests_API.md` | STUN/TURN конфигурация звонков |
|
||||
| `ClientErrorLog` | `05_Technical_Requests_API.md` | логирование клиентской ошибки |
|
||||
| `ClientDebugLog` | `05_Technical_Requests_API.md` | клиентский debug-лог |
|
||||
| `CallDeliveryReport` | `05_Technical_Requests_API.md` | диагностика доставки/установки звонков |
|
||||
| `ListSubscriptionsFeed` | `06_Channels_Read_API.md` | лента каналов/подписок |
|
||||
| `GetChannelMessages` | `06_Channels_Read_API.md` | сообщения канала |
|
||||
| `GetMessageThread` | `06_Channels_Read_API.md` | тред сообщения |
|
||||
| `GetChannelsCounters` | `06_Channels_Read_API.md` | счетчики разделов каналов |
|
||||
| `ListGroupChats200` | `06_Channels_Read_API.md` | список групповых чатов типа `200` |
|
||||
| `GetGroupDialog` | `06_Channels_Read_API.md` | сообщения группового чата типа `200` |
|
||||
| `UpsertUserParam` | `10_User_Params_API.md` | запись параметра пользователя |
|
||||
| `GetUserParam` | `10_User_Params_API.md` | чтение одного параметра пользователя |
|
||||
| `ListUserParams` | `10_User_Params_API.md` | список параметров пользователя |
|
||||
| `GetFriendsLists` | `11_Connections_API.md` | входящие/исходящие друзья |
|
||||
| `ListContacts` | `11_Connections_API.md` | контакты текущего пользователя |
|
||||
| `GetUserConnectionsGraph` | `11_Connections_API.md` | граф связей пользователя |
|
||||
| `AddCloseFriend` | `11_Connections_API.md` | добавить близкого друга |
|
||||
| `UpsertPushToken` | `12_Direct_Messages_Push_Calls_API.md` | регистрация WebPush-токена |
|
||||
| `SendTestWebPush` | `12_Direct_Messages_Push_Calls_API.md` | тестовая push-доставка |
|
||||
| `SendDirectMessage` | `12_Direct_Messages_Push_Calls_API.md` | отправка подписанного DM-пакета |
|
||||
| `SendMessagePair` | `12_Direct_Messages_Push_Calls_API.md` | отправка пары входящий/исходящий DM |
|
||||
| `ReceiveOutcomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | алиас `SendMessagePair` |
|
||||
| `ReceiveIncomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | прием входящего DM-блока |
|
||||
| `AckSessionDelivery` | `12_Direct_Messages_Push_Calls_API.md` | подтверждение доставки в сессию |
|
||||
| `CallInviteBroadcast` | `12_Direct_Messages_Push_Calls_API.md` | broadcast приглашения к звонку |
|
||||
| `CallSignalToSession` | `12_Direct_Messages_Push_Calls_API.md` | сигнал звонка в конкретную сессию |
|
||||
|
||||
## Важные замечания
|
||||
|
||||
- `ReceiveOutcomingMessage` сейчас зарегистрирован как алиас того же handler/request-класса, что и `SendMessagePair`.
|
||||
- Классы `Net_MarkChannelMessagesSeen_*` существуют в коде, но операция `MarkChannelMessagesSeen` не зарегистрирована в `JsonHandlerRegistry`, поэтому в публичный список API не входит.
|
||||
- HTTP debug endpoints из `src/main/java/server/debug/` не входят в этот индекс WebSocket `op`; они описаны отдельно в `13_HTTP_Debug_API.md`.
|
||||
@@ -0,0 +1,129 @@
|
||||
# API для разработчиков: параметры пользователя
|
||||
|
||||
Документ описывает операции для записи и чтения пользовательских параметров.
|
||||
|
||||
Текущие операции:
|
||||
|
||||
- `UpsertUserParam`
|
||||
- `GetUserParam`
|
||||
- `ListUserParams`
|
||||
|
||||
## 1. `UpsertUserParam`
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "UpsertUserParam",
|
||||
"requestId": "param-upsert-001",
|
||||
"payload": {
|
||||
"login": "alice",
|
||||
"param": "display_name",
|
||||
"time_ms": 1774700000123,
|
||||
"value": "Alice",
|
||||
"device_key": "BASE64_DEVICE_PUBLIC_KEY",
|
||||
"signature": "BASE64_SIGNATURE"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "UpsertUserParam",
|
||||
"requestId": "param-upsert-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Типовые ошибки
|
||||
|
||||
- `400 / BAD_FIELDS` — некорректные обязательные поля.
|
||||
- `422 / BAD_SIGNATURE` — подпись не прошла проверку.
|
||||
- `501 / DB_ERROR` — ошибка БД.
|
||||
|
||||
---
|
||||
|
||||
## 2. `GetUserParam`
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "GetUserParam",
|
||||
"requestId": "param-get-001",
|
||||
"payload": {
|
||||
"login": "alice",
|
||||
"param": "display_name"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "GetUserParam",
|
||||
"requestId": "param-get-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "alice",
|
||||
"param": "display_name",
|
||||
"time_ms": 1774700000123,
|
||||
"value": "Alice",
|
||||
"device_key": "BASE64_DEVICE_PUBLIC_KEY",
|
||||
"signature": "BASE64_SIGNATURE"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Если параметр не найден, сервер возвращает `404` с пустым `payload`; отдельный прикладной код ошибки текущий handler не задаёт.
|
||||
|
||||
---
|
||||
|
||||
## 3. `ListUserParams`
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "ListUserParams",
|
||||
"requestId": "param-list-001",
|
||||
"payload": {
|
||||
"login": "alice"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "ListUserParams",
|
||||
"requestId": "param-list-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "alice",
|
||||
"params": [
|
||||
{
|
||||
"login": "alice",
|
||||
"param": "display_name",
|
||||
"time_ms": 1774700000123,
|
||||
"value": "Alice",
|
||||
"device_key": "BASE64_DEVICE_PUBLIC_KEY",
|
||||
"signature": "BASE64_SIGNATURE"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Примечание
|
||||
|
||||
Имена JSON-полей `time_ms` и `device_key` сейчас соответствуют Java-модели ответа/запроса и должны передаваться именно в таком виде.
|
||||
@@ -0,0 +1,174 @@
|
||||
# API для разработчиков: связи пользователей
|
||||
|
||||
Документ описывает операции чтения и записи пользовательских связей.
|
||||
|
||||
Текущие операции:
|
||||
|
||||
- `GetFriendsLists`
|
||||
- `ListContacts`
|
||||
- `GetUserConnectionsGraph`
|
||||
- `AddCloseFriend`
|
||||
|
||||
## 1. `GetFriendsLists`
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "GetFriendsLists",
|
||||
"requestId": "friends-001",
|
||||
"payload": {
|
||||
"login": "alice"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "GetFriendsLists",
|
||||
"requestId": "friends-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"out_friends": ["Bob"],
|
||||
"in_friends": ["Kate"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. `ListContacts`
|
||||
|
||||
`ListContacts` использует текущую авторизованную сессию. В payload нет дополнительных полей.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "ListContacts",
|
||||
"requestId": "contacts-001",
|
||||
"payload": {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "ListContacts",
|
||||
"requestId": "contacts-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"contacts": ["Bob", "Kate"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. `GetUserConnectionsGraph`
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "GetUserConnectionsGraph",
|
||||
"requestId": "graph-001",
|
||||
"payload": {
|
||||
"login": "alice"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "GetUserConnectionsGraph",
|
||||
"requestId": "graph-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"outFriends": ["Bob"],
|
||||
"inFriends": ["Kate"],
|
||||
"outContacts": [],
|
||||
"inContacts": [],
|
||||
"outFollows": [],
|
||||
"inFollows": [],
|
||||
"outSpouses": [],
|
||||
"inSpouses": [],
|
||||
"outParents": [],
|
||||
"inParents": [],
|
||||
"outChildren": [],
|
||||
"inChildren": [],
|
||||
"outSiblings": [],
|
||||
"inSiblings": [],
|
||||
"outKnownPersons": [],
|
||||
"inKnownPersons": [],
|
||||
"outShineConfirmed": [],
|
||||
"inShineConfirmed": [],
|
||||
"outShineSeen": [],
|
||||
"inShineSeen": [],
|
||||
"parents": [],
|
||||
"children": [],
|
||||
"siblings": [],
|
||||
"spouses": [],
|
||||
"allUsers": [
|
||||
{
|
||||
"login": "Bob",
|
||||
"official": false,
|
||||
"shine": true,
|
||||
"officialLabel": "",
|
||||
"shineLabel": "shine",
|
||||
"avatar": { "ar": "..." }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Примечание
|
||||
|
||||
Поля `known_person`, `shine_confirmed`, `shine_seen` в UI считаются недопроверенной зоной проекта; при изменениях этой логики нужна ручная end-to-end проверка.
|
||||
|
||||
---
|
||||
|
||||
## 4. `AddCloseFriend`
|
||||
|
||||
`AddCloseFriend` использует текущую авторизованную сессию как источник `login`.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "AddCloseFriend",
|
||||
"requestId": "close-friend-001",
|
||||
"payload": {
|
||||
"toLogin": "bob"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "AddCloseFriend",
|
||||
"requestId": "close-friend-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"login": "Alice",
|
||||
"toLogin": "Bob",
|
||||
"relation": "close_friend"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,306 @@
|
||||
# API для разработчиков: DM, push и сигналы звонков
|
||||
|
||||
Документ описывает WebSocket-операции для подписанных личных сообщений, WebPush и realtime-сигналов звонков.
|
||||
|
||||
Логика личных сообщений дополнительно описана в `Dev_Docs/Personal_Messages/README.md`; этот файл фиксирует именно публичные `op`, поля запросов и поля ответов.
|
||||
|
||||
## 1. `UpsertPushToken`
|
||||
|
||||
Требует авторизации.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "UpsertPushToken",
|
||||
"requestId": "push-upsert-001",
|
||||
"payload": {
|
||||
"sessionId": "SESSION_ID",
|
||||
"endpoint": "https://push.example/...",
|
||||
"p256dhKey": "BASE64",
|
||||
"authKey": "BASE64",
|
||||
"platform": "web",
|
||||
"userAgent": "Mozilla/5.0 ..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "UpsertPushToken",
|
||||
"requestId": "push-upsert-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"tokenId": "token-1",
|
||||
"updatedAtMs": 1774700000123
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. `SendTestWebPush`
|
||||
|
||||
Требует авторизации. Если `login` передан, он должен совпадать с логином текущей сессии.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SendTestWebPush",
|
||||
"requestId": "push-test-001",
|
||||
"payload": {
|
||||
"login": "alice",
|
||||
"sessionId": "SESSION_ID",
|
||||
"title": "Test",
|
||||
"text": "Push body"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SendTestWebPush",
|
||||
"requestId": "push-test-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"targetLogin": "alice",
|
||||
"attemptedSessions": 1,
|
||||
"sessionsWithPushConfig": 1,
|
||||
"delivered": 1,
|
||||
"failed": 0,
|
||||
"sentAtMs": 1774700000123
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. `SendDirectMessage`
|
||||
|
||||
Отправляет один подписанный DM-пакет.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SendDirectMessage",
|
||||
"requestId": "dm-001",
|
||||
"payload": {
|
||||
"blobB64": "BASE64_SIGNED_DM_PACKET"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SendDirectMessage",
|
||||
"requestId": "dm-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"messageId": "dm-1",
|
||||
"deliveredWsSessions": 1,
|
||||
"deliveredWebPushSessions": 0,
|
||||
"sessionNotFound": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. `SendMessagePair` и `ReceiveOutcomingMessage`
|
||||
|
||||
`ReceiveOutcomingMessage` сейчас является алиасом `SendMessagePair` и использует тот же request/handler.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SendMessagePair",
|
||||
"requestId": "dm-pair-001",
|
||||
"payload": {
|
||||
"incomingBlobB64": "BASE64_INCOMING_SIGNED_BLOCK",
|
||||
"outgoingBlobB64": "BASE64_OUTGOING_SIGNED_BLOCK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "SendMessagePair",
|
||||
"requestId": "dm-pair-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"baseKey": "base-key",
|
||||
"incomingKey": "incoming-key",
|
||||
"outgoingKey": "outgoing-key",
|
||||
"deliveredWsSessions": 1,
|
||||
"deliveredWebPushSessions": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. `ReceiveIncomingMessage`
|
||||
|
||||
Принимает входящий подписанный DM-блок.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "ReceiveIncomingMessage",
|
||||
"requestId": "dm-in-001",
|
||||
"payload": {
|
||||
"incomingBlobB64": "BASE64_INCOMING_SIGNED_BLOCK"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "ReceiveIncomingMessage",
|
||||
"requestId": "dm-in-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"messageKey": "incoming-key",
|
||||
"baseKey": "base-key",
|
||||
"deliveredWsSessions": 1,
|
||||
"deliveredWebPushSessions": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. `AckSessionDelivery`
|
||||
|
||||
Требует авторизации. Подтверждает доставку сообщения в текущую сессию.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "AckSessionDelivery",
|
||||
"requestId": "ack-001",
|
||||
"payload": {
|
||||
"messageKey": "incoming-key"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "AckSessionDelivery",
|
||||
"requestId": "ack-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"messageKey": "incoming-key"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. `CallInviteBroadcast`
|
||||
|
||||
Требует авторизации. Отправляет приглашение к звонку на активные сессии пользователя `toLogin`.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "CallInviteBroadcast",
|
||||
"requestId": "call-invite-001",
|
||||
"payload": {
|
||||
"toLogin": "bob",
|
||||
"callId": "call-1",
|
||||
"type": 100
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "CallInviteBroadcast",
|
||||
"requestId": "call-invite-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"callId": "call-1",
|
||||
"deliveredWsSessions": 1,
|
||||
"deliveredFcmSessions": 0,
|
||||
"deliveredWebPushSessions": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. `CallSignalToSession`
|
||||
|
||||
Требует авторизации. Отправляет сигнал звонка в конкретную сессию получателя.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "CallSignalToSession",
|
||||
"requestId": "call-signal-001",
|
||||
"payload": {
|
||||
"toLogin": "bob",
|
||||
"targetSessionId": "SESSION_ID",
|
||||
"callId": "call-1",
|
||||
"type": 101,
|
||||
"data": "{\"sdp\":\"...\"}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "CallSignalToSession",
|
||||
"requestId": "call-signal-001",
|
||||
"status": 200,
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"delivered": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Если целевая сессия не найдена или доставка не удалась, сервер может вернуть `404`.
|
||||
|
||||
## Типовые ошибки
|
||||
|
||||
- `422 / NOT_AUTHENTICATED` — требуется авторизация.
|
||||
- `400 / BAD_FIELDS` — не заполнены обязательные поля.
|
||||
- `404 / USER_NOT_FOUND` — пользователь не найден.
|
||||
- `404 / SESSION_NOT_FOUND` — сессия не найдена.
|
||||
- `422 / BAD_SIGNATURE` — подпись DM не прошла проверку.
|
||||
- `422 / BAD_DEVICE_KEY` — некорректный device key отправителя.
|
||||
- `422 / BAD_TIME_WINDOW` — время подписанного сообщения вне допустимого окна.
|
||||
- `422 / REPLAY` — повторное сообщение заблокировано.
|
||||
@@ -0,0 +1,190 @@
|
||||
# API для разработчиков: HTTP debug endpoints
|
||||
|
||||
Этот файл описывает отдельный HTTP debug API сервера. Он не использует WebSocket-конверт `op/requestId/payload` и включается только настройкой:
|
||||
|
||||
- `debug.tempApi.enabled=true`
|
||||
|
||||
Источник истины:
|
||||
|
||||
- `src/main/java/server/debug/DebugApiConfigurator.java`
|
||||
- `src/main/java/server/debug/*Servlet.java`
|
||||
|
||||
Если `.debug-token` отсутствует или пуст, endpoints возвращают `503 / DEBUG_DISABLED`.
|
||||
|
||||
## Авторизация
|
||||
|
||||
Для большинства debug endpoints используется Bearer token из `.debug-token`:
|
||||
|
||||
```http
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
Для `POST /debug/ws/ui-reload-all` поддерживается заголовок:
|
||||
|
||||
```http
|
||||
X-Debug-Token: <token>
|
||||
```
|
||||
|
||||
При неверном токене сервер возвращает `401 / UNAUTHORIZED`.
|
||||
|
||||
## Формат успешного HTTP-ответа
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"payload": {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Формат HTTP-ошибки
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": false,
|
||||
"code": "BAD_JSON",
|
||||
"message": "Тело запроса должно быть JSON"
|
||||
}
|
||||
```
|
||||
|
||||
## 1. `GET /debug/ws/clients`
|
||||
|
||||
Возвращает список активных WebSocket-клиентов.
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"count": 1,
|
||||
"clients": [
|
||||
{
|
||||
"sessionId": "SESSION_ID",
|
||||
"login": "alice",
|
||||
"authStatus": 2,
|
||||
"wsOpen": true,
|
||||
"remoteAddress": "127.0.0.1",
|
||||
"ip": "127.0.0.1",
|
||||
"userAgent": "Mozilla/5.0 ...",
|
||||
"clientInfoFromClient": "...",
|
||||
"clientInfoFromRequest": "...",
|
||||
"userLanguage": "ru",
|
||||
"sessionCreatedAtMs": 1774700000123
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. `POST /debug/ws/connect`
|
||||
|
||||
Запускает debug-сценарий соединения двух активных WS-сессий и отправляет им события:
|
||||
|
||||
- `DebugConnectPrepareResponder`
|
||||
- `DebugConnectStartInitiator`
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"initiatorSessionId": "SESSION_ID_1",
|
||||
"responderSessionId": "SESSION_ID_2",
|
||||
"clearDebugLog": true
|
||||
}
|
||||
```
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"runId": "dbg-...",
|
||||
"callId": "debug-call-...",
|
||||
"accepted": true,
|
||||
"initiatorSessionId": "SESSION_ID_1",
|
||||
"responderSessionId": "SESSION_ID_2",
|
||||
"initiatorLogin": "alice",
|
||||
"responderLogin": "bob",
|
||||
"mode": "cross-login"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Ошибки
|
||||
|
||||
- `400 / BAD_JSON` — тело запроса не JSON.
|
||||
- `400 / BAD_FIELDS` — не заполнены sessionId или переданы одинаковые sessionId.
|
||||
- `404 / INITIATOR_NOT_FOUND` — сессия инициатора не найдена или неактивна.
|
||||
- `404 / RESPONDER_NOT_FOUND` — сессия получателя не найдена или неактивна.
|
||||
|
||||
## 3. `GET /debug/ws/logs`
|
||||
|
||||
Возвращает tail debug-логов из `DebugRunLogBuffer`.
|
||||
|
||||
### Query-параметры
|
||||
|
||||
- `limit` — количество записей.
|
||||
- `runId` — фильтр по runId.
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"count": 1,
|
||||
"limit": 100,
|
||||
"runIdFilter": "ui-run-1",
|
||||
"logs": [
|
||||
{
|
||||
"ts": 1774700000123,
|
||||
"level": "info",
|
||||
"runId": "ui-run-1",
|
||||
"source": "debug-connect",
|
||||
"sessionId": "SESSION_ID",
|
||||
"login": "alice",
|
||||
"message": "opened channels tab",
|
||||
"details": "{}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. `POST /debug/ws/ui-reload-all`
|
||||
|
||||
Рассылает активным UI-сессиям debug-событие на reload.
|
||||
|
||||
### Запрос
|
||||
|
||||
```json
|
||||
{
|
||||
"reason": "manual_debug_api",
|
||||
"reloadAfterMs": 700
|
||||
}
|
||||
```
|
||||
|
||||
Если `reason` не передан или пустой, сервер использует `manual_debug_api`. `reloadAfterMs` ограничивается диапазоном `100..15000`.
|
||||
|
||||
### Успешный ответ
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": true,
|
||||
"payload": {
|
||||
"accepted": true,
|
||||
"reason": "manual_debug_api",
|
||||
"reloadAfterMs": 700,
|
||||
"issuedAtMs": 1774700000123,
|
||||
"totalConnections": 2,
|
||||
"sentCount": 2,
|
||||
"skippedCount": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Ошибки
|
||||
|
||||
- `400 / BAD_JSON` — тело запроса не JSON.
|
||||
@@ -0,0 +1,18 @@
|
||||
# SHiNE-agent-bot-coder: очередь, voice, codex, systemd
|
||||
|
||||
- краткое описание фичи:
|
||||
Добавлен новый сервис `SHiNE-agent-bot-coder` (Java), который обрабатывает сообщения от `@AidarKC`, ведёт JSONL-историю, использует файловую очередь, распознаёт voice через OpenAI, вызывает Codex CLI и поддерживает запуск как `systemd`-сервис.
|
||||
|
||||
- что именно проверять:
|
||||
1. Бот принимает текст от `@AidarKC`, ставит задачу в очередь и отправляет ответ от Codex.
|
||||
2. Бот принимает voice, отправляет текст распознавания и затем ответ от Codex.
|
||||
3. Одновременные сообщения обрабатываются строго по одному (без параллельных запусков Codex).
|
||||
4. После рестарта сервиса незавершённая активная задача повторно уходит в обработку.
|
||||
5. Команда `/new` архивирует текущую историю и создаёт новую.
|
||||
6. `systemd`-сервис стартует и автоматически перезапускается.
|
||||
|
||||
- ожидаемый результат:
|
||||
Все пункты выше отрабатывают без потери сообщений, с корректным обновлением `data/queue.jsonl`, `data/state.json` и `data/history/*.jsonl`.
|
||||
|
||||
- статус:
|
||||
`pending`
|
||||
@@ -0,0 +1,22 @@
|
||||
# Агент-бот coder: устранение дублей и зависаний
|
||||
|
||||
- краткое описание фичи:
|
||||
- добавлен lock-файл `data/app.lock`, чтобы гарантировать единственный инстанс бота;
|
||||
- доработано завершение worker/codex при stop/restart, чтобы не было ложных retry после штатной остановки;
|
||||
- синхронизирован systemd-профиль под `--user` для `ai`;
|
||||
- улучшена отправка промежуточных статусов по событиям `codex --json`.
|
||||
|
||||
- что проверять:
|
||||
- при запущенном сервисе повторный запуск jar вручную завершается сразу с сообщением про занятый lock;
|
||||
- команда `/status` отвечает один раз (без дублей);
|
||||
- тестовая текстовая задача от `@AidarKC` обрабатывается и возвращает ответ;
|
||||
- при `/stop` активная задача завершается без последующего спама retry-ошибками;
|
||||
- в логах нет `409 Conflict` из-за второго poller после чистого перезапуска.
|
||||
|
||||
- ожидаемый результат:
|
||||
- одновременно работает только один процесс бота;
|
||||
- бот не дублирует ответы;
|
||||
- очередь не застревает на interrupted после штатного stop/restart.
|
||||
|
||||
- статус:
|
||||
- pending
|
||||
@@ -0,0 +1,21 @@
|
||||
# Python-обвязка Telegram → Codex (упрощённый сервис)
|
||||
|
||||
- краткое описание фичи:
|
||||
- добавлен новый упрощённый сервис `SHiNE-agent-bot-coder/py_bot_service.py`;
|
||||
- сервис работает через long-polling Telegram, принимает только текст, ведёт историю в `JSONL`;
|
||||
- добавлены команды `/status`, `/queue`, `/stop`, `/cancel`, `/new`, `/help`;
|
||||
- systemd unit переключён на запуск Python-сервиса.
|
||||
|
||||
- что проверять:
|
||||
- `systemctl --user status shine-agent-bot-coder` показывает `active (running)`;
|
||||
- бот отвечает на `/status` одним сообщением без дублей;
|
||||
- тестовый текстовый запрос получает финальный ответ от Codex;
|
||||
- `/stop` корректно останавливает текущую задачу;
|
||||
- `/new` переносит текущую историю в `data/history/archive`.
|
||||
|
||||
- ожидаемый результат:
|
||||
- стабильная обработка текстовых задач без зависаний и двойной обработки;
|
||||
- только один инстанс сервиса (через lock `data/py_app.lock`).
|
||||
|
||||
- статус:
|
||||
- pending
|
||||
@@ -0,0 +1,36 @@
|
||||
# Локальный деплой SHiNE-agent-bot-coder (systemd, пользователь ai)
|
||||
|
||||
## Где находится сервис
|
||||
- Папка сервиса: `SHiNE-agent-bot-coder/`
|
||||
- Systemd unit: `SHiNE-agent-bot-coder/scripts/systemd/shine-agent-bot-coder.service`
|
||||
- Скрипт установки: `SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh`
|
||||
|
||||
## Предусловия
|
||||
1. Заполнен `.env` на основе `.env.example`.
|
||||
2. Доступен рабочий Codex CLI:
|
||||
- `/home/ai/.cache/JetBrains/IntelliJIdea2026.1/aia/codex/bin/codex-x86_64-unknown-linux-musl`
|
||||
3. На машине установлен `systemd --user`.
|
||||
|
||||
## Установка
|
||||
Из корня репозитория:
|
||||
|
||||
```bash
|
||||
bash SHiNE-agent-bot-coder/scripts/systemd/install-local-systemd.sh
|
||||
```
|
||||
|
||||
Скрипт:
|
||||
1. проверяет наличие `python3`;
|
||||
2. копирует unit в `~/.config/systemd/user/`;
|
||||
3. делает `systemctl --user daemon-reload`;
|
||||
4. включает автозапуск и стартует сервис.
|
||||
|
||||
## Проверка
|
||||
```bash
|
||||
systemctl --user status shine-agent-bot-coder --no-pager
|
||||
journalctl --user -u shine-agent-bot-coder -f
|
||||
```
|
||||
|
||||
## Перезапуск после изменений
|
||||
```bash
|
||||
systemctl --user restart shine-agent-bot-coder
|
||||
```
|
||||
Reference in New Issue
Block a user