From 5b4308939231a8df8b9fe5c645f8cad0b437eb33 Mon Sep 17 00:00:00 2001 From: andrekir Date: Sun, 7 Apr 2024 19:50:27 -0300 Subject: [PATCH] refactor: simplify `RadioConfigViewModel` packet processing --- .../mesh/model/RadioConfigViewModel.kt | 29 +++++++------------ .../datastore/RadioConfigRepository.kt | 9 ++++++ .../geeksville/mesh/service/MeshService.kt | 4 +++ .../mesh/service/ServiceRepository.kt | 10 +++++++ 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/model/RadioConfigViewModel.kt b/app/src/main/java/com/geeksville/mesh/model/RadioConfigViewModel.kt index 6e4adc9d5..3054c2286 100644 --- a/app/src/main/java/com/geeksville/mesh/model/RadioConfigViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/model/RadioConfigViewModel.kt @@ -18,8 +18,6 @@ import com.geeksville.mesh.Portnums import com.geeksville.mesh.Position import com.geeksville.mesh.android.Logging import com.geeksville.mesh.config -import com.geeksville.mesh.database.MeshLogRepository -import com.geeksville.mesh.database.entity.MeshLog import com.geeksville.mesh.deviceProfile import com.geeksville.mesh.moduleConfig import com.geeksville.mesh.repository.datastore.RadioConfigRepository @@ -30,7 +28,6 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -58,7 +55,6 @@ data class RadioConfigState( class RadioConfigViewModel @Inject constructor( private val app: Application, private val radioConfigRepository: RadioConfigRepository, - meshLogRepository: MeshLogRepository, ) : ViewModel(), Logging { private var destNum: Int = 0 @@ -73,7 +69,7 @@ class RadioConfigViewModel @Inject constructor( val myNodeInfo: StateFlow get() = radioConfigRepository.myNodeInfo val ourNodeInfo: StateFlow get() = radioConfigRepository.ourNodeInfo - private val requestIds = MutableStateFlow>(hashMapOf()) + private val requestIds = MutableStateFlow(hashSetOf()) private val _radioConfigState = MutableStateFlow(RadioConfigState()) val radioConfigState: StateFlow = _radioConfigState @@ -85,12 +81,9 @@ class RadioConfigViewModel @Inject constructor( _currentDeviceProfile.value = it }.launchIn(viewModelScope) - viewModelScope.launch { - combine(meshLogRepository.getAllLogs(9), requestIds) { list, ids -> - val unprocessed = ids.filterValues { !it }.keys.ifEmpty { return@combine emptyList() } - list.filter { log -> log.meshPacket?.decoded?.requestId in unprocessed } - }.collect { it.forEach(::processPacketResponse) } - } + radioConfigRepository.meshPacketFlow.onEach(::processPacketResponse) + .launchIn(viewModelScope) + debug("RadioConfigViewModel created") } @@ -112,7 +105,7 @@ class RadioConfigViewModel @Inject constructor( val packetId = service.packetId try { requestAction(service, packetId, destNum) - requestIds.update { it.apply { put(packetId, false) } } + requestIds.update { it.apply { add(packetId) } } _radioConfigState.update { state -> if (state.responseState is ResponseState.Loading) { val total = maxOf(requestIds.value.size, state.responseState.total) @@ -362,7 +355,7 @@ class RadioConfigViewModel @Inject constructor( } fun clearPacketResponse() { - requestIds.value = hashMapOf() + requestIds.value = hashSetOf() _radioConfigState.update { it.copy(responseState = ResponseState.Empty) } } @@ -411,9 +404,9 @@ class RadioConfigViewModel @Inject constructor( } } - private fun processPacketResponse(log: MeshLog?) { - val packet = log?.meshPacket ?: return + private fun processPacketResponse(packet: MeshProtos.MeshPacket) { val data = packet.decoded + if (data.requestId !in requestIds.value) return val route = radioConfigState.value.route // val destNum = destNode.value?.num ?: return @@ -426,8 +419,8 @@ class RadioConfigViewModel @Inject constructor( if (parsed.errorReason != MeshProtos.Routing.Error.NONE) { setResponseStateError(parsed.errorReason.name) } else if (packet.from == destNum && route.isEmpty()) { - requestIds.update { it.apply { put(data.requestId, true) } } - if (requestIds.value.filterValues { !it }.isEmpty()) setResponseStateSuccess() + requestIds.update { it.apply { remove(data.requestId) } } + if (requestIds.value.isEmpty()) setResponseStateSuccess() else incrementCompleted() } } @@ -498,7 +491,7 @@ class RadioConfigViewModel @Inject constructor( else -> TODO() } - requestIds.update { it.apply { put(data.requestId, true) } } + requestIds.update { it.apply { remove(data.requestId) } } } } } diff --git a/app/src/main/java/com/geeksville/mesh/repository/datastore/RadioConfigRepository.kt b/app/src/main/java/com/geeksville/mesh/repository/datastore/RadioConfigRepository.kt index d1163dfee..507464957 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/datastore/RadioConfigRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/datastore/RadioConfigRepository.kt @@ -8,6 +8,7 @@ import com.geeksville.mesh.ConfigProtos.Config import com.geeksville.mesh.IMeshService import com.geeksville.mesh.LocalOnlyProtos.LocalConfig import com.geeksville.mesh.LocalOnlyProtos.LocalModuleConfig +import com.geeksville.mesh.MeshProtos.MeshPacket import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig import com.geeksville.mesh.MyNodeInfo import com.geeksville.mesh.NodeInfo @@ -16,7 +17,9 @@ import com.geeksville.mesh.model.NodeDB import com.geeksville.mesh.model.getChannelUrl import com.geeksville.mesh.service.MeshService.ConnectionState import com.geeksville.mesh.service.ServiceRepository +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.firstOrNull @@ -167,6 +170,12 @@ class RadioConfigRepository @Inject constructor( serviceRepository.clearErrorMessage() } + val meshPacketFlow: SharedFlow get() = serviceRepository.meshPacketFlow + + suspend fun emitMeshPacket(packet: MeshPacket) = coroutineScope { + serviceRepository.emitMeshPacket(packet) + } + val tracerouteResponse: StateFlow get() = serviceRepository.tracerouteResponse fun setTracerouteResponse(value: String?) { diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index 224ba5450..3455b81d5 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -997,6 +997,10 @@ class MeshService : Service(), Logging { ) insertMeshLog(packetToSave) + serviceScope.handledLaunch { + radioConfigRepository.emitMeshPacket(packet) + } + // Update last seen for the node that sent the packet, but also for _our node_ because anytime a packet passes // through our node on the way to the phone that means that local node is also alive in the mesh diff --git a/app/src/main/java/com/geeksville/mesh/service/ServiceRepository.kt b/app/src/main/java/com/geeksville/mesh/service/ServiceRepository.kt index ab544ab72..ab63704d8 100644 --- a/app/src/main/java/com/geeksville/mesh/service/ServiceRepository.kt +++ b/app/src/main/java/com/geeksville/mesh/service/ServiceRepository.kt @@ -1,8 +1,11 @@ package com.geeksville.mesh.service import com.geeksville.mesh.IMeshService +import com.geeksville.mesh.MeshProtos.MeshPacket import com.geeksville.mesh.android.Logging +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import javax.inject.Inject import javax.inject.Singleton @@ -39,6 +42,13 @@ class ServiceRepository @Inject constructor() : Logging { _errorMessage.value = null } + private val _meshPacketFlow = MutableSharedFlow() + val meshPacketFlow: SharedFlow get() = _meshPacketFlow + + suspend fun emitMeshPacket(packet: MeshPacket) { + _meshPacketFlow.emit(packet) + } + private val _tracerouteResponse = MutableStateFlow(null) val tracerouteResponse: StateFlow get() = _tracerouteResponse