Добавить догоняющую синхронизацию 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
@@ -446,11 +446,14 @@ Request:
"op": "ReceiveIncomingMessage",
"requestId": "req-456",
"payload": {
"incomingBlobB64": "..."
"incomingBlobB64": "...",
"sourceServerLogin": "server-a"
}
}
```
`sourceServerLogin` необязателен и используется как best-effort подсказка, чтобы сервер при дальнейшей пересылке не отправлял то же событие обратно серверу-источнику.
### 10.3. `DeleteMessage`
Назначение:
@@ -559,7 +562,50 @@ UI-следствие для клиента:
Идемпотентность обязательна.
### 11.3. Ошибки доставки
### 11.3. Догоняющая синхронизация истории
Для восстановления пропущенных DM-событий между access-серверами используется отдельная операция:
- `DmSyncBatch`
Сервер-получатель синхронизации запрашивает у другого access-сервера историю одного пользователя по курсору:
- `ownerLogin`;
- `afterStoredAtMs`;
- `afterMessageKey`;
- `limit`, максимум `500`;
- `maxBytes`, ограничение суммарного размера raw-блоков пачки.
Удалённый сервер отдаёт все DM-события, относящиеся к этому пользователю:
- контентные копии и read-receipt по `target_login`;
- tombstone типов `5/6/7/8`, где пользователь участвует как `fromLogin` или `toLogin`.
Порядок пачки:
- `created_at_ms ASC`;
- `message_key ASC`.
Курсор хранится локально для пары:
- пользователь;
- удалённый access-сервер.
При первом добавлении сервера или отсутствии курсора синхронизация стартует с `0` и постепенно подтягивает всю доступную историю пачками.
При применении событий, полученных через `DmSyncBatch`, сервер:
- проверяет формат `SHiNE_DM`;
- проверяет подпись;
- применяет существующие правила ревизий, read-receipt и tombstone;
- не отправляет realtime/push-уведомления клиентам;
- не запускает повторный fan-out, чтобы не создавать циклы.
Плановый sync запускается фоном после старта WebSocket-сервера и повторяется раз в 6 часов.
В текущей реализации межсерверная авторизация для `DmSyncBatch` ещё не включена. Сервер отдаёт пачку только если сам локально является access-сервером `ownerLogin` по актуальной таблице `user_access_servers_current`.
### 11.4. Ошибки доставки
Если часть серверов временно недоступна:
@@ -571,7 +617,7 @@ UI-следствие для клиента:
Основная таблица остаётся:
- `signed_messages_v2`
- `signed_messages`
В ней должны сохраняться:
@@ -590,6 +636,12 @@ UI-следствие для клиента:
Сообщение об удалении переписки тоже хранится в БД, а старые сообщения до его времени из БД удаляются.
Для догоняющей межсерверной синхронизации дополнительно используются:
- индекс по `target_login`, `created_at_ms`, `message_key`;
- отдельные индексы по delete-событиям для `from_login` и `to_login`;
- таблица `dm_sync_peer_state` с курсором чтения для пары `ownerLogin + remoteServerLogin`.
## 13. Что обязательно должно измениться в коде относительно v0.5
- сервер не должен требовать одинаковый `encryptedBody` у `type=1` и `type=2`;
@@ -610,4 +662,4 @@ UI-следствие для клиента:
- хранение отдельного `keyId` шифрования в DM;
- ротация `clientKey`;
- финальная конкретная UI-реализация массовой перешифровки;
- физическая полная реализация DM federation в текущем коде.
- межсерверная авторизация `DmSyncBatch`.
@@ -327,3 +327,5 @@ ReadReceiptBody_v1_0
## 13. Примечание о поддержке
В версии DM v1 все типы `1..8` используют единый контейнер `SHiNE_DM`.
Межсерверная операция `DmSyncBatch` не вводит новый байтовый формат DM. Она передаёт уже сохранённые raw-контейнеры `SHiNE_DM` в Base64 вместе с серверными метаданными курсора (`storedAtMs`, `messageKey`), а принимающий сервер заново проверяет подпись и применяет тот же контейнер по его `messageType`.