mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-06-02 06:24:16 +02:00
refactor: eliminate NodeInfoReadDataSource, use NodeRepository directly
MeshLogRepositoryImpl was the sole external consumer of NodeInfoReadDataSource — it only needed myNodeNum to identify the local node in logs. Replace with NodeRepository.myNodeInfo (already SDK-backed via SdkNodeRepositoryImpl). PacketRepositoryImpl referenced NodeInfoDao.MAX_BIND_PARAMS — inlined as a private constant since it's just the SQLite bind-param limit. With zero external consumers remaining, delete: - NodeInfoReadDataSource interface - SwitchingNodeInfoReadDataSource implementation The Room NodeInfoDao/NodeEntity/MyNodeEntity remain in the database module for now (internal tests + migration history) but have no external dependents — ready for a future Room migration 40 to DROP. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
+10
-8
@@ -7,14 +7,14 @@
|
||||
|
||||
## Summary
|
||||
|
||||
**Completed:** ~92% of the Clean Break migration. AIDL dropped, SDK is sole radio path,
|
||||
**Completed:** ~93% of the Clean Break migration. AIDL dropped, SDK is sole radio path,
|
||||
transport layer fully deleted, Desktop uses shared SDK bridge, dead infrastructure gone,
|
||||
POC ViewModels removed, stale broadcast constants removed.
|
||||
POC ViewModels removed, NodeInfoReadDataSource eliminated.
|
||||
|
||||
**Remaining:** Room table cleanup, optional VM parameter slimming, and test coverage for
|
||||
new bridge code.
|
||||
|
||||
**Net change:** 154 files changed, +3,655 / -15,301 lines (net -11,646 LOC removed)
|
||||
**Net change:** 159 files changed, +3,684 / -15,460 lines (net -11,776 LOC removed)
|
||||
|
||||
---
|
||||
|
||||
@@ -97,13 +97,15 @@ new bridge code.
|
||||
|
||||
## What Remains
|
||||
|
||||
### 1. Room Table Cleanup (low priority)
|
||||
### 1. Room Table Cleanup (medium priority — unblocked)
|
||||
- Migration 39→40: DROP legacy `nodes`, `my_node` tables
|
||||
- Remove old `NodeEntity`, `MyNodeEntity` Room entities + DAOs
|
||||
- Remove old `NodeEntity`, `MyNodeEntity` Room entities + `NodeInfoDao`
|
||||
- SDK SqlDelight is already source of truth; Room tables are redundant
|
||||
- **Blocked by:** `NodeInfoReadDataSource` (used by `MeshLogRepositoryImpl` for node
|
||||
name resolution), `PacketRepositoryImpl` (uses `NodeInfoDao.MAX_BIND_PARAMS`)
|
||||
- Requires migrating node-name lookup to SDK APIs before tables can be dropped
|
||||
- **No longer blocked:** `NodeInfoReadDataSource` eliminated, `PacketRepositoryImpl`
|
||||
no longer depends on `NodeInfoDao`
|
||||
- Remaining internal consumers: `MeshtasticDatabase.nodeInfoDao()` abstract method,
|
||||
`CommonNodeInfoDaoTest`, `CommonPacketDaoTest`, `MigrationTest`
|
||||
- Requires: Room schema migration file, entity deletion, DAO deletion, test updates
|
||||
|
||||
### 2. VM Parameter Slimming (optional, quality-of-life)
|
||||
VMs currently inject SDK-backed adapters (RadioController, NodeRepository, etc.)
|
||||
|
||||
-40
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.data.datasource
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.meshtastic.core.database.entity.MyNodeEntity
|
||||
import org.meshtastic.core.database.entity.NodeEntity
|
||||
import org.meshtastic.core.database.entity.NodeWithRelations
|
||||
|
||||
interface NodeInfoReadDataSource {
|
||||
fun myNodeInfoFlow(): Flow<MyNodeEntity?>
|
||||
|
||||
fun nodeDBbyNumFlow(): Flow<Map<Int, NodeWithRelations>>
|
||||
|
||||
fun getNodesFlow(
|
||||
sort: String,
|
||||
filter: String,
|
||||
includeUnknown: Boolean,
|
||||
hopsAwayMax: Int,
|
||||
lastHeardMin: Int,
|
||||
): Flow<List<NodeWithRelations>>
|
||||
|
||||
suspend fun getNodesOlderThan(lastHeard: Int): List<NodeEntity>
|
||||
|
||||
suspend fun getUnknownNodes(): List<NodeEntity>
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.data.datasource
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseProvider
|
||||
import org.meshtastic.core.database.entity.MyNodeEntity
|
||||
import org.meshtastic.core.database.entity.NodeEntity
|
||||
import org.meshtastic.core.database.entity.NodeWithRelations
|
||||
|
||||
@Single
|
||||
class SwitchingNodeInfoReadDataSource(private val dbManager: DatabaseProvider) : NodeInfoReadDataSource {
|
||||
|
||||
override fun myNodeInfoFlow(): Flow<MyNodeEntity?> =
|
||||
dbManager.currentDb.flatMapLatest { db -> db.nodeInfoDao().getMyNodeInfo() }
|
||||
|
||||
override fun nodeDBbyNumFlow(): Flow<Map<Int, NodeWithRelations>> =
|
||||
dbManager.currentDb.flatMapLatest { db -> db.nodeInfoDao().nodeDBbyNum() }
|
||||
|
||||
override fun getNodesFlow(
|
||||
sort: String,
|
||||
filter: String,
|
||||
includeUnknown: Boolean,
|
||||
hopsAwayMax: Int,
|
||||
lastHeardMin: Int,
|
||||
): Flow<List<NodeWithRelations>> = dbManager.currentDb.flatMapLatest { db ->
|
||||
db.nodeInfoDao()
|
||||
.getNodes(
|
||||
sort = sort,
|
||||
filter = filter,
|
||||
includeUnknown = includeUnknown,
|
||||
hopsAwayMax = hopsAwayMax,
|
||||
lastHeardMin = lastHeardMin,
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getNodesOlderThan(lastHeard: Int): List<NodeEntity> =
|
||||
dbManager.withDb { it.nodeInfoDao().getNodesOlderThan(lastHeard) } ?: emptyList()
|
||||
|
||||
override suspend fun getUnknownNodes(): List<NodeEntity> =
|
||||
dbManager.withDb { it.nodeInfoDao().getUnknownNodes() } ?: emptyList()
|
||||
}
|
||||
+5
-5
@@ -27,7 +27,6 @@ import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.common.util.nowMillis
|
||||
import org.meshtastic.core.data.datasource.NodeInfoReadDataSource
|
||||
import org.meshtastic.core.database.DatabaseProvider
|
||||
import org.meshtastic.core.database.entity.asEntity
|
||||
import org.meshtastic.core.database.entity.asExternalModel
|
||||
@@ -36,6 +35,7 @@ import org.meshtastic.core.model.MeshLog
|
||||
import org.meshtastic.core.repository.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.MeshLogRepository.Companion.DEFAULT_MAX_LOGS
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.MyNodeInfo
|
||||
import org.meshtastic.proto.PortNum
|
||||
@@ -53,7 +53,7 @@ open class MeshLogRepositoryImpl(
|
||||
private val dbManager: DatabaseProvider,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
private val meshLogPrefs: MeshLogPrefs,
|
||||
private val nodeInfoReadDataSource: NodeInfoReadDataSource,
|
||||
private val nodeRepository: NodeRepository,
|
||||
) : MeshLogRepository {
|
||||
|
||||
/** Retrieves all [MeshLog]s in the database, up to [maxItem]. */
|
||||
@@ -142,8 +142,8 @@ open class MeshLogRepositoryImpl(
|
||||
.getOrNull()
|
||||
|
||||
/** Returns a flow that maps a [nodeNum] to [MeshLog.NODE_NUM_LOCAL] if it is the locally connected node. */
|
||||
private fun effectiveLogId(nodeNum: Int): Flow<Int> = nodeInfoReadDataSource
|
||||
.myNodeInfoFlow()
|
||||
private fun effectiveLogId(nodeNum: Int): Flow<Int> = nodeRepository
|
||||
.myNodeInfo
|
||||
.map { info -> if (nodeNum == info?.myNodeNum) MeshLog.NODE_NUM_LOCAL else nodeNum }
|
||||
.distinctUntilChanged()
|
||||
|
||||
@@ -169,7 +169,7 @@ open class MeshLogRepositoryImpl(
|
||||
|
||||
/** Deletes all logs associated with a specific [nodeNum] and [portNum]. */
|
||||
override suspend fun deleteLogs(nodeNum: Int, portNum: Int) = withContext(dispatchers.io) {
|
||||
val myNodeNum = nodeInfoReadDataSource.myNodeInfoFlow().firstOrNull()?.myNodeNum
|
||||
val myNodeNum = nodeRepository.myNodeInfo.value?.myNodeNum
|
||||
val logId = if (nodeNum == myNodeNum) MeshLog.NODE_NUM_LOCAL else nodeNum
|
||||
dbManager.currentDb.value.meshLogDao().deleteLogs(logId, portNum)
|
||||
}
|
||||
|
||||
+2
-2
@@ -28,7 +28,6 @@ import kotlinx.coroutines.withContext
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.koin.core.annotation.Single
|
||||
import org.meshtastic.core.database.DatabaseProvider
|
||||
import org.meshtastic.core.database.dao.NodeInfoDao
|
||||
import org.meshtastic.core.database.entity.PacketEntity
|
||||
import org.meshtastic.core.database.entity.toReaction
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
@@ -245,7 +244,7 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
|
||||
} else {
|
||||
withContext(dispatchers.io) {
|
||||
val dao = dbManager.currentDb.value.packetDao()
|
||||
ids.chunked(NodeInfoDao.MAX_BIND_PARAMS)
|
||||
ids.chunked(MAX_SQLITE_BIND_PARAMS)
|
||||
.flatMap { dao.getPacketsByPacketIds(it) }
|
||||
.associateBy { it.packet.packetId }
|
||||
}
|
||||
@@ -515,5 +514,6 @@ class PacketRepositoryImpl(private val dbManager: DatabaseProvider, private val
|
||||
private const val MESSAGES_PAGE_SIZE = 50
|
||||
private const val DELETE_CHUNK_SIZE = 500
|
||||
private const val MILLISECONDS_IN_SECOND = 1000L
|
||||
private const val MAX_SQLITE_BIND_PARAMS = 999
|
||||
}
|
||||
}
|
||||
|
||||
+13
-9
@@ -25,10 +25,10 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okio.ByteString.Companion.toByteString
|
||||
import org.meshtastic.core.data.datasource.NodeInfoReadDataSource
|
||||
import org.meshtastic.core.database.entity.MyNodeEntity
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
import org.meshtastic.core.model.MeshLog
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.testing.FakeDatabaseProvider
|
||||
import org.meshtastic.core.testing.FakeMeshLogPrefs
|
||||
import org.meshtastic.proto.Data
|
||||
@@ -47,7 +47,7 @@ abstract class CommonMeshLogRepositoryTest {
|
||||
|
||||
protected lateinit var dbProvider: FakeDatabaseProvider
|
||||
protected lateinit var meshLogPrefs: FakeMeshLogPrefs
|
||||
protected lateinit var nodeInfoReadDataSource: NodeInfoReadDataSource
|
||||
protected lateinit var nodeRepository: NodeRepository
|
||||
private val testDispatcher = UnconfinedTestDispatcher()
|
||||
private val dispatchers = CoroutineDispatchers(main = testDispatcher, io = testDispatcher, default = testDispatcher)
|
||||
|
||||
@@ -59,11 +59,11 @@ abstract class CommonMeshLogRepositoryTest {
|
||||
dbProvider = FakeDatabaseProvider()
|
||||
meshLogPrefs = FakeMeshLogPrefs()
|
||||
meshLogPrefs.setLoggingEnabled(true)
|
||||
nodeInfoReadDataSource = mock(MockMode.autofill)
|
||||
nodeRepository = mock(MockMode.autofill)
|
||||
|
||||
every { nodeInfoReadDataSource.myNodeInfoFlow() } returns MutableStateFlow(null)
|
||||
every { nodeRepository.myNodeInfo } returns MutableStateFlow(null)
|
||||
|
||||
repository = MeshLogRepositoryImpl(dbProvider, dispatchers, meshLogPrefs, nodeInfoReadDataSource)
|
||||
repository = MeshLogRepositoryImpl(dbProvider, dispatchers, meshLogPrefs, nodeRepository)
|
||||
}
|
||||
|
||||
@AfterTest
|
||||
@@ -105,9 +105,10 @@ abstract class CommonMeshLogRepositoryTest {
|
||||
fun `deleteLogs redirects local node number to NODE_NUM_LOCAL`() = runTest(testDispatcher) {
|
||||
val localNodeNum = 999
|
||||
val port = PortNum.TEXT_MESSAGE_APP.value
|
||||
val myNodeEntity =
|
||||
MyNodeEntity(
|
||||
val myNodeInfo =
|
||||
MyNodeInfo(
|
||||
myNodeNum = localNodeNum,
|
||||
hasGPS = false,
|
||||
model = "model",
|
||||
firmwareVersion = "1.0",
|
||||
couldUpdate = false,
|
||||
@@ -117,8 +118,11 @@ abstract class CommonMeshLogRepositoryTest {
|
||||
minAppVersion = 0,
|
||||
maxChannels = 0,
|
||||
hasWifi = false,
|
||||
channelUtilization = 0f,
|
||||
airUtilTx = 0f,
|
||||
deviceId = null,
|
||||
)
|
||||
every { nodeInfoReadDataSource.myNodeInfoFlow() } returns MutableStateFlow(myNodeEntity)
|
||||
every { nodeRepository.myNodeInfo } returns MutableStateFlow(myNodeInfo)
|
||||
|
||||
val log =
|
||||
MeshLog(
|
||||
|
||||
Reference in New Issue
Block a user