Traceroute map position snapshots (#4035)

Signed-off-by: Jord <650645+DivineOmega@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Jord 2025-12-18 14:14:03 +00:00 committed by GitHub
parent 03fd2bf9ba
commit 9833795864
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1195 additions and 44 deletions

View file

@ -141,8 +141,14 @@ fun NavGraphBuilder.nodeDetailGraph(navController: NavHostController, scrollToTo
TracerouteLogScreen(
viewModel = metricsViewModel,
onNavigateUp = navController::navigateUp,
onViewOnMap = { requestId ->
navController.navigate(NodeDetailRoutes.TracerouteMap(args.destNum, requestId))
onViewOnMap = { requestId, responseLogUuid ->
navController.navigate(
NodeDetailRoutes.TracerouteMap(
destNum = args.destNum,
requestId = requestId,
logUuid = responseLogUuid,
),
)
},
)
}
@ -166,6 +172,7 @@ fun NavGraphBuilder.nodeDetailGraph(navController: NavHostController, scrollToTo
TracerouteMapScreen(
metricsViewModel = metricsViewModel,
requestId = args.requestId,
logUuid = args.logUuid,
onNavigateUp = navController::navigateUp,
)
}

View file

@ -64,6 +64,7 @@ import org.meshtastic.core.data.repository.MeshLogRepository
import org.meshtastic.core.data.repository.NodeRepository
import org.meshtastic.core.data.repository.PacketRepository
import org.meshtastic.core.data.repository.RadioConfigRepository
import org.meshtastic.core.data.repository.TracerouteSnapshotRepository
import org.meshtastic.core.database.DatabaseManager
import org.meshtastic.core.database.entity.MeshLog
import org.meshtastic.core.database.entity.MetadataEntity
@ -147,6 +148,8 @@ class MeshService : Service() {
@Inject lateinit var meshLogRepository: Lazy<MeshLogRepository>
@Inject lateinit var tracerouteSnapshotRepository: TracerouteSnapshotRepository
@Inject lateinit var radioInterfaceService: RadioInterfaceService
@Inject lateinit var locationRepository: LocationRepository
@ -176,6 +179,8 @@ class MeshService : Service() {
@Inject lateinit var analytics: PlatformAnalytics
private val tracerouteStartTimes = ConcurrentHashMap<Int, Long>()
private val logUuidByPacketId = ConcurrentHashMap<Int, String>()
private val logInsertJobByPacketId = ConcurrentHashMap<Int, Job>()
companion object {
@ -826,6 +831,8 @@ class MeshService : Service() {
// that is not shared'
var shouldBroadcast = !fromUs
val logUuid = logUuidByPacketId[packet.id]
val logInsertJob = logInsertJobByPacketId[packet.id]
when (data.portnumValue) {
Portnums.PortNum.TEXT_MESSAGE_APP_VALUE -> {
if (data.replyId != 0 && data.emoji == 0) {
@ -939,6 +946,28 @@ class MeshService : Service() {
val full = packet.getFullTracerouteResponse(::getUserName)
if (full != null) {
val requestId = packet.decoded.requestId
if (logUuid != null) {
serviceScope.handledLaunch {
logInsertJob?.join()
val forwardRoute = routeDiscovery?.routeList.orEmpty()
val returnRoute = routeDiscovery?.routeBackList.orEmpty()
val routeNodeNums = (forwardRoute + returnRoute).distinct()
val nodeDbByNum = nodeRepository.nodeDBbyNum.value
val snapshotPositions =
routeNodeNums
.mapNotNull { nodeNum ->
val position =
nodeDbByNum[nodeNum]?.validPosition ?: return@mapNotNull null
nodeNum to position
}
.toMap()
tracerouteSnapshotRepository.upsertSnapshotPositions(
logUuid = logUuid,
requestId = requestId,
positions = snapshotPositions,
)
}
}
val start = tracerouteStartTimes.remove(requestId)
val responseText =
if (start != null) {
@ -960,6 +989,7 @@ class MeshService : Service() {
requestId = requestId,
forwardRoute = routeDiscovery?.routeList.orEmpty(),
returnRoute = routeDiscovery?.routeBackList.orEmpty(),
logUuid = logUuid,
),
)
}
@ -1412,7 +1442,7 @@ class MeshService : Service() {
portNum = packet.decoded.portnumValue,
fromRadio = fromRadio { this.packet = packet },
)
insertMeshLog(packetToSave)
val logInsertJob = insertMeshLog(packetToSave)
serviceScope.handledLaunch { serviceRepository.emitMeshPacket(packet) }
@ -1441,17 +1471,22 @@ class MeshService : Service() {
// Generate our own hopsAway, comparing hopStart to hopLimit.
it.hopsAway = getHopsAwayForPacket(packet)
}
handleReceivedData(packet)
logInsertJobByPacketId[packet.id] = logInsertJob
logUuidByPacketId[packet.id] = packetToSave.uuid
try {
handleReceivedData(packet)
} finally {
logUuidByPacketId.remove(packet.id)
logInsertJobByPacketId.remove(packet.id)
}
}
}
private fun insertMeshLog(packetToSave: MeshLog) {
serviceScope.handledLaunch {
// Do not log, because might contain PII
// info("insert: ${packetToSave.message_type} =
// ${packetToSave.raw_message.toOneLineString()}")
meshLogRepository.get().insert(packetToSave)
}
private fun insertMeshLog(packetToSave: MeshLog): Job = serviceScope.handledLaunch {
// Do not log, because might contain PII
// info("insert: ${packetToSave.message_type} =
// ${packetToSave.raw_message.toOneLineString()}")
meshLogRepository.get().insert(packetToSave)
}
private fun setLocalConfig(config: ConfigProtos.Config) {

View file

@ -267,7 +267,11 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
if (errorRes == null) {
dismissedTracerouteRequestId = response.requestId
navController.navigate(
NodeDetailRoutes.TracerouteMap(response.destinationNodeNum, response.requestId),
NodeDetailRoutes.TracerouteMap(
destNum = response.destinationNodeNum,
requestId = response.requestId,
logUuid = response.logUuid,
),
)
} else {
tracerouteMapError = errorRes