Skip to content

Commit

Permalink
feat(config): implement excluded modules validation
Browse files Browse the repository at this point in the history
  • Loading branch information
andrekir committed Dec 11, 2024
1 parent 0f9c1fc commit f4672d0
Show file tree
Hide file tree
Showing 24 changed files with 1,051 additions and 306 deletions.
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
29 changes: 22 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 @@ -108,4 +119,8 @@ class NodeRepository @Inject constructor(
suspend fun deleteNode(num: Int) = withContext(dispatchers.io) {
nodeInfoDao.deleteNode(num)
}

suspend fun insertMetadata(metadata: MetadataEntity) = withContext(dispatchers.io) {
nodeInfoDao.upsert(metadata)
}
}
12 changes: 10 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,8 +22,11 @@ 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

Expand All @@ -49,7 +52,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 +96,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 +114,7 @@ interface NodeInfoDao {

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

@Upsert
fun upsert(meta: MetadataEntity)
}
Loading

0 comments on commit f4672d0

Please sign in to comment.