core:service is the central app-orchestration layer: MeshServiceOrchestrator
is constructed by both androidApp's MeshService.kt and desktopApp's
Main.kt, and will be needed by a future web client too -- it can't be
wholesale-excluded the way a leaf feature could be.
Its only web-hostile dependency was two constructor parameters typed
directly against core:takserver: TAKServerManager (already an
interface) and TAKMeshIntegration (a concrete class). core:takserver
can never get a wasmJs target -- its production implementation is a
TLS SSLServerSocket *listener* accepting inbound ATAK/iTAK
connections, and a browser sandbox can never accept inbound
connections at all, a more fundamental impossibility than the
outbound-only TCP case already excluded for MQTT.
MeshServiceOrchestrator only ever read takServerManager.isRunning and
called takMeshIntegration.start()/stop() -- the entire interaction
surface. Following this codebase's own convention (core:repository
hosts portable interfaces, core:*Impl-style modules hold the
platform-coupled implementation), a new minimal TakServerIntegration
interface in core:repository folds those three members into one seam.
TAKMeshIntegration now implements it directly; isRunning delegates to
the real takServerManager.isRunning (its own internal start/stop
re-entrancy latch, previously also named isRunning, is renamed to
isRunningState to keep the two states distinct). Its Koin provider
binds under both types (`@Single(binds = [TAKMeshIntegration::class,
TakServerIntegration::class])`) so feature/settings' debug UI still
resolves the concrete class while core:service resolves only the
interface -- verified sound against Koin's own K2-compiler-plugin
binding model via a real KoinVerificationTest run, not assumed.
core:service's dependency on core:takserver is removed entirely
(confirmed via grep: nothing else in the module referenced it).
wasmJs gets a real, honest no-op TakServerIntegration -- isRunning
always false, start/stop are no-ops -- documented as a permanent
platform impossibility, not a stand-in for future work.
androidApp/desktopApp needed zero changes: both already register
core:takserver's own Koin module directly, which still supplies the
real implementation there.
Three of six commonTest files move to a new nonWebTest source set,
for two unrelated, both-confirmed-empirically reasons:
SharedRadioInterfaceServiceLivenessTest.kt depends on core:testing (no
wasmJs target, the same gap every KMP module's test suite has hit this
session); RadioControllerImplTest.kt and RadioControllerRestoreTest.kt
crash the Kotlin/Wasm compiler ("Serialization of IrErrorType is not
supported anymore") when constructing a real RadioControllerImpl --
bisected to exactly these two files, which both differ from the four
that pass by constructing that class (interface delegation via `by`
plus Lazy<T> constructor params) -- a genuine backend limitation, not
a library gap, logged as deferred rather than worked around.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
:core:service
Overview
Targets: Android · JVM (Desktop) · iOS
The :core:service module contains the abstractions and client-side logic for interacting with the main Meshtastic Android Service.
Key Components
1. MeshService
Android foreground service entry point that hosts the orchestrator lifecycle.
2. ServiceRepository
A high-level repository that wraps the service connection and exposes reactive Flows for connection status and data arrival.
3. ConnectionState
Represents the current state of the radio connection (Connected, Disconnected, DeviceSleep, etc.).
4. RadioControllerImpl
The in-process RadioController composition root (Desktop, iOS, and single-process Android). It assembles four focused sub-controllers — AdminControllerImpl, MessagingControllerImpl, NodeControllerImpl, QueryControllerImpl — via Kotlin interface delegation, and owns the cross-cutting concerns (connection state, packet-id, location, device-address switching). Commands are direct suspend calls to CommandSender; admin sends are fire-and-forget (the device is the source of truth). Config writes use the editSettings { } transaction.
Dependency Graph
graph TB
:core:service[service]:::kmp-library
:core:service --> :core:repository
:core:service -.-> :core:common
:core:service -.-> :core:data
:core:service -.-> :core:database
:core:service -.-> :core:di
:core:service -.-> :core:model
:core:service -.-> :core:navigation
:core:service -.-> :core:network
:core:service -.-> :core:ble
:core:service -.-> :core:prefs
:core:service -.-> :core:resources
:core:service -.-> :core:takserver
:core:service -.-> :core:testing
classDef android-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-application-compose fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef compose-desktop-application fill:#CAFFBF,stroke:#000,stroke-width:2px,color:#000;
classDef android-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef android-library fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-library-compose fill:#9BF6FF,stroke:#000,stroke-width:2px,color:#000;
classDef android-test fill:#A0C4FF,stroke:#000,stroke-width:2px,color:#000;
classDef jvm-library fill:#BDB2FF,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-feature fill:#FFD6A5,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library-compose fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef kmp-library fill:#FFC1CC,stroke:#000,stroke-width:2px,color:#000;
classDef unknown fill:#FFADAD,stroke:#000,stroke-width:2px,color:#000;