mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor(desktop): Use common MeshServiceOrchestrator in desktop app
This commit is contained in:
parent
e04787d033
commit
f39df2f4bb
4 changed files with 5 additions and 129 deletions
|
|
@ -29,9 +29,9 @@
|
||||||
- [x] Task: Conductor - User Manual Verification 'Extraction to core:network' (Protocol in workflow.md)
|
- [x] Task: Conductor - User Manual Verification 'Extraction to core:network' (Protocol in workflow.md)
|
||||||
|
|
||||||
## Phase 4: Desktop Integration
|
## Phase 4: Desktop Integration
|
||||||
- [ ] Task: Integrate newly extracted shared abstractions into the `desktop` module
|
- [x] Task: Integrate newly extracted shared abstractions into the `desktop` module
|
||||||
- [ ] Implement desktop-specific actuals or Koin bindings for the shared interfaces
|
- [x] Implement desktop-specific actuals or Koin bindings for the shared interfaces
|
||||||
- [ ] Wire up abstracted services/radio logic in desktop Koin graph
|
- [x] Wire up abstracted services/radio logic in desktop Koin graph
|
||||||
- [ ] Task: Conductor - User Manual Verification 'Desktop Integration' (Protocol in workflow.md)
|
- [ ] Task: Conductor - User Manual Verification 'Desktop Integration' (Protocol in workflow.md)
|
||||||
|
|
||||||
## Phase 5: Verification & Cleanup
|
## Phase 5: Verification & Cleanup
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ import org.meshtastic.core.ui.theme.AppTheme
|
||||||
import org.meshtastic.desktop.data.DesktopPreferencesDataSource
|
import org.meshtastic.desktop.data.DesktopPreferencesDataSource
|
||||||
import org.meshtastic.desktop.di.desktopModule
|
import org.meshtastic.desktop.di.desktopModule
|
||||||
import org.meshtastic.desktop.di.desktopPlatformModule
|
import org.meshtastic.desktop.di.desktopPlatformModule
|
||||||
import org.meshtastic.desktop.radio.DesktopMeshServiceController
|
import org.meshtastic.core.service.MeshServiceOrchestrator
|
||||||
import org.meshtastic.desktop.ui.DesktopMainScreen
|
import org.meshtastic.desktop.ui.DesktopMainScreen
|
||||||
import org.meshtastic.desktop.ui.navSavedStateConfig
|
import org.meshtastic.desktop.ui.navSavedStateConfig
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
@ -82,7 +82,7 @@ fun main() = application(exitProcessOnExit = false) {
|
||||||
val systemLocale = remember { Locale.getDefault() }
|
val systemLocale = remember { Locale.getDefault() }
|
||||||
|
|
||||||
// Start the mesh service processing chain (desktop equivalent of Android's MeshService)
|
// Start the mesh service processing chain (desktop equivalent of Android's MeshService)
|
||||||
val meshServiceController = remember { koinApp.koin.get<DesktopMeshServiceController>() }
|
val meshServiceController = remember { koinApp.koin.get<MeshServiceOrchestrator>() }
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
meshServiceController.start()
|
meshServiceController.start()
|
||||||
onDispose { meshServiceController.stop() }
|
onDispose { meshServiceController.stop() }
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,6 @@ import org.meshtastic.core.repository.PlatformAnalytics
|
||||||
import org.meshtastic.core.repository.RadioInterfaceService
|
import org.meshtastic.core.repository.RadioInterfaceService
|
||||||
import org.meshtastic.core.repository.ServiceBroadcasts
|
import org.meshtastic.core.repository.ServiceBroadcasts
|
||||||
import org.meshtastic.core.repository.ServiceRepository
|
import org.meshtastic.core.repository.ServiceRepository
|
||||||
import org.meshtastic.desktop.radio.DesktopMeshServiceController
|
|
||||||
import org.meshtastic.desktop.radio.DesktopRadioInterfaceService
|
import org.meshtastic.desktop.radio.DesktopRadioInterfaceService
|
||||||
import org.meshtastic.desktop.stub.NoopAppWidgetUpdater
|
import org.meshtastic.desktop.stub.NoopAppWidgetUpdater
|
||||||
import org.meshtastic.desktop.stub.NoopCompassHeadingProvider
|
import org.meshtastic.desktop.stub.NoopCompassHeadingProvider
|
||||||
|
|
@ -151,19 +150,6 @@ private fun desktopPlatformStubsModule() = module {
|
||||||
single<org.meshtastic.feature.node.compass.MagneticFieldProvider> { NoopMagneticFieldProvider() }
|
single<org.meshtastic.feature.node.compass.MagneticFieldProvider> { NoopMagneticFieldProvider() }
|
||||||
|
|
||||||
// Desktop mesh service controller — replaces Android's MeshService lifecycle
|
// Desktop mesh service controller — replaces Android's MeshService lifecycle
|
||||||
single {
|
|
||||||
DesktopMeshServiceController(
|
|
||||||
radioInterfaceService = get(),
|
|
||||||
serviceRepository = get(),
|
|
||||||
messageProcessor = get(),
|
|
||||||
connectionManager = get(),
|
|
||||||
packetHandler = get(),
|
|
||||||
router = get(),
|
|
||||||
nodeManager = get(),
|
|
||||||
commandSender = get(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ktor HttpClient for JVM/Desktop (equivalent of CoreNetworkAndroidModule on Android)
|
// Ktor HttpClient for JVM/Desktop (equivalent of CoreNetworkAndroidModule on Android)
|
||||||
single<HttpClient> { HttpClient(Java) { install(ContentNegotiation) { json(get<Json>()) } } }
|
single<HttpClient> { HttpClient(Java) { install(ContentNegotiation) { json(get<Json>()) } } }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,110 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package org.meshtastic.desktop.radio
|
|
||||||
|
|
||||||
import co.touchlab.kermit.Logger
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.SupervisorJob
|
|
||||||
import kotlinx.coroutines.cancel
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import org.meshtastic.core.common.util.handledLaunch
|
|
||||||
import org.meshtastic.core.repository.CommandSender
|
|
||||||
import org.meshtastic.core.repository.MeshConnectionManager
|
|
||||||
import org.meshtastic.core.repository.MeshMessageProcessor
|
|
||||||
import org.meshtastic.core.repository.MeshRouter
|
|
||||||
import org.meshtastic.core.repository.NodeManager
|
|
||||||
import org.meshtastic.core.repository.PacketHandler
|
|
||||||
import org.meshtastic.core.repository.RadioInterfaceService
|
|
||||||
import org.meshtastic.core.repository.ServiceRepository
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Desktop equivalent of Android's `MeshService.onCreate()`.
|
|
||||||
*
|
|
||||||
* Starts the full message-processing chain that connects the radio transport layer to the business logic:
|
|
||||||
* ```
|
|
||||||
* radioInterfaceService.receivedData
|
|
||||||
* → messageProcessor.handleFromRadio(bytes, myNodeNum)
|
|
||||||
* → FromRadioPacketHandler → MeshRouter/PacketHandler/etc.
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* On Android this chain runs inside an Android `Service` (foreground service with notifications). On Desktop there is
|
|
||||||
* no Android Service concept, so this controller manages the same lifecycle in-process, started at app launch time.
|
|
||||||
*/
|
|
||||||
@Suppress("LongParameterList")
|
|
||||||
class DesktopMeshServiceController(
|
|
||||||
private val radioInterfaceService: RadioInterfaceService,
|
|
||||||
private val serviceRepository: ServiceRepository,
|
|
||||||
private val messageProcessor: MeshMessageProcessor,
|
|
||||||
private val connectionManager: MeshConnectionManager,
|
|
||||||
private val packetHandler: PacketHandler,
|
|
||||||
private val router: MeshRouter,
|
|
||||||
private val nodeManager: NodeManager,
|
|
||||||
private val commandSender: CommandSender,
|
|
||||||
) {
|
|
||||||
private var serviceScope: CoroutineScope? = null
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the mesh service processing chain.
|
|
||||||
*
|
|
||||||
* This should be called once at application startup (after Koin is initialized). It mirrors the initialization
|
|
||||||
* logic from `MeshService.onCreate()`.
|
|
||||||
*/
|
|
||||||
@Suppress("InjectDispatcher")
|
|
||||||
fun start() {
|
|
||||||
if (serviceScope != null) {
|
|
||||||
Logger.w { "DesktopMeshServiceController: Already started, ignoring duplicate start()" }
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.i { "DesktopMeshServiceController: Starting mesh service processing chain" }
|
|
||||||
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
|
||||||
serviceScope = scope
|
|
||||||
|
|
||||||
// Start all processing components (same order as MeshService.onCreate)
|
|
||||||
packetHandler.start(scope)
|
|
||||||
router.start(scope)
|
|
||||||
nodeManager.start(scope)
|
|
||||||
connectionManager.start(scope)
|
|
||||||
messageProcessor.start(scope)
|
|
||||||
commandSender.start(scope)
|
|
||||||
|
|
||||||
// Auto-connect to saved device address (mirrors MeshService.onCreate)
|
|
||||||
scope.handledLaunch { radioInterfaceService.connect() }
|
|
||||||
|
|
||||||
// Wire the data flow: radio → message processor
|
|
||||||
radioInterfaceService.receivedData
|
|
||||||
.onEach { bytes -> messageProcessor.handleFromRadio(bytes, nodeManager.myNodeNum) }
|
|
||||||
.launchIn(scope)
|
|
||||||
|
|
||||||
// Wire service actions to the router
|
|
||||||
serviceRepository.serviceAction.onEach(router.actionHandler::onServiceAction).launchIn(scope)
|
|
||||||
|
|
||||||
// Load any cached node database
|
|
||||||
nodeManager.loadCachedNodeDB()
|
|
||||||
|
|
||||||
Logger.i { "DesktopMeshServiceController: Processing chain started" }
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Stops the mesh service processing chain and cancels all coroutines. */
|
|
||||||
fun stop() {
|
|
||||||
Logger.i { "DesktopMeshServiceController: Stopping" }
|
|
||||||
serviceScope?.cancel("DesktopMeshServiceController stopped")
|
|
||||||
serviceScope = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue