Files
mobile-android/Architecture.md

14 KiB
Raw Blame History

Rosetta Android — Architecture

Документ описывает текущую архитектуру rosetta-android (ветка dev) по коду, без идеализаций.

1. Архитектурный стиль

Приложение построено как layered + feature-oriented архитектура:

  • UI на Jetpack Compose (MainActivity + ui/*).
  • Бизнес-оркестрация в singleton-сервисах (ProtocolManager, CallManager, TransportManager, UpdateManager).
  • Data слой через репозитории (MessageRepository, GroupRepository, AvatarRepository, AccountManager).
  • Persistence через Room (RosettaDatabase).
  • Crypto изолирован в crypto/*.

DI-контейнера (Hilt/Koin) сейчас нет: зависимости поднимаются через object, getInstance(...), singleton-инициализацию.


2. Слои и границы

flowchart TB
    subgraph UI["UI Layer (Compose + ViewModel)"]
      A1["MainActivity"]
      A2["ui/chats/*"]
      A3["ui/auth/*"]
      A4["ui/settings/*"]
    end

    subgraph SVC["Service Layer (Singleton orchestrators)"]
      B1["ProtocolManager"]
      B2["CallManager"]
      B3["TransportManager"]
      B4["UpdateManager"]
      B5["RosettaFirebaseMessagingService"]
    end

    subgraph DATA["Data Layer"]
      C1["MessageRepository"]
      C2["GroupRepository"]
      C3["AvatarRepository"]
      C4["AccountManager / PreferencesManager"]
      C5["DraftManager / ForwardManager"]
    end

    subgraph DB["Persistence Layer"]
      D1["Room: RosettaDatabase"]
      D2["DAO: message/dialog/group/etc"]
    end

    subgraph NET["Network Layer"]
      E1["Protocol (WebSocket)"]
      E2["Packet* codec"]
      E3["OkHttp HTTP (transport/update)"]
      E4["WebRTC"]
    end

    subgraph CRYPTO["Crypto Layer"]
      F1["CryptoManager"]
      F2["MessageCrypto"]
      F3["XChaCha20E2EE (calls)"]
    end

    UI --> SVC
    UI --> DATA
    SVC --> DATA
    SVC --> NET
    DATA --> DB
    DATA --> CRYPTO
    SVC --> CRYPTO

3. Главные модули и ответственность

3.1 MainActivity (composition root)

MainActivity — главный orchestration entrypoint приложения:

  • поднимает ProtocolManager.initialize(...), CallManager.initialize(...);
  • управляет auth-гейтингом, онбордингом и основным nav-stack (Screen);
  • привязывает текущий аккаунт к runtime-сервисам;
  • триггерит fast reconnect на onResume;
  • следит за разрешениями (уведомления, fullscreen intent и т.д.).

3.2 RosettaApplication

На старте процесса инициализирует глобальные подсистемы:

  • crash reporting,
  • draft manager,
  • transport manager,
  • update manager.

3.3 Репозитории

MessageRepository

Ключевой data-центр для чатов:

  • инициализация аккаунт-контекста (publicKey/privateKey);
  • отправка сообщений (optimistic insert + сетевой send);
  • обработка входящих PacketMessage/PacketDelivery/PacketRead;
  • обновление dialogs, messages, message_search_index;
  • синк timestamp (accounts_sync_times);
  • шина событий для UI (newMessageEvents, deliveryStatusEvents).

GroupRepository

  • хранение и операции по группам,
  • интеграция с PacketGroup*.

AvatarRepository

  • кэш/история аватаров (Room + file storage),
  • реактивная выдача аватаров через Flow.

AccountManager

  • хранение аккаунтов в DataStore,
  • last logged public/private hash в SharedPreferences для быстрых синхронных чтений.

4. Сетевой стек

4.1 Protocol (низкий уровень)

Protocol отвечает за:

  • WebSocket lifecycle (DISCONNECTED/CONNECTING/CONNECTED/HANDSHAKING/DEVICE_VERIFICATION_REQUIRED/AUTHENTICATED),
  • heartbeat,
  • reconnect/backoff,
  • packet encode/decode,
  • waitPacket/unwaitPacket обработчики,
  • queue pre-handshake пакетов.

Ключевые механизмы устойчивости:

  • lifecycleMutex для serialized lifecycle операций,
  • connectionGeneration для игнора stale callbacks старых сокетов,
  • guard isConnecting от параллельного connect().

4.2 ProtocolManager (верхний уровень)

ProtocolManager — orchestration-слой над Protocol:

  • единая точка для UI/Data слоёв (send, authenticate, reconnect, waitPacket и т.д.);
  • bootstrap после auth (sync, own-profile resolve, push subscribe);
  • маршрутизация входящих packet-ов в репозитории/подсистемы;
  • call signaling bridge для CallManager;
  • управление typed caches (SearchUser, user info cache).

Новый runtime-дизайн connection orchestration:

  • ProtocolConnectionModels.ktConnectionLifecycleState, ConnectionEvent, bootstrap context;
  • ProtocolConnectionSupervisor.kt — actor/event-loop для serialized событий;
  • ReadyPacketGate.kt — очередь пакетов до состояния READY (TTL + max size).

5. Lifecycle состояния соединения (верхний уровень)

ProtocolManager.connectionLifecycleState:

  • DISCONNECTED
  • CONNECTING
  • HANDSHAKING
  • AUTHENTICATED
  • BOOTSTRAPPING
  • READY
  • DEVICE_VERIFICATION_REQUIRED

Переход в READY происходит только когда одновременно выполнено:

  • аккаунт инициализирован,
  • протокол аутентифицирован,
  • sync завершён,
  • own-profile резолвнут (или истёк fallback timeout).
stateDiagram-v2
    [*] --> DISCONNECTED
    DISCONNECTED --> CONNECTING
    CONNECTING --> HANDSHAKING
    HANDSHAKING --> DEVICE_VERIFICATION_REQUIRED
    HANDSHAKING --> AUTHENTICATED
    AUTHENTICATED --> BOOTSTRAPPING
    BOOTSTRAPPING --> READY
    READY --> DISCONNECTED
    DEVICE_VERIFICATION_REQUIRED --> CONNECTING

6. Поток auth / session bootstrap

sequenceDiagram
    participant UI as AuthFlow/MainActivity
    participant PM as ProtocolManager
    participant P as Protocol
    participant MR as MessageRepository

    UI->>PM: initializeAccount(public, private)
    UI->>PM: connect()
    UI->>PM: authenticate(public, privateHash)
    PM->>P: connect + startHandshake
    P-->>PM: AUTHENTICATED
    PM->>PM: onAuthenticated()
    PM->>PM: subscribePushTokenIfAvailable()
    PM->>PM: requestSynchronize()
    PM->>MR: initialize(...)
    PM-->>PM: SyncCompleted + OwnProfileResolved
    PM-->>UI: connectionLifecycleState = READY

Критично: отправка пользовательских пакетов до READY не теряется, а попадает в ReadyPacketGate.


7. Поток сообщений (send/receive/delivery)

7.1 Отправка

  1. UI (ChatViewModel) вызывает отправку через MessageRepository.sendMessage(...).
  2. Репозиторий делает optimistic insert в messages (WAITING).
  3. Формируется PacketMessage.
  4. Отправка идёт в ProtocolManager.send(...).
  5. Если состояние не READY, пакет ставится в ReadyPacketGate.
  6. После READY очередь сбрасывается в Protocol.sendPacket(...).

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

  1. Сервер присылает PacketDelivery (0x08).
  2. ProtocolManager маршрутизирует в MessageRepository.handleDelivery(...).
  3. Репозиторий обновляет статус в Room.
  4. UI получает апдейт через Flow/события.

7.3 Входящие

  1. PacketMessage (0x06) приходит в Protocol.
  2. ProtocolManager dispatch → MessageRepository.handleIncomingMessage(...).
  3. Сообщение сохраняется в Room, обновляется dialogs и индексы поиска.
  4. UI реактивно перерисовывается.

8. Sync-пайплайн

Используется пакет PacketSync (0x19) и режимы:

  • BATCH_START
  • поток синк-пакетов (MESSAGE/READ/DELIVERY/...)
  • BATCH_END
  • NOT_NEEDED

Особенности:

  • есть последовательная очередь inbound задач для сохранения порядка обработки;
  • after-sync hooks: retry waiting messages, request missing user info;
  • sync timestamp хранится в accounts_sync_times.

9. Calls (WebRTC + signaling)

CallManager использует:

  • signaling пакеты: PacketSignalPeer (0x1A), PacketWebRTC (0x1B);
  • ICE: PacketIceServers (0x1C);
  • WebRTC stack (PeerConnectionFactory, PeerConnection, audio track);
  • E2EE голоса через XChaCha20E2EE обвязки sender/receiver.

Основные фазы звонка:

  • IDLEINCOMING/OUTGOINGCONNECTINGACTIVEIDLE.
stateDiagram-v2
    [*] --> IDLE
    IDLE --> OUTGOING
    IDLE --> INCOMING
    OUTGOING --> CONNECTING
    INCOMING --> CONNECTING
    CONNECTING --> ACTIVE
    ACTIVE --> IDLE
    OUTGOING --> IDLE
    INCOMING --> IDLE

10. Transport (вложения)

TransportManager:

  • получает transport server через PacketRequestTransport (0x0F) (desktop parity);
  • upload/download через OkHttp;
  • resumable download (HTTP Range);
  • трекает состояния прогресса через StateFlow (uploading, downloading);
  • поддерживает cancel/pause/resume через FileDownloadManager.

11. Push Notifications

RosettaFirebaseMessagingService:

  • обрабатывает onNewToken и подписку токена через ProtocolManager;
  • dedup пушей;
  • маршрутизация типов (personal_message, group_message, call, read);
  • очистка уведомлений по read events;
  • wake-up reconnect при silent push.

12. Обновления (SDU)

UpdateManager:

  1. запрашивает update server через PacketRequestUpdate (0x0A);
  2. ходит на SDU HTTP endpoint;
  3. скачивает APK через DownloadManager;
  4. ведёт update state machine (Idle/Checking/UpdateAvailable/Downloading/ReadyToInstall/Error).

13. Persistence (Room)

RosettaDatabase (version 17) включает:

  • messages — сообщения,
  • dialogs — диалоги + денормализованные поля для быстрых списков,
  • message_search_index — локальный индекс поиска,
  • groups — группы,
  • pinned_messages — закрепы,
  • avatar_cache — аватары,
  • blacklist — blacklist,
  • accounts_sync_times — sync cursor,
  • encrypted_accounts — аккаунты (legacy Room account storage).

Есть длинная цепочка миграций (4→17) с оптимизациями под производительность и денормализацию.


14. Crypto

  • CryptoManager:

  • seed phrase / keypair,

  • PBKDF2-derived key caching,

  • encrypt/decrypt для локального хранения.

  • MessageCrypto:

  • message-level XChaCha20-Poly1305,

  • ECDH/AES-обмен ключом для payload,

  • attachment decrypt logic.

Crypto и network связаны через MessageRepository/ProtocolManager.


15. Наблюдаемость и диагностика

  • wire/protocol логи через ProtocolManager.addLog(...) + trace file;
  • debug logs доступны в UI;
  • отдельные диагностические логи для звонков (CallManager breadcrumbs).

16. Текущие архитектурные сильные стороны

  • Реактивная модель состояния (StateFlow) на большинстве критических путей.
  • Сильная декомпозиция packet протокола (Packet*).
  • Наличие ready-gate и serialized supervisor снижает race-condition в соединении.
  • Room + денормализация ускоряют списки чатов/поиск.

17. Текущие архитектурные риски

  • MainActivity остаётся очень крупным composition root.
  • ProtocolManager и MessageRepository всё ещё крупные “god objects”.
  • Отсутствие DI усложняет управляемость зависимостей/тестируемость.
  • Часть жизненного цикла связана через runtime singleton state, что повышает риск регрессий при эволюции.

18. Карта ключевых файлов

  • app/src/main/java/com/rosetta/messenger/MainActivity.kt
  • app/src/main/java/com/rosetta/messenger/RosettaApplication.kt
  • app/src/main/java/com/rosetta/messenger/network/Protocol.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolConnectionModels.kt
  • app/src/main/java/com/rosetta/messenger/network/ProtocolConnectionSupervisor.kt
  • app/src/main/java/com/rosetta/messenger/network/ReadyPacketGate.kt
  • app/src/main/java/com/rosetta/messenger/network/CallManager.kt
  • app/src/main/java/com/rosetta/messenger/network/TransportManager.kt
  • app/src/main/java/com/rosetta/messenger/push/RosettaFirebaseMessagingService.kt
  • app/src/main/java/com/rosetta/messenger/update/UpdateManager.kt
  • app/src/main/java/com/rosetta/messenger/data/MessageRepository.kt
  • app/src/main/java/com/rosetta/messenger/database/RosettaDatabase.kt
  • app/src/main/java/com/rosetta/messenger/crypto/CryptoManager.kt
  • app/src/main/java/com/rosetta/messenger/crypto/MessageCrypto.kt