SHiNE-server/Dev_Docs/Personal_Messages/README.md

9.6 KiB
Raw Blame History

Личные сообщения (DM)

Текущее состояние

Сейчас в проекте реализованы:

  • новый формат контентных личных сообщений SHiNE_DM;
  • ревизии сообщений через revisionTimeMs;
  • редактирование сообщения через повторную отправку той же логической пары;
  • удаление сообщения через пустую ревизию;
  • upsert последней версии сообщения на сервере.

Сейчас в проекте не реализованы:

  • вложения в DM;
  • upload/download файлов для DM;
  • UI-кнопка прикрепления файла;
  • серверное хранение файловых связей для DM.

Черновик будущих вложений вынесен отдельно:

  • Dev_Docs/Personal_Messages/Черновик_будущих_DM_вложений.md

Общая схема

Личное сообщение по-прежнему отправляется парой signed-блоков:

  • type=1 — входящий блок для получателя;
  • type=2 — исходящая копия для отправителя.

Read-receipt пока остаются в legacy-формате:

  • type=3 — входящее подтверждение прочтения;
  • type=4 — исходящая копия подтверждения.

Ключи сообщения:

  • baseKey = fromLogin|toLogin|timeMs|nonce
  • messageKey = baseKey|messageType

Логический идентификатор письма задаётся парой:

  • timeMs
  • nonce

Эти поля не меняются при редактировании или удалении. Меняется только:

  • revisionTimeMs
  • содержимое encryptedBody

Сервер хранит только последнюю версию записи для каждого messageKey.

Формат контентного DM: SHiNE_DM

Префикс бинарного блока:

  • SHiNE_DM

Поля идут в big-endian порядке:

  1. formatVersionMajor (u8) = 1
  2. formatVersionMinor (u8) = 0
  3. toLoginLen (u8) + toLogin (ASCII, 1..60)
  4. fromLoginLen (u8) + fromLogin (ASCII, 1..60)
  5. timeMs (u64)
  6. nonce (u32)
  7. messageType (u16) — только 1 или 2
  8. revisionTimeMs (u64)
  9. attachmentsCount (u8)
  10. encryptedBodyLen (u32)
  11. encryptedBody (bytes)
  12. signature (64 bytes, Ed25519)

Ограничения

  • attachmentsCount сейчас всегда должен быть 0
  • encryptedBodyLen сейчас ограничен сервером до 16384 байт
  • revisionTimeMs не может быть отрицательным

Если приходит attachmentsCount != 0, сервер отклоняет такой DM как:

  • ATTACHMENTS_DISABLED

Legacy read-receipt: SHiNE_dm2

Подтверждения прочтения type=3/4 пока используют старый контейнер SHiNE_dm2:

  1. toLoginLen (u8) + toLogin
  2. fromLoginLen (u8) + fromLogin
  3. timeMs (u64)
  4. nonce (u32)
  5. messageType (u16) — 3 или 4
  6. payloadLen (u16)
  7. payloadBytes
  8. signature

Редактирование

Редактирование делается новой отправкой той же логической пары сообщения:

  • timeMs и nonce остаются теми же;
  • messageType остаётся 1/2;
  • revisionTimeMs становится больше;
  • encryptedBody содержит новую версию текста.

Если на сервер приходит более старая ревизия, она игнорируется.

Если приходит та же ревизия и тот же бинарный блок, сервер тоже её не применяет повторно.

Удаление

Удаление личного сообщения делается как новая ревизия того же сообщения:

  • timeMs и nonce остаются прежними;
  • revisionTimeMs увеличивается;
  • attachmentsCount = 0;
  • encryptedBodyLen = 0;
  • encryptedBody пустой.

В UI такое сообщение не показывается.

На сервере это не отдельный тип сообщения, а просто последняя пустая ревизия того же messageKey.

Поведение сервера

Для контентных DM сервер:

  1. принимает пару signed-блоков type=1/2;
  2. валидирует формат, подпись и совпадение ключевых полей пары;
  3. проверяет, что для обеих сторон пары совпадают:
    • fromLogin
    • toLogin
    • timeMs
    • nonce
    • revisionTimeMs
    • encryptedBody
  4. делает upsert последней версии в signed_messages_v2;
  5. сбрасывает pending-доставку по сессиям для новой ревизии;
  6. рассылает актуальную версию адресатам через SignedMessageArrived.

История старых ревизий сейчас не хранится отдельно: в таблице остаётся только последняя версия по каждому messageKey.

Хранение в БД

Основная таблица:

  • signed_messages_v2

Для контентных DM в ней используются:

  • message_key
  • base_key
  • target_login
  • from_login
  • to_login
  • time_ms
  • nonce
  • message_type
  • revision_time_ms
  • raw_block
  • created_at_ms

Отдельных таблиц файлов для DM сейчас нет.

События и доставка

Запрос на отправку по WebSocket остаётся прежним:

  • SendMessagePair
  • ReceiveOutcomingMessage как алиас

Клиент отправляет:

  • incomingBlobB64
  • outgoingBlobB64

Событие в активные сессии:

  • SignedMessageArrived

Если пришла новая ревизия того же сообщения, messageKey остаётся прежним, а внутри blobB64 будет более новый revisionTimeMs.

Подтверждение доставки в сессию:

  • AckSessionDelivery

WebPush и локальные уведомления сейчас работают так:

  • для активной онлайн-сессии приоритет у доставки по WebSocket через SignedMessageArrived;
  • если целевая сессия не онлайн по WebSocket, сервер может отправить WebPush с kind=new_message;
  • если вкладка/приложение живы, но страница скрыта (document.visibilityState !== visible), UI дополнительно пытается показать системное уведомление через service worker;
  • для активной видимой страницы UI проигрывает короткий локальный сигнал на каждое новое входящее DM, если браузер ранее разрешил аудио-контекст после пользовательского жеста;
  • для скрытой, но живой страницы UI также делает best effort сигнал через vibrate() и более длинный локальный звук;
  • эти локальные сигналы не гарантируются браузером: на мобильных устройствах они зависят от политики Chrome/Android/iOS.

Правила UI

UI сейчас работает так:

  • показывает только текст encryptedBody;
  • умеет обновлять уже существующее сообщение по тому же messageKey;
  • не показывает удалённые сообщения;
  • позволяет владельцу сообщения вызвать меню Скопировать как текст / Прочесть / Изменить / Удалить;
  • при редактировании показывает над полем ввода полоску Редактируем сообщение: ... с кнопкой отмены;
  • после редактирования показывает под временем отдельную строку изменено: <дата время>;
  • на видимом экране чата/приложения проигрывает короткий локальный звук на новое входящее DM;
  • при входящем DM для скрытой, но ещё живой страницы пытается поднять системное уведомление через service worker;
  • не показывает и не принимает вложения.

Что обязательно помнить

  • вложения в DM сейчас отключены на уровне протокола и UI;
  • любые старые описания /f/..., /upload и файловых таблиц для DM больше не актуальны;
  • если позже вложения вернутся, их формат и серверная логика могут быть другими.