mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-06-26 06:25:24 -04:00
fix: resolve release/2.8.0 branch-review findings (car hosts, AI node IDs, discovery abort, AQ zeros) (#5813)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,7 +130,7 @@ class AiFunctionProviderImpl(
|
||||
val nodes =
|
||||
nodeMap.values.map { node ->
|
||||
NodeSummary(
|
||||
id = "!${node.num.toString(HEX_RADIX)}",
|
||||
id = NodeAddress.numToDefaultId(node.num),
|
||||
name = node.user.long_name.takeIf { it.isNotBlank() } ?: "Node ${node.num}",
|
||||
batteryLevel = node.deviceMetrics.battery_level?.coerceIn(0, MAX_BATTERY_LEVEL),
|
||||
lastHeard = node.lastHeard.toLong() * MS_PER_SEC,
|
||||
@@ -201,8 +201,11 @@ class AiFunctionProviderImpl(
|
||||
try {
|
||||
val node =
|
||||
if (nodeId.startsWith("!")) {
|
||||
// Hex format: extract number and search
|
||||
val nodeNum = nodeId.drop(1).toInt(HEX_RADIX)
|
||||
// Canonical hex node ID (e.g. "!ffffffff"). idToNum parses the full unsigned 32-bit
|
||||
// range and returns null for malformed input, which we surface as NotFound.
|
||||
val nodeNum =
|
||||
NodeAddress.idToNum(nodeId)
|
||||
?: return@withTimeout GetNodeDetailsResult.NotFound("Node not found: $nodeId")
|
||||
nodeRepository.nodeDBbyNum.first()[nodeNum]
|
||||
} else {
|
||||
// User ID format
|
||||
@@ -218,7 +221,7 @@ class AiFunctionProviderImpl(
|
||||
|
||||
val details =
|
||||
NodeDetails(
|
||||
id = "!${node.num.toString(HEX_RADIX)}",
|
||||
id = NodeAddress.numToDefaultId(node.num),
|
||||
userId = node.user.id,
|
||||
name = node.user.long_name.takeIf { it.isNotBlank() } ?: "Node ${node.num}",
|
||||
batteryLevel = node.deviceMetrics.battery_level?.coerceIn(0, MAX_BATTERY_LEVEL),
|
||||
@@ -502,7 +505,6 @@ class AiFunctionProviderImpl(
|
||||
companion object {
|
||||
private val OPERATION_TIMEOUT = 5.seconds
|
||||
private const val MAX_BATTERY_LEVEL = 100
|
||||
private const val HEX_RADIX = 16
|
||||
private const val MS_PER_SEC = 1000L
|
||||
private const val HEALTH_SCORE_BASE = 50
|
||||
private const val HEALTH_SCORE_ONLINE_RATIO = 50
|
||||
|
||||
@@ -137,6 +137,22 @@ class AiFunctionProviderImplTest {
|
||||
assertEquals(true, isHandled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getNodeDetails_round_trips_high_bit_node_num() = runTest {
|
||||
// A node num with the high bit set (-1 == 0xFFFFFFFF) must format and parse as the canonical
|
||||
// "!ffffffff", not the signed "!-1" — regression guard for the node-ID hex fix.
|
||||
val testNode = Node(num = -1, user = User(id = "!ffffffff", long_name = "HighBit", short_name = "HB"))
|
||||
val nodeMap = MutableStateFlow(mapOf(-1 to testNode))
|
||||
every { nodeRepository.nodeDBbyNum } returns nodeMap
|
||||
|
||||
val provider = createProvider()
|
||||
val result = provider.getNodeDetails("!ffffffff")
|
||||
|
||||
assertIs<GetNodeDetailsResult.Success>(result)
|
||||
assertEquals("!ffffffff", result.node.id)
|
||||
assertEquals("HighBit", result.node.name)
|
||||
}
|
||||
|
||||
// --- getMeshMetrics tests ---
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user