Добавить догоняющую синхронизацию DM между access-серверами

This commit is contained in:
AidarKC
2026-07-29 13:59:40 +04:00
parent ca8b6a33ba
commit 143adcbbe4
21 changed files with 1025 additions and 13 deletions
+73 -7
View File
@@ -10,7 +10,8 @@
Важно:
- legacy-операция `SendDirectMessage` отключена и не зарегистрирована в публичном API;
- для DM v1 нужно использовать только `SendMessagePair`, `ReceiveOutcomingMessage`, `ReceiveIncomingMessage`, `DeleteMessage`, `DeleteConversation`.
- для DM v1 нужно использовать `SendMessagePair`, `ReceiveOutcomingMessage`, `ReceiveIncomingMessage`, `DeleteMessage`, `DeleteConversation`, `GetDirectMessages`;
- `DmSyncBatch` предназначен для межсерверной догоняющей синхронизации, не для обычного клиентского UI.
## 1. `UpsertPushToken`
@@ -139,11 +140,14 @@
"op": "ReceiveIncomingMessage",
"requestId": "dm-in-001",
"payload": {
"incomingBlobB64": "BASE64_INCOMING_SIGNED_BLOCK"
"incomingBlobB64": "BASE64_INCOMING_SIGNED_BLOCK",
"sourceServerLogin": "server-a"
}
}
```
`sourceServerLogin` необязателен. Если поле есть, сервер использует его как подсказку, чтобы не отправлять событие обратно серверу-источнику.
## 5. `DeleteMessage`
Принимает один signed DM-блок `type=5` или `type=6`.
@@ -241,7 +245,69 @@
Для следующей страницы клиент должен передать `nextBeforeTimeMs` и `nextBeforeMessageKey` из предыдущего ответа.
## 8. `AckSessionDelivery`
## 8. `DmSyncBatch`
Межсерверная операция для догоняющей синхронизации истории одного пользователя. В текущей реализации не требует авторизации сервера-источника, но удалённый сервер отдаёт данные только если сам является access-сервером `ownerLogin` по `user_access_servers_current`.
### Запрос
```json
{
"op": "DmSyncBatch",
"requestId": "dm-sync-001",
"payload": {
"ownerLogin": "alice",
"afterStoredAtMs": 1774700000000,
"afterMessageKey": "alice|bob|1774699999000|123456780|2",
"limit": 500,
"maxBytes": 3000000
}
}
```
`afterStoredAtMs` и `afterMessageKey` образуют курсор. Если курсора нет, сервер передаёт `0` и пустую строку. `limit` ограничен максимумом `500`.
### Успешный ответ
```json
{
"op": "DmSyncBatch",
"requestId": "dm-sync-001",
"status": 200,
"ok": true,
"payload": {
"ownerLogin": "alice",
"limit": 500,
"rawBytes": 84512,
"hasMore": true,
"nextStoredAtMs": 1774700100000,
"nextMessageKey": "alice|bob|1774700000123|123456789|1",
"items": [
{
"messageKey": "alice|bob|1774700000123|123456789|1",
"baseKey": "alice|bob|1774700000123|123456789",
"targetLogin": "alice",
"fromLogin": "bob",
"toLogin": "alice",
"messageType": 1,
"timeMs": 1774700000123,
"storedAtMs": 1774700100000,
"blobB64": "BASE64_SIGNED_BLOCK"
}
]
}
}
```
События в `items` идут по `storedAtMs ASC, messageKey ASC`. В пачке могут быть сообщения любых диалогов пользователя, read-receipt и delete/tombstone типов `5/6/7/8`.
Ошибки:
- `400 / EMPTY_OWNER_LOGIN` — не передан `ownerLogin`
- `403 / LOCAL_SERVER_NOT_ACCESS_SERVER` — этот сервер не является access-сервером пользователя
- `500 / LOCAL_SERVER_NOT_CONFIGURED` — не настроен `server.SHiNE.login`
## 9. `AckSessionDelivery`
Требует авторизации. Подтверждает доставку в текущую сессию.
@@ -257,7 +323,7 @@
}
```
## 9. Событие `SignedMessageArrived`
## 10. Событие `SignedMessageArrived`
Сервер присылает его по WebSocket в активные сессии адресата.
@@ -282,15 +348,15 @@
Для типов `5/6/7/8` событие тоже приходит в таком же конверте, но логика применения определяется `messageType` и бинарным `blobB64`.
## 10. `CallInviteBroadcast`
## 11. `CallInviteBroadcast`
Требует авторизации. Шлёт приглашение к звонку в активные сессии `toLogin`.
## 10. `CallSignalToSession`
## 12. `CallSignalToSession`
Требует авторизации. Шлёт сигнал звонка в конкретную сессию.
## 11. Замечания
## 13. Замечания
- все DM-типы `1..8` используют `SHiNE_DM`
- `GetUser` может lazy-import пользователя из Solana PDA, поэтому именно через него клиент обычно получает `clientKey` адресата для E2EE