Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(config): implement excluded modules validation #1460

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
564 changes: 564 additions & 0 deletions app/schemas/com.geeksville.mesh.database.MeshtasticDatabase/16.json

Large diffs are not rendered by default.

29 changes: 22 additions & 7 deletions app/src/androidTest/java/com/geeksville/mesh/NodeInfoDaoTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import com.geeksville.mesh.database.MeshtasticDatabase
import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.NodeSortOption
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertEquals
Expand All @@ -40,6 +42,18 @@ class NodeInfoDaoTest {
private lateinit var database: MeshtasticDatabase
private lateinit var nodeInfoDao: NodeInfoDao

private val unknownNode = NodeEntity(
num = 7,
user = user {
id = "!a1b2c3d4"
longName = "Meshtastic c3d4"
shortName = "c3d4"
hwModel = MeshProtos.HardwareModel.UNSET
},
longName = "Meshtastic c3d4",
shortName = null // Dao filter for includeUnknown
)

private val ourNode = NodeEntity(
num = 8,
user = user {
Expand Down Expand Up @@ -79,7 +93,7 @@ class NodeInfoDaoTest {
39.952583 to -75.165222, // Philadelphia
)

private val testNodes = listOf(ourNode) + testPositions.mapIndexed { index, pos ->
private val testNodes = listOf(ourNode, unknownNode) + testPositions.mapIndexed { index, pos ->
NodeEntity(
num = 9 + index,
user = user {
Expand All @@ -89,7 +103,7 @@ class NodeInfoDaoTest {
hwModel = MeshProtos.HardwareModel.ANDROID_SIM
isLicensed = false
},
longName = "Kevin Mester$index", shortName = if (index == 2) null else "KM$index",
longName = "Kevin Mester$index", shortName = "KM$index",
latitude = pos.first, longitude = pos.second,
lastHeard = 9 + index,
)
Expand Down Expand Up @@ -124,18 +138,18 @@ class NodeInfoDaoTest {
sort = sort.sqlValue,
filter = filter,
includeUnknown = includeUnknown,
).first().filter { it != ourNode }
).map { list -> list.map { it.toModel() } }.first().filter { it.num != ourNode.num }

@Test // node list size
fun testNodeListSize() = runBlocking {
val nodes = nodeInfoDao.nodeDBbyNum().first()
assertEquals(11, nodes.size)
assertEquals(12, nodes.size)
}

@Test // nodeDBbyNum() re-orders our node at the top of the list
fun testOurNodeInfoIsFirst() = runBlocking {
val nodes = nodeInfoDao.nodeDBbyNum().first()
assertEquals(ourNode, nodes.values.first())
assertEquals(ourNode.num, nodes.values.first().node.num)
}

@Test
Expand All @@ -155,8 +169,9 @@ class NodeInfoDaoTest {
@Test
fun testSortByDistance() = runBlocking {
val nodes = getNodes(sort = NodeSortOption.DISTANCE)
fun NodeEntity.toNode() = Node(num = num, user = user, position = position)
val sortedNodes = nodes.sortedWith( // nodes with invalid (null) positions at the end
compareBy<NodeEntity> { it.validPosition == null }.thenBy { it.distance(ourNode) }
compareBy<Node> { it.validPosition == null }.thenBy { it.distance(ourNode.toNode()) }
)
assertEquals(sortedNodes, nodes)
}
Expand Down Expand Up @@ -185,7 +200,7 @@ class NodeInfoDaoTest {
@Test
fun testIncludeUnknownIsTrue() = runBlocking {
val nodes = getNodes(includeUnknown = true)
val containsUnsetNode = nodes.any { it.shortName == null }
val containsUnsetNode = nodes.any { it.isUnknownUser }
assertTrue(containsUnsetNode)
}
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/geeksville/mesh/database/Converters.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,19 @@ class Converters : Logging {
fun paxCounterToBytes(value: PaxcountProtos.Paxcount): ByteArray? {
return value.toByteArray()
}

@TypeConverter
fun bytesToMetadata(bytes: ByteArray): MeshProtos.DeviceMetadata {
return try {
MeshProtos.DeviceMetadata.parseFrom(bytes)
} catch (ex: InvalidProtocolBufferException) {
errormsg("bytesToMetadata TypeConverter error:", ex)
MeshProtos.DeviceMetadata.getDefaultInstance()
}
}

@TypeConverter
fun metadataToBytes(value: MeshProtos.DeviceMetadata): ByteArray? {
return value.toByteArray()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import com.geeksville.mesh.database.dao.NodeInfoDao
import com.geeksville.mesh.database.dao.QuickChatActionDao
import com.geeksville.mesh.database.entity.ContactSettings
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.database.entity.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.database.entity.Packet
Expand All @@ -46,6 +47,7 @@ import com.geeksville.mesh.database.entity.ReactionEntity
MeshLog::class,
QuickChatAction::class,
ReactionEntity::class,
MetadataEntity::class,
],
autoMigrations = [
AutoMigration(from = 3, to = 4),
Expand All @@ -60,8 +62,9 @@ import com.geeksville.mesh.database.entity.ReactionEntity
AutoMigration(from = 12, to = 13, spec = AutoMigration12to13::class),
AutoMigration(from = 13, to = 14),
AutoMigration(from = 14, to = 15),
AutoMigration(from = 15, to = 16),
],
version = 15,
version = 16,
exportSchema = true,
)
@TypeConverters(Converters::class)
Expand Down
30 changes: 23 additions & 7 deletions app/src/main/java/com/geeksville/mesh/database/NodeRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,19 @@ 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.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.NodeSortOption
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
Expand All @@ -49,15 +54,20 @@ class NodeRepository @Inject constructor(
.stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, null)

// our node info
private val _ourNodeInfo = MutableStateFlow<NodeEntity?>(null)
val ourNodeInfo: StateFlow<NodeEntity?> get() = _ourNodeInfo
private val _ourNodeInfo = MutableStateFlow<Node?>(null)
val ourNodeInfo: StateFlow<Node?> get() = _ourNodeInfo

// The unique userId of our node
private val _myId = MutableStateFlow<String?>(null)
val myId: StateFlow<String?> get() = _myId

// A map from nodeNum to NodeEntity
val nodeDBbyNum: StateFlow<Map<Int, NodeEntity>> = nodeInfoDao.nodeDBbyNum()
fun getNodeDBbyNum() = nodeInfoDao.nodeDBbyNum()
.map { map -> map.mapValues { (_, it) -> it.toEntity() } }

// A map from nodeNum to Node
@OptIn(ExperimentalCoroutinesApi::class)
val nodeDBbyNum: StateFlow<Map<Int, Node>> = nodeInfoDao.nodeDBbyNum()
.mapLatest { map -> map.mapValues { (_, it) -> it.toModel() } }
.onEach {
val ourNodeInfo = it.values.firstOrNull()
_ourNodeInfo.value = ourNodeInfo
Expand All @@ -67,8 +77,8 @@ class NodeRepository @Inject constructor(
.conflate()
.stateIn(processLifecycle.coroutineScope, SharingStarted.Eagerly, emptyMap())

fun getNode(userId: String): NodeEntity = nodeDBbyNum.value.values.find { it.user.id == userId }
?: NodeEntity(
fun getNode(userId: String): Node = nodeDBbyNum.value.values.find { it.user.id == userId }
?: Node(
num = DataPacket.idToDefaultNodeNum(userId) ?: 0,
user = getUser(userId),
)
Expand All @@ -84,6 +94,7 @@ class NodeRepository @Inject constructor(
.setHwModel(MeshProtos.HardwareModel.UNSET)
.build()

@OptIn(ExperimentalCoroutinesApi::class)
fun getNodes(
sort: NodeSortOption = NodeSortOption.LAST_HEARD,
filter: String = "",
Expand All @@ -92,7 +103,7 @@ class NodeRepository @Inject constructor(
sort = sort.sqlValue,
filter = filter,
includeUnknown = includeUnknown,
).flowOn(dispatchers.io).conflate()
).mapLatest { list -> list.map { it.toModel() } }.flowOn(dispatchers.io).conflate()

suspend fun upsert(node: NodeEntity) = withContext(dispatchers.io) {
nodeInfoDao.upsert(node)
Expand All @@ -107,5 +118,10 @@ class NodeRepository @Inject constructor(

suspend fun deleteNode(num: Int) = withContext(dispatchers.io) {
nodeInfoDao.deleteNode(num)
nodeInfoDao.deleteMetadata(num)
}

suspend fun insertMetadata(metadata: MetadataEntity) = withContext(dispatchers.io) {
nodeInfoDao.upsert(metadata)
}
}
16 changes: 14 additions & 2 deletions app/src/main/java/com/geeksville/mesh/database/dao/NodeInfoDao.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ import androidx.room.Insert
import androidx.room.MapColumn
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Upsert
import com.geeksville.mesh.database.entity.MetadataEntity
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeWithRelations
import com.geeksville.mesh.database.entity.NodeEntity
import kotlinx.coroutines.flow.Flow

@Suppress("TooManyFunctions")
@Dao
interface NodeInfoDao {

Expand All @@ -49,7 +53,8 @@ interface NodeInfoDao {
last_heard DESC
"""
)
fun nodeDBbyNum(): Flow<Map<@MapColumn(columnName = "num") Int, NodeEntity>>
@Transaction
fun nodeDBbyNum(): Flow<Map<@MapColumn(columnName = "num") Int, NodeWithRelations>>

@Query(
"""
Expand Down Expand Up @@ -92,11 +97,12 @@ interface NodeInfoDao {
last_heard DESC
"""
)
@Transaction
fun getNodes(
sort: String,
filter: String,
includeUnknown: Boolean,
): Flow<List<NodeEntity>>
): Flow<List<NodeWithRelations>>

@Upsert
fun upsert(node: NodeEntity)
Expand All @@ -109,4 +115,10 @@ interface NodeInfoDao {

@Query("DELETE FROM nodes WHERE num=:num")
fun deleteNode(num: Int)

@Upsert
fun upsert(meta: MetadataEntity)

@Query("DELETE FROM metadata WHERE num=:num")
fun deleteMetadata(num: Int)
}
Loading
Loading