feat: add traceroute (#620)

pull/623/head
Andre K 2023-04-16 06:16:41 -03:00 zatwierdzone przez GitHub
rodzic 72c278c92c
commit da5f1d529d
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
8 zmienionych plików z 95 dodań i 2 usunięć

Wyświetl plik

@ -104,6 +104,9 @@ interface IMeshService {
/// Send position packet with wantResponse to nodeNum
void requestPosition(in int idNum, in Position position);
/// Send traceroute packet with wantResponse to nodeNum
void requestTraceroute(in int requestId, in int destNum);
/// Send Shutdown admin packet to nodeNum
void requestShutdown(in int idNum);

Wyświetl plik

@ -51,4 +51,14 @@ data class MeshLog(@PrimaryKey val uuid: String,
return null
} ?: nodeInfo?.position
}
}
val routeDiscovery: MeshProtos.RouteDiscovery?
get() {
return meshPacket?.run {
if (hasDecoded() && decoded.portnumValue == Portnums.PortNum.TRACEROUTE_APP_VALUE) {
return MeshProtos.RouteDiscovery.parseFrom(decoded.payload)
}
return null
}
}
}

Wyświetl plik

@ -56,6 +56,7 @@ class NodeDB(private val ui: UIViewModel) {
private val _nodes = MutableLiveData<Map<String, NodeInfo>>(mapOf(*(if (seedWithTestNodes) testNodes else listOf()).map { it.user!!.id to it }
.toTypedArray()))
val nodes: LiveData<Map<String, NodeInfo>> get() = _nodes
val nodesByNum get() = nodes.value?.values?.associateBy { it.num }
fun setNodes(nodes: Map<String, NodeInfo>) {
_nodes.value = nodes

Wyświetl plik

@ -34,6 +34,7 @@ import com.geeksville.mesh.util.positionToMeter
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -44,6 +45,7 @@ import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeoutOrNull
import org.osmdroid.bonuspack.kml.KmlDocument
import org.osmdroid.views.MapView
import org.osmdroid.views.overlay.FolderOverlay
@ -172,6 +174,44 @@ class UIViewModel @Inject constructor(
.filterValues { it.data.waypoint!!.expire > System.currentTimeMillis() / 1000 }
}.asLiveData()
private val _packetResponse = MutableStateFlow<MeshLog?>(null)
val packetResponse: StateFlow<MeshLog?> = _packetResponse
/**
* Called immediately after activity observes packetResponse
*/
fun clearPacketResponse() {
_packetResponse.tryEmit(null)
}
/**
* Returns the packet response to a given [packetId] or null after [timeout] milliseconds
*/
private suspend fun getResponseBy(packetId: Int, timeout: Long) = withContext(Dispatchers.IO) {
withTimeoutOrNull(timeout) {
var packet: MeshLog? = null
while (packet == null) {
packet = _meshLog.value.lastOrNull { it.meshPacket?.decoded?.requestId == packetId }
if (packet == null) delay(1000)
}
packet
}
}
fun requestTraceroute(destNum: Int) = viewModelScope.launch {
meshService?.let { service ->
try {
val packetId = service.packetId
val waitFactor = (service.nodes.count { it.isOnline } - 1)
.coerceAtMost(config.lora.hopLimit)
service.requestTraceroute(packetId, destNum)
_packetResponse.emit(getResponseBy(packetId, 20000L * waitFactor))
} catch (ex: RemoteException) {
errormsg("Request traceroute error: ${ex.message}")
}
}
}
fun generatePacketId(): Int? {
return try {
meshService?.packetId

Wyświetl plik

@ -1734,13 +1734,21 @@ class MeshService : Service(), Logging {
override fun requestPosition(idNum: Int, position: Position) =
toRemoteExceptions {
val (lat, lon, alt) = with(position) { Triple(latitude, longitude, altitude) }
val (lat, lon, alt) = position
// request position
if (idNum != 0) sendPosition(time = 1, destNum = idNum, wantResponse = true)
// set local node's fixed position
else sendPosition(time = 0, destNum = null, lat = lat, lon = lon, alt = alt)
}
override fun requestTraceroute(requestId: Int, destNum: Int) = toRemoteExceptions {
sendToRadio(newMeshPacketTo(destNum).buildMeshPacket(id = requestId) {
portnumValue = Portnums.PortNum.TRACEROUTE_APP_VALUE
payload = routeDiscovery {}.toByteString()
wantResponse = true
})
}
override fun requestShutdown(idNum: Int) = toRemoteExceptions {
sendToRadio(newMeshPacketTo(idNum).buildAdminPacket {
shutdownSeconds = 5

Wyświetl plik

@ -13,6 +13,7 @@ import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.asLiveData
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.geeksville.mesh.NodeInfo
@ -86,6 +87,12 @@ class UsersFragment : ScreenFragment("Users"), Logging {
model.requestPosition(node.num)
}
}
R.id.traceroute -> {
if (position > 0 && user != null) {
debug("requesting traceroute for ${user.longName}")
model.requestTraceroute(node.num)
}
}
R.id.reboot -> {
MaterialAlertDialogBuilder(requireContext())
.setTitle("${getString(R.string.reboot)}\n${user?.longName}?")
@ -323,6 +330,25 @@ class UsersFragment : ScreenFragment("Users"), Logging {
model.nodeDB.nodes.observe(viewLifecycleOwner) {
nodesAdapter.onNodesChanged(it.values.toTypedArray())
}
model.packetResponse.asLiveData().observe(viewLifecycleOwner) { meshLog ->
meshLog?.meshPacket?.let { meshPacket ->
val routeList = meshLog.routeDiscovery?.routeList
fun nodeName(num: Int) = model.nodeDB.nodesByNum?.get(num)?.user?.longName
var routeStr = "${nodeName(meshPacket.from)} --> "
routeList?.forEach { num -> routeStr += "${nodeName(num)} --> " }
routeStr += "${nodeName(meshPacket.to)}"
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.traceroute)
.setMessage(routeStr)
.setPositiveButton(R.string.okay) { _, _ -> }
.show()
model.clearPacketResponse()
}
}
}
override fun onDestroyView() {

Wyświetl plik

@ -10,6 +10,10 @@
android:id="@+id/request_position"
android:title="@string/request_position"
app:showAsAction="withText" />
<item
android:id="@+id/traceroute"
android:title="@string/traceroute"
app:showAsAction="withText" />
</group>
<group android:id="@+id/group_admin">
<item

Wyświetl plik

@ -127,6 +127,7 @@
<string name="resend">Resend</string>
<string name="shutdown">Shutdown</string>
<string name="reboot">Reboot</string>
<string name="traceroute">Traceroute</string>
<string name="intro_show">Show Introduction</string>
<string name="intro_welcome">Welcome to Meshtastic</string>
<string name="intro_welcome_text">Meshtastic is an open-source, off-grid, encrypted communication platform. The Meshtastic radios form a mesh network and communicate using the LoRa protocol to send text messages.</string>