# Rosetta Android — Architecture > Документ отражает текущее состояние `rosetta-android` (ветка `dev`) по коду на 2026-04-18. ## 1. Архитектурный профиль Приложение сейчас устроено как layered + service-oriented архитектура: - UI: `MainActivity` + Compose-экраны + ViewModel. - DI: Hilt (`@HiltAndroidApp`, `@AndroidEntryPoint`, модули в `di/AppContainer.kt`). - Runtime orchestration: `ProtocolRuntime` -> `ProtocolRuntimeCore` (+ compatibility facade `ProtocolManager`), `CallManager`, `TransportManager`, `UpdateManager`. - Session/Identity runtime state: `SessionStore`, `SessionReducer`, `IdentityStore`. - Data: `MessageRepository`, `GroupRepository`, `AccountManager`, `PreferencesManager`. - Persistence: Room (`RosettaDatabase`) + DataStore/SharedPreferences. Основная runtime-логика сети вынесена в instance-класс `ProtocolRuntimeCore`. `ProtocolManager` сохранен как тонкий compatibility facade. DI-вход в network core идет через `ProtocolRuntime` (Hilt singleton). --- ## 2. Слои и границы ```mermaid flowchart TB subgraph ENTRY["Android Entry Points"] E1["RosettaApplication"] E2["MainActivity"] E3["RosettaFirebaseMessagingService"] E4["IncomingCallActivity / CallForegroundService"] end subgraph DI["Hilt Singleton Graph"] D1["ProtocolGateway"] D1A["ProtocolRuntime"] D2["SessionCoordinator"] D3["IdentityGateway"] D4["AccountManager / PreferencesManager"] D5["MessageRepository / GroupRepository"] D6["UiEntryPoint + EntryPointAccessors"] end subgraph SESSION["Session / Identity Runtime"] S1["SessionStore"] S2["SessionReducer"] S3["IdentityStore"] S4["AppSessionCoordinator"] end subgraph NET["Network Runtime"] N0["ProtocolRuntime"] N1["ProtocolRuntimeCore"] N1A["ProtocolManager (compat facade)"] N2["Protocol"] N3["PacketSubscriptionRegistry"] N4["ReadyPacketGate"] end subgraph DATA["Data + Persistence"] R1["MessageRepository"] R2["GroupRepository"] R3["Room: RosettaDatabase"] end ENTRY --> DI DI --> SESSION DI --> NET DI --> DATA D1 --> D1A D1A --> N1 N1A --> N1 SESSION --> NET DATA --> NET DATA --> R3 NET --> N2 ``` --- ## 3. DI и composition root ### 3.1 Hilt - `RosettaApplication` помечен `@HiltAndroidApp`. - Entry points уровня Android-компонентов: `MainActivity`, `IncomingCallActivity`, `CallForegroundService`, `RosettaFirebaseMessagingService`. - Основные модули: - `AppDataModule`: `AccountManager`, `PreferencesManager`. - `AppGatewayModule`: биндинги `ProtocolGateway`, `SessionCoordinator`, `IdentityGateway`, `ProtocolClient`. - `ProtocolGatewayImpl` и `ProtocolClientImpl` делегируют в `ProtocolRuntime`, а не напрямую в UI-слой. ### 3.2 UI bridge для composable-слоя UI-композаблы получают зависимости через `UiEntryPoint` + `EntryPointAccessors.fromApplication(...)`. `UiDependencyAccess.get(...)` из `ui/*` удален (DoD: 0 вхождений). Для non-Hilt `object`-ов (`CallManager`, `TransportManager`, `UpdateManager`, utils) используется `ProtocolRuntimeAccess` + `ProtocolRuntimePort`: - runtime ставится в `RosettaApplication` через `ProtocolRuntimeAccess.install(protocolRuntime)`; - доступ до install запрещен (fail-fast), чтобы не было тихого отката в `ProtocolManager`. ### 3.3 Разрыв DI-cycle (Hilt) После перехода на `ProtocolRuntime` был закрыт цикл зависимостей: `MessageRepository -> ProtocolClient -> ProtocolRuntime -> MessageRepository`. Текущее решение: - `ProtocolClientImpl` получает `Provider` (ленивая резолюция). - `ProtocolRuntime` остается singleton-композицией для `MessageRepository/GroupRepository/AccountManager`. - На `assembleDebug/assembleRelease` больше нет `Dagger/DependencyCycle`. --- ## 4. Session lifecycle: единый source of truth ### 4.1 Модель состояния `SessionState`: - `LoggedOut` - `AuthInProgress(publicKey?, reason)` - `Ready(account, reason)` ### 4.2 Модель событий `SessionAction`: - `LoggedOut` - `AuthInProgress` - `Ready` - `SyncFromCachedAccount` ### 4.3 Контур изменения состояния - Только `SessionStore` владеет `MutableStateFlow`. - Только `SessionReducer` вычисляет next-state. - `SessionCoordinator`/`AppSessionCoordinator` больше не мутируют состояние напрямую, а делают `dispatch(action)`. - `SessionStore.dispatch(...)` синхронно обновляет `IdentityStore` для консистентности account/profile/auth-runtime. ```mermaid flowchart LR A["AuthFlow / MainActivity / Unlock / SetPassword"] --> B["SessionCoordinator.dispatch(action)"] B --> C["SessionStore.dispatch(action)"] C --> D["SessionReducer.reduce(current, action)"] D --> E["StateFlow"] C --> F["IdentityStore sync"] ``` ### 4.4 State machine ```mermaid stateDiagram-v2 [*] --> LoggedOut LoggedOut --> AuthInProgress: dispatch(AuthInProgress) AuthInProgress --> Ready: dispatch(Ready) AuthInProgress --> LoggedOut: dispatch(LoggedOut) Ready --> LoggedOut: dispatch(LoggedOut) Ready --> Ready: dispatch(SyncFromCachedAccount(account)) ``` --- ## 5. Network orchestration после декомпозиции `ProtocolRuntime` — DI-фасад runtime слоя. `ProtocolRuntimeCore` содержит runtime state machine и делегирует отдельные зоны ответственности: - `ConnectionOrchestrator`: connect/reconnect/authenticate + network-aware поведение. - `BootstrapCoordinator`: пересчет lifecycle (`AUTHENTICATED`/`BOOTSTRAPPING`/`READY`) и работа с `ReadyPacketGate`. - `SyncCoordinator`: sync state machine (request/timeout, BATCH_START/BATCH_END/NOT_NEEDED, foreground/manual sync). - `PresenceTypingService`: in-memory typing presence с TTL и snapshot `StateFlow`. - `PacketRouter`: user/search cache + resolve/search continuation routing. - `OwnProfileSyncService`: применение собственного профиля из search и синхронизация `IdentityStore`. - `RetryQueueService`: retry очереди отправки `PacketMessage`. - `AuthBootstrapCoordinator`: session-aware post-auth bootstrap (transport/update/profile/sync/push). - `NetworkReconnectWatcher`: единый watcher ожидания сети и fast-reconnect триггеры. - `DeviceVerificationService`: состояние списка устройств + pending verification + resolve packets. - `DeviceRuntimeService`: device-id/handshake device + device verification orchestration. - `CallSignalBridge`: call/webrtc/ice signal send+subscribe bridge. - `PacketSubscriptionRegistry`: централизованные подписки на пакеты и fan-out. - `OutgoingMessagePipelineService`: отправка `PacketMessage` с retry/error policy. ```mermaid flowchart TB PM["ProtocolRuntimeCore"] --> CO["ConnectionOrchestrator"] PM --> BC["BootstrapCoordinator"] PM --> SC["SyncCoordinator"] PM --> PT["PresenceTypingService"] PM --> PR["PacketRouter"] PM --> OPS["OwnProfileSyncService"] PM --> RQ["RetryQueueService"] PM --> ABC["AuthBootstrapCoordinator"] PM --> NRW["NetworkReconnectWatcher"] PM --> DVS["DeviceVerificationService"] PM --> CSB["CallSignalBridge"] PM --> PSR["PacketSubscriptionRegistry"] PM --> SUP["ProtocolConnectionSupervisor"] PM --> RPG["ReadyPacketGate"] PM --> P["Protocol (WebSocket + packet codec)"] ``` --- ## 6. Централизация packet-subscriptions Проблема дублирующихся low-level подписок закрыта через `PacketSubscriptionRegistry`: - На каждый `packetId` создается один bus и один bridge на `Protocol.waitPacket(...)`. - Дальше packet fan-out идет в: - callback API (`waitPacket/unwaitPacket`), - `SharedFlow` (`packetFlow(packetId)`). ```mermaid sequenceDiagram participant Feature as Feature/Service participant PM as ProtocolRuntimeCore participant REG as PacketSubscriptionRegistry participant P as Protocol Feature->>PM: waitPacket(0x03, callback) PM->>REG: addCallback(0x03, callback) REG->>P: waitPacket(0x03, protocolBridge) [once per packetId] P-->>REG: Packet(0x03) REG-->>Feature: callback(packet) REG-->>Feature: packetFlow(0x03).emit(packet) ``` --- ## 7. Отправка сообщений: use-cases + retry Из `ChatViewModel` выделены use-cases: - `SendTextMessageUseCase` - `SendMediaMessageUseCase` - `SendForwardUseCase` Текущий поток: 1. ViewModel готовит command и шифрованный payload. 2. UseCase собирает `PacketMessage`. 3. UseCase вызывает `protocolGateway.sendMessageWithRetry(packet)`. 4. `ProtocolRuntimeCore` регистрирует пакет в `RetryQueueService` и отправляет в сеть. 5. Если lifecycle еще не `READY`, пакет попадает в `ReadyPacketGate` и flush после `READY`. ```mermaid flowchart LR VM["ChatViewModel"] --> UC["Send*UseCase"] UC --> GW["ProtocolGateway.sendMessageWithRetry"] GW --> PM["ProtocolRuntimeCore"] PM --> RQ["RetryQueueService"] PM --> RG["ReadyPacketGate"] PM --> P["Protocol.sendPacket"] ``` --- ## 8. Auth/bootstrap: фактический runtime flow ```mermaid sequenceDiagram participant UI as Auth UI (SetPassword/Unlock) participant SC as SessionCoordinatorImpl participant SS as SessionStore participant PG as ProtocolGateway participant PM as ProtocolRuntimeCore participant AM as AccountManager UI->>SC: bootstrapAuthenticatedSession(account, reason) SC->>SS: dispatch(AuthInProgress) SC->>PG: initializeAccount(public, private) SC->>PG: connect() SC->>PG: authenticate(public, privateHash) SC->>PG: reconnectNowIfNeeded(...) SC->>AM: setCurrentAccount(public) SC->>SS: dispatch(Ready) PM-->>PM: HANDSHAKE -> AUTHENTICATED -> BOOTSTRAPPING PM-->>PM: SyncCompleted + OwnProfileResolved PM-->>PM: connectionLifecycleState = READY ``` Важно: `SessionState.Ready` (app-session готова) и `connectionLifecycleState = READY` (сеть готова) — это разные state-модели. --- ## 9. Состояния соединения (network lifecycle) `ProtocolRuntimeCore.connectionLifecycleState`: - `DISCONNECTED` - `CONNECTING` - `HANDSHAKING` - `AUTHENTICATED` - `BOOTSTRAPPING` - `READY` - `DEVICE_VERIFICATION_REQUIRED` ```mermaid stateDiagram-v2 [*] --> DISCONNECTED DISCONNECTED --> CONNECTING CONNECTING --> HANDSHAKING HANDSHAKING --> DEVICE_VERIFICATION_REQUIRED HANDSHAKING --> AUTHENTICATED AUTHENTICATED --> BOOTSTRAPPING BOOTSTRAPPING --> READY READY --> DISCONNECTED DEVICE_VERIFICATION_REQUIRED --> CONNECTING ``` --- ## 10. Ключевые файлы новой архитектуры - `app/src/main/java/com/rosetta/messenger/di/AppContainer.kt` - `app/src/main/java/com/rosetta/messenger/di/UiEntryPoint.kt` - `app/src/main/java/com/rosetta/messenger/network/ProtocolRuntime.kt` - `app/src/main/java/com/rosetta/messenger/network/ProtocolRuntimeCore.kt` - `app/src/main/java/com/rosetta/messenger/network/ProtocolClient.kt` - `app/src/main/java/com/rosetta/messenger/network/ProtocolRuntimeAccess.kt` - `app/src/main/java/com/rosetta/messenger/session/AppSessionCoordinator.kt` - `app/src/main/java/com/rosetta/messenger/session/SessionStore.kt` - `app/src/main/java/com/rosetta/messenger/session/SessionReducer.kt` - `app/src/main/java/com/rosetta/messenger/session/SessionAction.kt` - `app/src/main/java/com/rosetta/messenger/session/IdentityStore.kt` - `app/src/main/java/com/rosetta/messenger/network/ProtocolManager.kt` - `app/src/main/java/com/rosetta/messenger/network/PacketSubscriptionRegistry.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/connection/ConnectionOrchestrator.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/BootstrapCoordinator.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/SyncCoordinator.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/PresenceTypingService.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/AuthBootstrapCoordinator.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/NetworkReconnectWatcher.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/DeviceVerificationService.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/DeviceRuntimeService.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/CallSignalBridge.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/OutgoingMessagePipelineService.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/PacketRouter.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/OwnProfileSyncService.kt` - `app/src/main/java/com/rosetta/messenger/network/connection/RetryQueueService.kt` - `app/src/main/java/com/rosetta/messenger/ui/chats/usecase/SendTextMessageUseCase.kt` - `app/src/main/java/com/rosetta/messenger/ui/chats/usecase/SendMediaMessageUseCase.kt` - `app/src/main/java/com/rosetta/messenger/ui/chats/usecase/SendForwardUseCase.kt` --- ## 11. Что осталось как технический долг - `ProtocolRuntimeCore` все еще содержит много cross-cutting логики и требует дальнейшей декомпозиции. - UI больше не использует `UiDependencyAccess.get(...)`, но часть экранов все еще берет зависимости через `UiEntryPoint` (следующий шаг: передача зависимостей параметрами/через VM). - DI-адаптеры (`ProtocolGatewayImpl`, `ProtocolClientImpl`) переведены на `ProtocolRuntime`, dependency-cycle закрыт через `Provider`. - Следующий шаг по network core: продолжить декомпозицию `ProtocolRuntimeCore` (например: `ProtocolLifecycleLogger`, `AuthRestoreService`, `ProtocolTraceService`) и сократить фасад `ProtocolManager` до полного legacy-режима.