Skip to content

Commit

Permalink
refactor: ensure node database flows on IO thread
Browse files Browse the repository at this point in the history
  • Loading branch information
andrekir committed Nov 26, 2024
1 parent 1d1b2bc commit 174a4d0
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,38 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.geeksville.mesh.model
package com.geeksville.mesh.database

import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.geeksville.mesh.CoroutineDispatchers
import com.geeksville.mesh.DataPacket
import com.geeksville.mesh.MeshProtos
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import kotlinx.coroutines.Dispatchers
import com.geeksville.mesh.model.NodeSortOption
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class NodeDB @Inject constructor(
class NodeRepository @Inject constructor(
processLifecycle: Lifecycle,
private val nodeInfoDao: NodeInfoDao,
private val dispatchers: CoroutineDispatchers,
) {
// hardware info about our local device (can be null)
private val _myNodeInfo = MutableStateFlow<MyNodeEntity?>(null)
val myNodeInfo: StateFlow<MyNodeEntity?> get() = _myNodeInfo
val myNodeInfo: StateFlow<MyNodeEntity?> = nodeInfoDao.getMyNodeInfo()
.flowOn(dispatchers.io)
.stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, null)

// our node info
private val _ourNodeInfo = MutableStateFlow<NodeEntity?>(null)
Expand All @@ -51,8 +57,15 @@ class NodeDB @Inject constructor(
val myId: StateFlow<String?> get() = _myId

// A map from nodeNum to NodeEntity
private val _nodeDBbyNum = MutableStateFlow<Map<Int, NodeEntity>>(mapOf())
val nodeDBbyNum: StateFlow<Map<Int, NodeEntity>> get() = _nodeDBbyNum
val nodeDBbyNum: StateFlow<Map<Int, NodeEntity>> = nodeInfoDao.nodeDBbyNum()
.onEach {
val ourNodeInfo = it.values.firstOrNull()
_ourNodeInfo.value = ourNodeInfo
_myId.value = ourNodeInfo?.user?.id
}
.flowOn(dispatchers.io)
.conflate()
.stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, emptyMap())

fun getUser(nodeNum: Int): MeshProtos.User = getUser(DataPacket.nodeNumToDefaultId(nodeNum))

Expand All @@ -65,18 +78,6 @@ class NodeDB @Inject constructor(
.setHwModel(MeshProtos.HardwareModel.UNSET)
.build()

init {
nodeInfoDao.getMyNodeInfo().onEach { _myNodeInfo.value = it }
.launchIn(processLifecycle.coroutineScope)

nodeInfoDao.nodeDBbyNum().onEach {
_nodeDBbyNum.value = it
val ourNodeInfo = it.values.firstOrNull()
_ourNodeInfo.value = ourNodeInfo
_myId.value = ourNodeInfo?.user?.id
}.launchIn(processLifecycle.coroutineScope)
}

fun getNodes(
sort: NodeSortOption = NodeSortOption.LAST_HEARD,
filter: String = "",
Expand All @@ -85,20 +86,20 @@ class NodeDB @Inject constructor(
sort = sort.sqlValue,
filter = filter,
includeUnknown = includeUnknown,
)
).flowOn(dispatchers.io).conflate()

suspend fun upsert(node: NodeEntity) = withContext(Dispatchers.IO) {
suspend fun upsert(node: NodeEntity) = withContext(dispatchers.io) {
nodeInfoDao.upsert(node)
}

suspend fun installNodeDB(mi: MyNodeEntity, nodes: List<NodeEntity>) = withContext(Dispatchers.IO) {
suspend fun installNodeDB(mi: MyNodeEntity, nodes: List<NodeEntity>) = withContext(dispatchers.io) {
nodeInfoDao.clearMyNodeInfo()
nodeInfoDao.setMyNodeInfo(mi) // set MyNodeEntity first
nodeInfoDao.clearNodeInfo()
nodeInfoDao.putAll(nodes)
}

suspend fun deleteNode(num: Int) = withContext(Dispatchers.IO) {
suspend fun deleteNode(num: Int) = withContext(dispatchers.io) {
nodeInfoDao.deleteNode(num)
}
}
3 changes: 2 additions & 1 deletion app/src/main/java/com/geeksville/mesh/model/UIState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import com.geeksville.mesh.channelSettings
import com.geeksville.mesh.config
import com.geeksville.mesh.copy
import com.geeksville.mesh.database.MeshLogRepository
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.PacketRepository
import com.geeksville.mesh.database.QuickChatActionRepository
import com.geeksville.mesh.database.entity.MyNodeEntity
Expand Down Expand Up @@ -165,7 +166,7 @@ data class Contact(
@HiltViewModel
class UIViewModel @Inject constructor(
private val app: Application,
private val nodeDB: NodeDB,
private val nodeDB: NodeRepository,
private val radioConfigRepository: RadioConfigRepository,
private val radioInterfaceService: RadioInterfaceService,
private val meshLogRepository: MeshLogRepository,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import com.geeksville.mesh.ModuleConfigProtos.ModuleConfig
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.deviceProfile
import com.geeksville.mesh.model.NodeDB
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.model.getChannelUrl
import com.geeksville.mesh.service.MeshService.ConnectionState
import com.geeksville.mesh.service.ServiceAction
Expand All @@ -48,7 +48,7 @@ import javax.inject.Inject
*/
class RadioConfigRepository @Inject constructor(
private val serviceRepository: ServiceRepository,
private val nodeDB: NodeDB,
private val nodeDB: NodeRepository,
private val channelSetRepository: ChannelSetRepository,
private val localConfigRepository: LocalConfigRepository,
private val moduleConfigRepository: ModuleConfigRepository,
Expand Down

0 comments on commit 174a4d0

Please sign in to comment.