Убрали старый sync и обновили bundle

Что сделано: вычистили неиспользуемый user-settings sync/DM sync хвост, сохранили сборку, обновили bundle.sh так, чтобы gradle-wrapper.jar всегда попадал в архив.

Проверено: compileJava и deploy на t2 (server + UI).
Не проверяли: полные интеграционные сценарии, ручные UI-флоу и продовый деплой.
This commit is contained in:
AidarKC
2026-08-28 14:51:47 +04:00
parent ef1fd9f579
commit 8a0275d962
56 changed files with 747 additions and 2428 deletions
+4 -7
View File
@@ -63,14 +63,9 @@
| `UpsertPushToken` | `12_Direct_Messages_Push_Calls_API.md` | регистрация WebPush-токена |
| `SendTestWebPush` | `12_Direct_Messages_Push_Calls_API.md` | тестовая push-доставка |
| `SendMessagePair` | `12_Direct_Messages_Push_Calls_API.md` | отправка пары входящий/исходящий DM |
| `ReceiveOutcomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | старая полная DM-пара для второго access-сервера отправителя |
| `ReceiveIncomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | прием входящего DM-блока |
| `ReceiveIncomingMessage` | `12_Direct_Messages_Push_Calls_API.md` | внутренняя доставка входящего DM-блока на единственный сервер получателя |
| `DeleteMessage` | `12_Direct_Messages_Push_Calls_API.md` | tombstone одного личного сообщения у обеих сторон |
| `DeleteConversation` | `12_Direct_Messages_Push_Calls_API.md` | tombstone удаления истории переписки |
| `DmSyncBatch` | `12_Direct_Messages_Push_Calls_API.md` | pull событий `synced=false` с ACK предыдущей страницы |
| `GetDmDeliveryStatus` | `12_Direct_Messages_Push_Calls_API.md` | read-only статус доставки по существующему `messageKey` |
| `UserSettingsSyncBatch` | `13_User_Settings_API.md` | межсерверная догоняющая синхронизация пользовательских настроек по курсору |
| `MarkAllUserSettingsUnsynced` | `13_User_Settings_API.md` | служебная пометка всех настроек как несинхронизированных |
| `GetDirectMessages` | `12_Direct_Messages_Push_Calls_API.md` | постраничная загрузка истории личного диалога |
| `AckSessionDelivery` | `12_Direct_Messages_Push_Calls_API.md` | подтверждение доставки в сессию |
| `CallInviteBroadcast` | `12_Direct_Messages_Push_Calls_API.md` | broadcast приглашения к звонку |
@@ -78,7 +73,9 @@
## Важные замечания
- `ReceiveOutcomingMessage` зарегистрирован как алиас того же handler/request-класса, что и `SendMessagePair`, и сохраняет прежний межсерверный payload.
- UI отправляет полную подписанную пару только через `SendMessagePair`.
- `ReceiveIncomingMessage` вызывается сервером отправителя для доставки одной
входящей копии на единственный access-сервер получателя.
- Межсерверные DM-операции пока доверяют `sourceServerLogin`; отдельная межсерверная авторизация запланирована позднее.
- `ServerHello` пока принимает заявленный `serverLogin` на доверии и не является криптографической аутентификацией.
- Отдельных HTTP endpoints для DM-файлов сейчас нет.
+20 -97
View File
@@ -9,8 +9,10 @@
Важно:
- для DM v1 нужно использовать `SendMessagePair`, `ReceiveOutcomingMessage`, `ReceiveIncomingMessage`, `DeleteMessage`, `DeleteConversation`, `GetDirectMessages`;
- `DmSyncBatch` предназначен для межсерверной догоняющей синхронизации, не для обычного клиентского UI.
- UI использует `SendMessagePair`, `DeleteMessage`, `DeleteConversation`
и `GetDirectMessages`;
- `ReceiveIncomingMessage` — внутренняя доставка одной входящей копии на
единственный access-сервер получателя.
- сервер поддерживает материализованный слой диалогов `dm_dialog_state`; `read receipt` обновляет серверный watermark и `unreadCount`, а не только локальный клиентский флаг.
- в `dm_dialog_state` сервер также хранит `last_message_blob_b64` для последнего контентного DM в base64, чтобы клиент мог отрисовать список чатов без дополнительного запроса.
@@ -69,9 +71,7 @@
}
```
## 3. `SendMessagePair` и `ReceiveOutcomingMessage`
`ReceiveOutcomingMessage` — алиас `SendMessagePair`.
## 3. `SendMessagePair`
### Назначение
@@ -114,7 +114,10 @@
}
```
Успешный `status=200` подтверждает локальное сохранение. До ответа клиенту сервер параллельно пробует оба актуальных сервера получателя. Поэтому `deliveryState` уже может быть `delivered`; если никто не ответил, возвращается `accepted`.
Успешный `status=200` подтверждает локальное сохранение. До ответа клиенту
сервер пробует единственный актуальный сервер получателя. Поэтому
`deliveryState` уже может быть `delivered`; если сервер получателя не
ответил, возвращается `accepted`.
Возможные `deliveryState`: `accepted`, `delivered`, `failed`.
@@ -132,7 +135,8 @@
### Назначение
Используется там, где нужно принять только incoming-вариант сообщения.
Используется сервером отправителя для доставки incoming-варианта сообщения на
единственный access-сервер получателя.
Принимаемые типы:
@@ -152,7 +156,9 @@
}
```
`sourceServerLogin` необязателен для совместимости. Пока межсерверная авторизация отложена, это поле считается доверенным. Пользовательская подпись signed-блока проверяется всегда. Пустой `sourceServerLogin` трактуется как клиентский вызов, непустой - как peer-вызов.
`sourceServerLogin` пока передаётся для диагностики маршрута. Межсерверная
авторизация остаётся отдельным будущим этапом, но пользовательская подпись
signed-блока проверяется всегда. Официальный UI эту операцию не вызывает.
Успешный ответ содержит существующие `messageKey`, `baseKey` и счётчики realtime-доставки. Повтор уже сохранённой той же ревизии обрабатывается идемпотентно.
@@ -262,31 +268,11 @@
Поле `deliveryState` заполняется для исходящих элементов `type=2`. У входящих `type=1` оно отсутствует/равно `null`.
## 8. Межсерверные операции DM
## 8. Внутренняя межсерверная доставка DM
До отдельного этапа server-auth поля `sourceServerLogin` доверяются. Каждый `SHiNE_DM` всё равно заново проходит проверку формата и пользовательской подписи.
### 8.1. `ReceiveIncomingMessage`
### 8.1. `ReceiveOutcomingMessage`
Прежняя операция передачи полной пары второму access-серверу отправителя. Delivery-state в межсерверный запрос не входит.
```json
{
"op": "ReceiveOutcomingMessage",
"requestId": "dm-peer-001",
"payload": {
"incomingBlobB64": "BASE64_INCOMING",
"outgoingBlobB64": "BASE64_OUTGOING",
"sourceServerLogin": "server-a"
}
}
```
Ответ имеет прежний формат `SendMessagePair`. Принимающий сервер сохраняет пару идемпотентно и самостоятельно ставит локальную задачу доставки.
### 8.2. `ReceiveIncomingMessage`
Прежняя операция передачи одной входящей копии серверу получателя или второму серверу самого получателя.
Передаёт одну входящую копию на единственный access-сервер получателя.
```json
{
@@ -301,72 +287,9 @@
Успешный 2xx-ответ означает, что signed-блок проверен и находится в БД (новая или идемпотентно повторённая запись).
### 8.3. `DmSyncBatch`
Pull-синхронизация событий владельца с `synced=false`. `ackSyncIds` подтверждает версии событий, успешно сохранённые из предыдущего ответа.
```json
{
"op": "DmSyncBatch",
"requestId": "dm-sync-001",
"payload": {
"ownerLogin": "alice",
"afterStoredAtMs": 0,
"afterMessageKey": "",
"limit": 500,
"maxBytes": 3000000,
"ackSyncIds": []
}
}
```
Ответ возвращает страницу несинхронизированных событий и курсор внутри текущего цикла:
```json
{
"nextStoredAtMs": 1774700001123,
"nextMessageKey": "alice|bob|1774700000123|123456789|2",
"hasMore": false,
"items": [
{
"syncId": "alice|bob|1774700000123|123456789|2:0:0",
"primaryMessageKey": "alice|bob|1774700000123|123456789|2",
"storedAtMs": 1774700001123,
"blobsB64": ["BASE64_INCOMING", "BASE64_OUTGOING"]
}
]
}
```
Для пары порядок всегда incoming/outgoing; для входящей копии и tombstone массив содержит один blob. `syncId` — технический идентификатор конкретной ревизии только для ACK синхронизации, а не второй ID сообщения. После сохранения вызывающий сервер передаёт `syncId` в `ackSyncIds` следующего запроса. Только тогда источник ставит `synced=true`. Новый цикл начинается с `afterStoredAtMs=0`; полный сброс флагов поэтому повторно отдаёт всю историю.
### 8.4. `GetDmDeliveryStatus`
Единственная новая межсерверная операция доставки. Read-only проверка существующего `messageKey`; не изменяет состояние отвечающего сервера.
```json
{
"op": "GetDmDeliveryStatus",
"requestId": "dm-status-001",
"payload": {
"messageKey": "alice|bob|1774700000123|123456789|2"
}
}
```
Ответ содержит `messageKey`, `known` и `delivered`. `delivered=true` означает доставку хотя бы одному серверу получателя.
Периодический процесс использует один логический последовательный сеанс поверх
постоянного WSS-пула: сначала синхронизирует настройки, затем вызывает
`DmSyncBatch` до завершения страниц и ACK. Существующий
`MarkAllUserSettingsUnsynced` также сбрасывает DM-флаги и возвращает
`dmUpdated`; отдельной операции `MarkAllDmUnsynced` нет.
Основные ошибки межсерверных операций:
- `400 / EMPTY_OWNER_LOGIN`, `EMPTY_MESSAGE_KEY`;
- `403 / LOCAL_SERVER_NOT_ACCESS_SERVER`;
- `500 / LOCAL_SERVER_NOT_CONFIGURED`.
Операции `ReceiveOutcomingMessage`, `DmSyncBatch` и
`GetDmDeliveryStatus` удалены вместе с репликацией между access-серверами
одного пользователя.
## 9. `AckSessionDelivery`
+36 -83
View File
@@ -1,104 +1,57 @@
# API пользовательских настроек
# User Settings API
Этот раздел описывает `user_settings` - отдельное хранилище пользовательских настроек, не связанное с `users_params` и не связанное с legacy DM-таблицами.
user_settings хранит технические настройки пользователя только на его
единственном действующем access-сервере. Межсерверной синхронизации настроек
нет. При смене access-сервера старые настройки автоматически не переносятся.
## 1. Назначение
## Подпись
`user_settings` хранит технические пользовательские настройки, которые должны синхронизироваться между максимум двумя access/sync-серверами пользователя.
UI формирует строку:
Основной текущий кейс:
SHiNe/UserSettings:<login>|<setting_type>|<setting_key>|<time_ms>|<value_text>|<value_num>
- `setting_type = 1` - курсор прочитанности канала;
- `setting_key = ownerBlockchainName/channelName`;
- `value_num = number of messages already seen in channel`;
- `value_text = ''`.
и подписывает её текущим Ed25519 clientKey пользователя. Сервер:
Если настройки нет, канал считается полностью прочитанным, то есть unread = `0`.
После первого открытия канала UI отправляет текущий курсор, чтобы зафиксировать baseline и дальше считать только новые сообщения.
1. находит пользователя;
2. проверяет совпадение client_key с актуальным ключом пользователя;
3. строго проверяет подпись;
4. при неверной подписи возвращает INVALID_SIGNATURE;
5. сохраняет запись только если time_ms новее локальной версии.
## 2. Структура записи
## Операции
- `login` - логин владельца настройки;
- `setting_type` - числовой код типа настройки;
- `setting_key` - строковый ключ настройки;
- `time_ms` - время установки значения в миллисекундах;
- `value_text` - строковое значение;
- `value_num` - числовое значение;
- `client_key` - публичный Ed25519 ключ клиента в Base64;
- `signature` - Ed25519 подпись preimage в Base64;
- `synced` - была ли настройка успешно доставлена на второй сервер.
### UpsertUserSetting
Уникальность: `(login, setting_type, setting_key)`.
Обновление: только если `time_ms` новее текущего значения.
Обязательные поля:
## 3. Формат подписи
- login;
- setting_type;
- setting_key;
- time_ms;
- client_key;
- signature.
Подписывается строка:
Значения:
`SHiNe/UserSettings:|login|setting_type|setting_key|time_ms|value_text|value_num`
- value_text — строковое значение, по умолчанию пустая строка;
- value_num — числовое значение, по умолчанию 0.
Где внутри полей используется экранирование `\` и `|`.
Поля sync_delivery и synced удалены.
Подпись создаётся клиентским `client_key`.
### GetUserSetting
## 4. Операции
Возвращает одну локальную настройку по login, setting_type и setting_key.
### `UpsertUserSetting`
### ListUserSettings
Записывает или обновляет настройку пользователя.
Возвращает все локальные настройки пользователя.
Если запрос пришёл от клиента, сервер:
## Удалённые операции
- сохраняет запись локально;
- пытается сразу отправить её на доступный sync-сервер;
- если отправка успешна, помечает запись как `synced=true`;
- если нет, оставляет `synced=false`.
После перехода на один access-сервер удалены:
Если запрос пришёл по синхронизации между серверами, используется `sync_delivery=true`, и повторной пересылки дальше не делается.
- UserSettingsSyncBatch;
- MarkAllUserSettingsUnsynced.
### `GetUserSetting`
Чтение одной настройки по `(login, setting_type, setting_key)`.
### `ListUserSettings`
Список всех настроек пользователя.
### `UserSettingsSyncBatch`
Внутренний межсерверный batch-эндпоинт.
- отдаёт настройки, новые относительно курсора;
- используется для bootstrap и догрузки после восстановления;
- применяется только для пользователей, чей сервер есть в `access_servers`.
### `MarkAllUserSettingsUnsynced`
Внутренний служебный запрос.
- помечает все настройки пользователя или все настройки сразу как `synced=false`;
- одновременно сбрасывает DM-outbox того же пользователя (или всех пользователей), чтобы операция замены/добавления access-сервера не оставила историю DM несинхронизированной;
- ответ дополнительно содержит `dmUpdated` — количество сброшенных DM-событий;
- нужен после добавления нового sync-сервера или при потере локальной БД.
## 5. Синхронизация
Настройки и DM имеют раздельные таблицы и правила ACK, но периодический процесс
использует один логический последовательный сеанс поверх постоянного WSS-пула:
сначала синхронизирует настройки, затем забирает `DmSyncBatch`. Завершение
логического сеанса не закрывает физический сокет.
- локальная запись создаётся с `synced=false`, если её ещё не подтвердил второй сервер;
- если запись пришла с другого сервера, она сохраняется сразу как `synced=true`;
- периодический sync раз в 6 часов проверяет несинхронизированные настройки, догружает их по курсору и затем забирает несинхронизированные DM;
- если появляется новый sync-сервер или локальная БД была потеряна, нужно пометить все настройки несинхронизированными и заново догрузить batch с нуля.
## 6. Текущий UI-кейс
UI при открытии канала отправляет `UpsertUserSetting` с:
- `setting_type = 1`;
- `setting_key = ownerBlockchainName/channelName`;
- `value_num = количество уже просмотренных сообщений в канале`.
Это значение используется сервером для расчёта unread в списке каналов и в канале.
Также удалены таблица peer-cursor и периодический сервис синхронизации
настроек.
+4 -3
View File
@@ -55,7 +55,8 @@
- физическое соединение создаётся одно на `serverLogin`;
- логические операции DM, settings и blockchain используют один WSS;
- завершение `RemoteSyncSession` не закрывает физический сокет;
- известные peer берутся из `sync_servers` и `user_access_servers_current`;
- известные peer берутся из `sync_servers` и первых действующих маршрутов
`user_access_servers_current`;
- список перечитывается каждые 30 секунд;
- при изменении URL соединение пересоздаётся;
- новые запросы не повторяются транспортом автоматически: действующие
@@ -65,8 +66,8 @@
| Приоритет | Операции |
| --- | --- |
| `REALTIME` | доставка DM, deletes, `GetDmDeliveryStatus` |
| `NORMAL` | настройки, `DmSyncBatch` и access-data sync |
| `REALTIME` | доставка DM и signed deletes |
| `NORMAL` | прочие межсерверные запросы |
| `BULK` | blockchain heads, blocks, `AddBlock` backfill |
На одном peer одновременно исполняется один запрос. Приоритет применяется к