chore: remove ~220 LOC dead code from node layer

Delete dead methods from NodeManager/NodeRepository interfaces:
- allowNodeDbWrites, setAllowNodeDbWrites (never read)
- loadCachedNodeDB (no-op, zero-value call in orchestrator)
- getNodes(): List<NodeInfo> (deprecated, unused)
- handleReceivedPaxcounter (zero callers)
- handleReceivedNodeStatus, updateNodeStatus (zero callers)
- insertMetadata (zero production callers)

Delete NodeInfo data class (85 LOC):
- All consumers now use Node domain model directly
- Retained MeshUser, Position, DeviceMetrics, EnvironmentMetrics
  which have active consumers across feature modules

Remove corresponding implementations from SdkNodeRepositoryImpl,
FakeNodeRepository, and test verifications.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich
2026-05-05 11:33:54 -05:00
parent a12aa2691e
commit e7d1767527
8 changed files with 0 additions and 222 deletions
@@ -40,12 +40,7 @@ import org.meshtastic.core.model.DataPacket
import org.meshtastic.core.model.MeshLog
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.Node
import org.meshtastic.core.model.NodeInfo
import org.meshtastic.core.model.NodeSortOption
import org.meshtastic.core.model.DeviceMetrics
import org.meshtastic.core.model.EnvironmentMetrics
import org.meshtastic.core.model.MeshUser
import org.meshtastic.core.model.Position
import org.meshtastic.core.model.util.NodeIdLookup
import org.meshtastic.core.model.util.onlineTimeThreshold
import org.meshtastic.core.repository.NodeManager
@@ -55,12 +50,9 @@ import org.meshtastic.core.repository.NotificationManager
import org.meshtastic.core.resources.Res
import org.meshtastic.core.resources.getStringSuspend
import org.meshtastic.core.resources.new_node_seen
import org.meshtastic.proto.DeviceMetadata
import org.meshtastic.proto.FirmwareEdition
import org.meshtastic.proto.HardwareModel
import org.meshtastic.proto.LocalStats
import org.meshtastic.proto.Paxcount
import org.meshtastic.proto.StatusMessage
import org.meshtastic.proto.Telemetry
import org.meshtastic.proto.User
import org.meshtastic.proto.NodeInfo as ProtoNodeInfo
@@ -235,13 +227,6 @@ class SdkNodeRepositoryImpl(
}
}
override fun insertMetadata(nodeNum: Int, metadata: DeviceMetadata) {
_nodeDBbyNum.update { map ->
val node = map[nodeNum] ?: return@update map
map + (nodeNum to node.copy(metadata = metadata))
}
}
// ── NodeManager surface ─────────────────────────────────────────────────
override val nodeDBbyNodeNum: Map<Int, Node>
@@ -251,16 +236,11 @@ class SdkNodeRepositoryImpl(
get() = _nodeDBbyNum.value.values.associateBy { it.user.id }
override val isNodeDbReady = MutableStateFlow(false)
override val allowNodeDbWrites = MutableStateFlow(false)
override fun setNodeDbReady(ready: Boolean) {
isNodeDbReady.value = ready
}
override fun setAllowNodeDbWrites(allowed: Boolean) {
allowNodeDbWrites.value = allowed
}
override val myNodeNum: StateFlow<Int?>
get() = _myNodeNum
@@ -274,15 +254,9 @@ class SdkNodeRepositoryImpl(
firmwareEdition.value = edition
}
override fun loadCachedNodeDB() {
// No-op in SDK mode — the SDK emits a Snapshot NodeChange on connect
// which populates the node map directly via installNodeInfo().
}
override fun clear() {
_nodeDBbyNum.value = emptyMap()
isNodeDbReady.value = false
allowNodeDbWrites.value = false
_myNodeNum.value = null
firmwareEdition.value = null
}
@@ -313,9 +287,6 @@ class SdkNodeRepositoryImpl(
return _nodeDBbyNum.value[num]?.user?.id ?: ""
}
@Suppress("Deprecated")
override fun getNodes(): List<NodeInfo> = _nodeDBbyNum.value.values.map { it.toNodeInfo() }
override fun removeByNodenum(nodeNum: Int) {
_nodeDBbyNum.update { it - nodeNum }
}
@@ -403,18 +374,6 @@ class SdkNodeRepositoryImpl(
}
}
override fun handleReceivedPaxcounter(fromNum: Int, p: Paxcount) {
updateNode(fromNum) { it.copy(paxcounter = p) }
}
override fun handleReceivedNodeStatus(fromNum: Int, s: StatusMessage) {
updateNodeStatus(fromNum, s.status)
}
override fun updateNodeStatus(nodeNum: Int, status: String?) {
updateNode(nodeNum) { it.copy(nodeStatus = status?.takeIf { s -> s.isNotEmpty() }) }
}
override fun installNodeInfo(info: ProtoNodeInfo, withBroadcast: Boolean) {
updateNode(info.num) { node ->
var next = node
@@ -515,40 +474,4 @@ class SdkNodeRepositoryImpl(
NodeSortOption.VIA_MQTT -> compareByDescending { it.viaMqtt }
NodeSortOption.VIA_FAVORITE -> compareByDescending { it.isFavorite }
}
@Suppress("CyclomaticComplexMethod")
private fun Node.toNodeInfo(): NodeInfo = NodeInfo(
num = num,
user = MeshUser(
id = user.id,
longName = user.long_name,
shortName = user.short_name,
hwModel = user.hw_model,
role = user.role.value,
),
position = Position(
latitude = latitude,
longitude = longitude,
altitude = position.altitude ?: 0,
time = position.time,
satellitesInView = position.sats_in_view,
groundSpeed = position.ground_speed ?: 0,
groundTrack = position.ground_track ?: 0,
precisionBits = position.precision_bits,
).takeIf { latitude != 0.0 || longitude != 0.0 },
snr = snr,
rssi = rssi,
lastHeard = lastHeard,
deviceMetrics = DeviceMetrics(
batteryLevel = deviceMetrics.battery_level ?: 0,
voltage = deviceMetrics.voltage ?: 0f,
channelUtilization = deviceMetrics.channel_utilization ?: 0f,
airUtilTx = deviceMetrics.air_util_tx ?: 0f,
uptimeSeconds = deviceMetrics.uptime_seconds ?: 0,
),
channel = channel,
environmentMetrics = EnvironmentMetrics.fromTelemetryProto(environmentMetrics, 0),
hopsAway = hopsAway,
nodeStatus = nodeStatus,
)
}
@@ -22,8 +22,6 @@ import org.meshtastic.core.common.util.bearing
import org.meshtastic.core.common.util.latLongToMeter
import org.meshtastic.core.common.util.nowSeconds
import org.meshtastic.core.model.util.anonymize
import org.meshtastic.core.model.util.onlineTimeThreshold
import org.meshtastic.proto.Config
import org.meshtastic.proto.HardwareModel
//
@@ -188,88 +186,3 @@ data class EnvironmentMetrics(
}
}
@CommonParcelize
data class NodeInfo(
val num: Int, // This is immutable, and used as a key
var user: MeshUser? = null,
var position: Position? = null,
var snr: Float = Float.MAX_VALUE,
var rssi: Int = Int.MAX_VALUE,
var lastHeard: Int = 0, // the last time we've seen this node in secs since 1970
var deviceMetrics: DeviceMetrics? = null,
var channel: Int = 0,
var environmentMetrics: EnvironmentMetrics? = null,
var hopsAway: Int = 0,
var nodeStatus: String? = null,
) : CommonParcelable {
@Suppress("MagicNumber")
val colors: Pair<Int, Int>
get() { // returns foreground and background @ColorInt for each 'num'
val r = (num and 0xFF0000) shr 16
val g = (num and 0x00FF00) shr 8
val b = num and 0x0000FF
val brightness = ((r * 0.299) + (g * 0.587) + (b * 0.114)) / 255
val foreground = if (brightness > 0.5) 0xFF000000.toInt() else 0xFFFFFFFF.toInt()
val background = (0xFF shl 24) or (r shl 16) or (g shl 8) or b
return foreground to background
}
val batteryLevel
get() = deviceMetrics?.batteryLevel
val voltage
get() = deviceMetrics?.voltage
@Suppress("ImplicitDefaultLocale")
val batteryStr
get() = if (batteryLevel in 1..100) "$batteryLevel%" else ""
/** true if the device was heard from recently */
val isOnline: Boolean
get() {
return lastHeard > onlineTimeThreshold()
}
// / return the position if it is valid, else null
val validPosition: Position?
get() {
return position?.takeIf { it.isValid() }
}
// / @return distance in meters to some other node (or null if unknown)
fun distance(o: NodeInfo?): Int? {
val p = validPosition
val op = o?.validPosition
return if (p != null && op != null) p.distance(op).toInt() else null
}
// / @return bearing to the other position in degrees
fun bearing(o: NodeInfo?): Int? {
val p = validPosition
val op = o?.validPosition
return if (p != null && op != null) p.bearing(op).toInt() else null
}
// / @return a nice human readable string for the distance, or null for unknown
@Suppress("MagicNumber")
fun distanceStr(o: NodeInfo?, prefUnits: Int = 0) = distance(o)?.let { dist ->
when {
dist == 0 -> null
// same point
prefUnits == Config.DisplayConfig.DisplayUnits.METRIC.value && dist < 1000 -> "$dist m"
prefUnits == Config.DisplayConfig.DisplayUnits.METRIC.value && dist >= 1000 ->
"${(dist / 100).toDouble() / 10.0} km"
prefUnits == Config.DisplayConfig.DisplayUnits.IMPERIAL.value && dist < 1609 ->
"${(dist.toDouble() * 3.281).toInt()} ft"
prefUnits == Config.DisplayConfig.DisplayUnits.IMPERIAL.value && dist >= 1609 ->
"${(dist / 160.9).toInt() / 10.0} mi"
else -> null
}
}
}
@@ -19,12 +19,8 @@ package org.meshtastic.core.repository
import kotlinx.coroutines.flow.StateFlow
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.Node
import org.meshtastic.core.model.NodeInfo
import org.meshtastic.core.model.util.NodeIdLookup
import org.meshtastic.proto.DeviceMetadata
import org.meshtastic.proto.FirmwareEdition
import org.meshtastic.proto.Paxcount
import org.meshtastic.proto.StatusMessage
import org.meshtastic.proto.Telemetry
import org.meshtastic.proto.User
import org.meshtastic.proto.NodeInfo as ProtoNodeInfo
@@ -45,12 +41,6 @@ interface NodeManager : NodeIdLookup {
/** Sets whether the node database is ready. */
fun setNodeDbReady(ready: Boolean)
/** Whether node database writes are allowed. */
val allowNodeDbWrites: StateFlow<Boolean>
/** Sets whether node database writes are allowed. */
fun setAllowNodeDbWrites(allowed: Boolean)
/** The local node number as a thread-safe [StateFlow]. */
val myNodeNum: StateFlow<Int?>
@@ -63,9 +53,6 @@ interface NodeManager : NodeIdLookup {
/** Sets the firmware edition of the connected device. */
fun setFirmwareEdition(edition: FirmwareEdition?)
/** Loads the cached node database from the repository. */
fun loadCachedNodeDB()
/** Clears the in-memory node database. */
fun clear()
@@ -75,9 +62,6 @@ interface NodeManager : NodeIdLookup {
/** Returns the local node ID. */
fun getMyId(): String
/** Returns a list of all known nodes. */
fun getNodes(): List<NodeInfo>
/** Processes a received user packet. */
fun handleReceivedUser(fromNum: Int, p: User, channel: Int = 0, manuallyVerified: Boolean = false)
@@ -87,15 +71,6 @@ interface NodeManager : NodeIdLookup {
/** Processes a received telemetry packet. */
fun handleReceivedTelemetry(fromNum: Int, telemetry: Telemetry)
/** Processes a received paxcounter packet. */
fun handleReceivedPaxcounter(fromNum: Int, p: Paxcount)
/** Processes a received node status message. */
fun handleReceivedNodeStatus(fromNum: Int, s: StatusMessage)
/** Updates the status string for a node. */
fun updateNodeStatus(nodeNum: Int, status: String?)
/** Updates a node using a transformation function. */
fun updateNode(nodeNum: Int, withBroadcast: Boolean = true, channel: Int = 0, transform: (Node) -> Node)
@@ -104,7 +79,4 @@ interface NodeManager : NodeIdLookup {
/** Installs node information from a ProtoNodeInfo object. */
fun installNodeInfo(info: ProtoNodeInfo, withBroadcast: Boolean = true)
/** Inserts hardware metadata for a node. */
fun insertMetadata(nodeNum: Int, metadata: DeviceMetadata)
}
@@ -21,7 +21,6 @@ import kotlinx.coroutines.flow.StateFlow
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.Node
import org.meshtastic.core.model.NodeSortOption
import org.meshtastic.proto.DeviceMetadata
import org.meshtastic.proto.LocalStats
import org.meshtastic.proto.User
@@ -166,12 +165,4 @@ interface NodeRepository {
* Used during the initial connection handshake.
*/
suspend fun installConfig(mi: MyNodeInfo, nodes: List<Node>)
/**
* Persists hardware metadata for a node.
*
* @param nodeNum The node number.
* @param metadata The [DeviceMetadata] to save.
*/
fun insertMetadata(nodeNum: Int, metadata: DeviceMetadata)
}
@@ -122,8 +122,6 @@ class MeshServiceOrchestrator(
databaseManager.switchActiveDatabase(radioPrefs.devAddr.value)
Logger.i { "Per-device database initialized" }
}
nodeManager.loadCachedNodeDB()
}
/**
@@ -115,7 +115,6 @@ class MeshServiceOrchestratorTest {
assertTrue(orchestrator.isRunning)
verify { serviceNotifications.initChannels() }
verify { nodeManager.loadCachedNodeDB() }
orchestrator.stop()
assertFalse(orchestrator.isRunning)
@@ -169,7 +168,6 @@ class MeshServiceOrchestratorTest {
// Components should only be initialized once
verify(exactly(1)) { serviceNotifications.initChannels() }
verify(exactly(1)) { nodeManager.loadCachedNodeDB() }
orchestrator.stop()
assertFalse(orchestrator.isRunning)
@@ -24,7 +24,6 @@ import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.Node
import org.meshtastic.core.model.NodeSortOption
import org.meshtastic.core.repository.NodeRepository
import org.meshtastic.proto.DeviceMetadata
import org.meshtastic.proto.LocalStats
import org.meshtastic.proto.User
@@ -164,11 +163,6 @@ class FakeNodeRepository :
_nodeDBbyNum.value = nodes.associateBy { it.num }
}
override fun insertMetadata(nodeNum: Int, metadata: DeviceMetadata) {
val node = _nodeDBbyNum.value[nodeNum] ?: return
_nodeDBbyNum.value = _nodeDBbyNum.value + (nodeNum to node.copy(metadata = metadata))
}
// --- Helper methods for testing ---
fun setNodes(nodes: List<Node>) {
@@ -84,17 +84,6 @@ class FakeNodeRepositoryTest {
}
}
@Test
fun `insertMetadata updates node metadata`() = runTest {
val nodeNum = 1234
repository.upsert(Node(num = nodeNum))
val metadata = org.meshtastic.proto.DeviceMetadata(firmware_version = "2.5.0")
repository.insertMetadata(nodeNum, metadata)
val node = repository.nodeDBbyNum.value[nodeNum]
assertEquals("2.5.0", node?.metadata?.firmware_version)
}
@Test
fun `deleteNodes removes multiple nodes`() = runTest {
repository.setNodes(listOf(Node(num = 1), Node(num = 2), Node(num = 3)))