refactor(core:service): Use MeshServiceOrchestrator to abstract service wiring

This commit is contained in:
James Rich 2026-03-17 11:06:40 -05:00
parent 26f9c50127
commit a85e282824
4 changed files with 61 additions and 22 deletions

View file

@ -12,10 +12,10 @@
- [x] Task: Move Android `Service` implementations to `core:service/androidMain` [965def0]
- [x] Move the files
- [x] Update imports and Koin injections
- [ ] Task: Abstract shared service logic into `core:service/commonMain`
- [ ] Write failing tests for abstracted shared logic (TDD Red)
- [ ] Extract interfaces and platform-agnostic logic (TDD Green)
- [ ] Refactor the implementations to use these shared abstractions
- [~] Task: Abstract shared service logic into `core:service/commonMain`
- [x] Write failing tests for abstracted shared logic (TDD Red)
- [x] Extract interfaces and platform-agnostic logic (TDD Green)
- [x] Refactor the implementations to use these shared abstractions
- [ ] Task: Conductor - User Manual Verification 'Extraction to core:service' (Protocol in workflow.md)
## Phase 3: Extraction to `core:network`

View file

@ -78,7 +78,7 @@ class MeshService : Service() {
private val connectionManager: MeshConnectionManager by inject()
private val serviceNotifications: MeshServiceNotifications by inject()
private val orchestrator: MeshServiceOrchestrator by inject()
private val router: MeshRouter by inject()
@ -121,24 +121,8 @@ class MeshService : Service() {
throw e
}
Logger.i { "Creating mesh service" }
serviceNotifications.initChannels()
packetHandler.start(serviceScope)
router.start(serviceScope)
nodeManager.start(serviceScope)
connectionManager.start(serviceScope)
messageProcessor.start(serviceScope)
commandSender.start(serviceScope)
serviceScope.handledLaunch { radioInterfaceService.connect() }
radioInterfaceService.receivedData
.onEach { bytes -> messageProcessor.handleFromRadio(bytes, nodeManager.myNodeNum) }
.launchIn(serviceScope)
serviceRepository.serviceAction.onEach(router.actionHandler::onServiceAction).launchIn(serviceScope)
nodeManager.loadCachedNodeDB()
orchestrator.start()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@ -207,6 +191,7 @@ class MeshService : Service() {
override fun onDestroy() {
Logger.i { "Destroying mesh service" }
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
orchestrator.stop()
serviceJob.cancel()
super.onDestroy()
}

View file

@ -22,6 +22,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.koin.core.annotation.Single
import org.meshtastic.core.common.util.handledLaunch
import org.meshtastic.core.repository.CommandSender
import org.meshtastic.core.repository.MeshConnectionManager
@ -42,6 +43,7 @@ import org.meshtastic.core.repository.ServiceRepository
* All injected dependencies are `commonMain` interfaces with real implementations in `core:data`.
*/
@Suppress("LongParameterList")
@Single
class MeshServiceOrchestrator(
private val radioInterfaceService: RadioInterfaceService,
private val serviceRepository: ServiceRepository,

View file

@ -0,0 +1,52 @@
package org.meshtastic.core.service
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlin.test.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.meshtastic.core.repository.*
class MeshServiceOrchestratorTest {
@Test
fun testStartWiresComponents() {
val radioInterfaceService = mockk<RadioInterfaceService>(relaxed = true)
val serviceRepository = mockk<ServiceRepository>(relaxed = true)
val packetHandler = mockk<PacketHandler>(relaxed = true)
val nodeManager = mockk<NodeManager>(relaxed = true)
val messageProcessor = mockk<MeshMessageProcessor>(relaxed = true)
val commandSender = mockk<CommandSender>(relaxed = true)
val connectionManager = mockk<MeshConnectionManager>(relaxed = true)
val router = mockk<MeshRouter>(relaxed = true)
val serviceNotifications = mockk<MeshServiceNotifications>(relaxed = true)
every { radioInterfaceService.receivedData } returns MutableSharedFlow()
every { serviceRepository.serviceAction } returns MutableSharedFlow()
val orchestrator = MeshServiceOrchestrator(
radioInterfaceService,
serviceRepository,
packetHandler,
nodeManager,
messageProcessor,
commandSender,
connectionManager,
router,
serviceNotifications
)
assertFalse(orchestrator.isRunning)
orchestrator.start()
assertTrue(orchestrator.isRunning)
verify { serviceNotifications.initChannels() }
verify { packetHandler.start(any()) }
verify { nodeManager.loadCachedNodeDB() }
orchestrator.stop()
assertFalse(orchestrator.isRunning)
}
}