kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
add times to traceroute displays. (#2999)
rodzic
80a7b9e081
commit
99938e97bd
|
|
@ -84,7 +84,7 @@ data class MetricsState(
|
|||
val powerMetrics: List<Telemetry> = emptyList(),
|
||||
val hostMetrics: List<Telemetry> = emptyList(),
|
||||
val tracerouteRequests: List<MeshLog> = emptyList(),
|
||||
val tracerouteResults: List<MeshPacket> = emptyList(),
|
||||
val tracerouteResults: List<MeshLog> = emptyList(),
|
||||
val positionLogs: List<Position> = emptyList(),
|
||||
val deviceHardware: DeviceHardware? = null,
|
||||
val isLocalDevice: Boolean = false,
|
||||
|
|
@ -321,7 +321,7 @@ constructor(
|
|||
|
||||
combine(
|
||||
meshLogRepository.getLogsFrom(nodeNum = 0, PortNum.TRACEROUTE_APP_VALUE),
|
||||
meshLogRepository.getMeshPacketsFrom(destNum, PortNum.TRACEROUTE_APP_VALUE),
|
||||
meshLogRepository.getLogsFrom(destNum ?: 0, PortNum.TRACEROUTE_APP_VALUE),
|
||||
) { request, response ->
|
||||
_state.update { state ->
|
||||
state.copy(
|
||||
|
|
|
|||
|
|
@ -22,48 +22,51 @@ import com.geeksville.mesh.MeshProtos.RouteDiscovery
|
|||
import com.geeksville.mesh.Portnums
|
||||
|
||||
val MeshProtos.MeshPacket.fullRouteDiscovery: RouteDiscovery?
|
||||
get() = with(decoded) {
|
||||
if (hasDecoded() && !wantResponse && portnum == Portnums.PortNum.TRACEROUTE_APP) {
|
||||
runCatching { RouteDiscovery.parseFrom(payload).toBuilder() }.getOrNull()?.apply {
|
||||
val fullRoute = listOf(to) + routeList + from
|
||||
clearRoute()
|
||||
addAllRoute(fullRoute)
|
||||
get() =
|
||||
with(decoded) {
|
||||
if (hasDecoded() && !wantResponse && portnum == Portnums.PortNum.TRACEROUTE_APP) {
|
||||
runCatching { RouteDiscovery.parseFrom(payload).toBuilder() }
|
||||
.getOrNull()
|
||||
?.apply {
|
||||
val fullRoute = listOf(to) + routeList + from
|
||||
clearRoute()
|
||||
addAllRoute(fullRoute)
|
||||
|
||||
val fullRouteBack = listOf(from) + routeBackList + to
|
||||
clearRouteBack()
|
||||
if (hopStart > 0 && snrBackCount > 0) { // otherwise back route is invalid
|
||||
addAllRouteBack(fullRouteBack)
|
||||
}
|
||||
}?.build()
|
||||
} else {
|
||||
null
|
||||
val fullRouteBack = listOf(from) + routeBackList + to
|
||||
clearRouteBack()
|
||||
if (hopStart > 0 && snrBackCount > 0) { // otherwise back route is invalid
|
||||
addAllRouteBack(fullRouteBack)
|
||||
}
|
||||
}
|
||||
?.build()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
private fun formatTraceroutePath(nodesList: List<String>, snrList: List<Int>): String {
|
||||
// nodesList should include both origin and destination nodes
|
||||
// origin will not have an SNR value, but destination should
|
||||
val snrStr = if (snrList.size == nodesList.size - 1) {
|
||||
snrList
|
||||
} else {
|
||||
// use unknown SNR for entire route if snrList has invalid size
|
||||
List(nodesList.size - 1) { -128 }
|
||||
}.map { snr ->
|
||||
val str = if (snr == -128) "?" else "${snr / 4f}"
|
||||
"⇊ $str dB"
|
||||
}
|
||||
val snrStr =
|
||||
if (snrList.size == nodesList.size - 1) {
|
||||
snrList
|
||||
} else {
|
||||
// use unknown SNR for entire route if snrList has invalid size
|
||||
List(nodesList.size - 1) { -128 }
|
||||
}
|
||||
.map { snr ->
|
||||
val str = if (snr == -128) "?" else "${snr / 4f}"
|
||||
"⇊ $str dB"
|
||||
}
|
||||
|
||||
return nodesList.map { userName ->
|
||||
"■ $userName"
|
||||
}.flatMapIndexed { i, nodeStr ->
|
||||
if (i == 0) listOf(nodeStr) else listOf(snrStr[i - 1], nodeStr)
|
||||
}.joinToString("\n")
|
||||
return nodesList
|
||||
.map { userName -> "■ $userName" }
|
||||
.flatMapIndexed { i, nodeStr -> if (i == 0) listOf(nodeStr) else listOf(snrStr[i - 1], nodeStr) }
|
||||
.joinToString("\n")
|
||||
}
|
||||
|
||||
private fun RouteDiscovery.getTracerouteResponse(
|
||||
getUser: (nodeNum: Int) -> String,
|
||||
): String = buildString {
|
||||
private fun RouteDiscovery.getTracerouteResponse(getUser: (nodeNum: Int) -> String): String = buildString {
|
||||
if (routeList.isNotEmpty()) {
|
||||
append("Route traced toward destination:\n\n")
|
||||
append(formatTraceroutePath(routeList.map(getUser), snrTowardsList))
|
||||
|
|
@ -75,6 +78,10 @@ private fun RouteDiscovery.getTracerouteResponse(
|
|||
}
|
||||
}
|
||||
|
||||
fun MeshProtos.MeshPacket.getTracerouteResponse(
|
||||
getUser: (nodeNum: Int) -> String,
|
||||
): String? = fullRouteDiscovery?.getTracerouteResponse(getUser)
|
||||
fun MeshProtos.MeshPacket.getTracerouteResponse(getUser: (nodeNum: Int) -> String): String? =
|
||||
fullRouteDiscovery?.getTracerouteResponse(getUser)
|
||||
|
||||
/** Returns a traceroute response string only when the result is complete (both directions). */
|
||||
fun MeshProtos.MeshPacket.getFullTracerouteResponse(getUser: (nodeNum: Int) -> String): String? = fullRouteDiscovery
|
||||
?.takeIf { it.routeList.isNotEmpty() && it.routeBackList.isNotEmpty() }
|
||||
?.getTracerouteResponse(getUser)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ import com.geeksville.mesh.fromRadio
|
|||
import com.geeksville.mesh.model.DeviceVersion
|
||||
import com.geeksville.mesh.model.NO_DEVICE_SELECTED
|
||||
import com.geeksville.mesh.model.Node
|
||||
import com.geeksville.mesh.model.getTracerouteResponse
|
||||
import com.geeksville.mesh.model.getFullTracerouteResponse
|
||||
import com.geeksville.mesh.position
|
||||
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
|
||||
import com.geeksville.mesh.repository.location.LocationRepository
|
||||
|
|
@ -148,6 +148,8 @@ class MeshService :
|
|||
|
||||
@Inject lateinit var meshPrefs: MeshPrefs
|
||||
|
||||
private val tracerouteStartTimes = ConcurrentHashMap<Int, Long>()
|
||||
|
||||
companion object : Logging {
|
||||
|
||||
// Intents broadcast by MeshService
|
||||
|
|
@ -848,7 +850,21 @@ class MeshService :
|
|||
}
|
||||
|
||||
Portnums.PortNum.TRACEROUTE_APP_VALUE -> {
|
||||
radioConfigRepository.setTracerouteResponse(packet.getTracerouteResponse(::getUserName))
|
||||
val full = packet.getFullTracerouteResponse(::getUserName)
|
||||
if (full != null) {
|
||||
val requestId = packet.decoded.requestId
|
||||
val start = tracerouteStartTimes.remove(requestId)
|
||||
val response =
|
||||
if (start != null) {
|
||||
val elapsedMs = System.currentTimeMillis() - start
|
||||
val seconds = elapsedMs / 1000.0
|
||||
info("Traceroute $requestId complete in $seconds s")
|
||||
"$full\n\nDuration: ${"%.1f".format(seconds)} s"
|
||||
} else {
|
||||
full
|
||||
}
|
||||
radioConfigRepository.setTracerouteResponse(response)
|
||||
}
|
||||
}
|
||||
|
||||
else -> debug("No custom processing needed for ${data.portnumValue}")
|
||||
|
|
@ -2376,6 +2392,7 @@ class MeshService :
|
|||
}
|
||||
|
||||
override fun requestTraceroute(requestId: Int, destNum: Int) = toRemoteExceptions {
|
||||
tracerouteStartTimes[requestId] = System.currentTimeMillis()
|
||||
packetHandler.sendToRadio(
|
||||
newMeshPacketTo(destNum).buildMeshPacket(
|
||||
wantAck = true,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ import com.geeksville.mesh.model.fullRouteDiscovery
|
|||
import com.geeksville.mesh.model.getTracerouteResponse
|
||||
import com.geeksville.mesh.ui.common.components.SimpleAlertDialog
|
||||
import com.geeksville.mesh.ui.common.theme.AppTheme
|
||||
import com.geeksville.mesh.ui.metrics.CommonCharts.MS_PER_SEC
|
||||
import java.text.DateFormat
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
|
|
@ -88,9 +89,9 @@ fun TracerouteLogScreen(modifier: Modifier = Modifier, viewModel: MetricsViewMod
|
|||
items(state.tracerouteRequests, key = { it.uuid }) { log ->
|
||||
val result =
|
||||
remember(state.tracerouteRequests) {
|
||||
state.tracerouteResults.find { it.decoded.requestId == log.fromRadio.packet.id }
|
||||
state.tracerouteResults.find { it.fromRadio.packet.decoded.requestId == log.fromRadio.packet.id }
|
||||
}
|
||||
val route = remember(result) { result?.fullRouteDiscovery }
|
||||
val route = remember(result) { result?.fromRadio?.packet?.fullRouteDiscovery }
|
||||
|
||||
val time = dateFormat.format(log.received_date)
|
||||
val (text, icon) = route.getTextAndIcon()
|
||||
|
|
@ -103,7 +104,15 @@ fun TracerouteLogScreen(modifier: Modifier = Modifier, viewModel: MetricsViewMod
|
|||
modifier =
|
||||
Modifier.combinedClickable(onLongClick = { expanded = true }) {
|
||||
if (result != null) {
|
||||
showDialog = result.getTracerouteResponse(::getUsername)
|
||||
val full = route
|
||||
if (full != null && full.routeList.isNotEmpty() && full.routeBackList.isNotEmpty()) {
|
||||
val elapsedMs = (result.received_date - log.received_date).coerceAtLeast(0)
|
||||
val seconds = elapsedMs.toDouble() / MS_PER_SEC
|
||||
val base = result.fromRadio.packet.getTracerouteResponse(::getUsername)
|
||||
showDialog = "$base\n\nDuration: ${"%.1f".format(seconds)} s"
|
||||
} else {
|
||||
showDialog = result.fromRadio.packet.getTracerouteResponse(::getUsername)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue