Traceroute rendering

This commit is contained in:
Daniel Pupius
2025-04-29 13:09:06 -07:00
parent 501c093242
commit 44dc97c529
5 changed files with 100 additions and 3 deletions

View File

@@ -26,9 +26,11 @@ format: |
{{- if $data.textMessage }} {{- if $data.textMessage }}
{{ "Text:" | dim }} {{ $data.textMessage }} {{ "Text:" | dim }} {{ $data.textMessage }}
{{- else if $data.mapReport }} {{- else if $data.mapReport }}
{{ "Map Report:" | dim }} {{ $data.mapReport | table }} {{ "Map Report:" | dim }}
{{ $data.mapReport | table }}
{{- else if $data.routeDiscovery }} {{- else if $data.routeDiscovery }}
{{ "Route Discovery:" | dim }} {{ $data.routeDiscovery | table }} {{ "Route Discovery:" | dim }}
{{ $data.routeDiscovery | table }}
{{- else if $data.position }} {{- else if $data.position }}
{{ "Position:" | dim }} Lat: {{ $data.position.latitudeI | mult 0.0000001 }}, Long: {{ $data.position.longitudeI | mult 0.0000001 }} {{ "Position:" | dim }} Lat: {{ $data.position.latitudeI | mult 0.0000001 }}, Long: {{ $data.position.longitudeI | mult 0.0000001 }}
{{- else if $data.nodeInfo }} {{- else if $data.nodeInfo }}

View File

@@ -7,6 +7,7 @@ import { TelemetryPacket } from "./TelemetryPacket";
import { ErrorPacket } from "./ErrorPacket"; import { ErrorPacket } from "./ErrorPacket";
import { WaypointPacket } from "./WaypointPacket"; import { WaypointPacket } from "./WaypointPacket";
import { MapReportPacket } from "./MapReportPacket"; import { MapReportPacket } from "./MapReportPacket";
import { TraceroutePacket } from "./TraceroutePacket";
import { GenericPacket } from "./GenericPacket"; import { GenericPacket } from "./GenericPacket";
interface PacketRendererProps { interface PacketRendererProps {
@@ -45,6 +46,9 @@ export const PacketRenderer: React.FC<PacketRendererProps> = ({ packet }) => {
case PortNum.MAP_REPORT_APP: case PortNum.MAP_REPORT_APP:
return <MapReportPacket packet={packet} />; return <MapReportPacket packet={packet} />;
case PortNum.TRACEROUTE_APP:
return <TraceroutePacket packet={packet} />;
default: default:
return <GenericPacket packet={packet} />; return <GenericPacket packet={packet} />;

View File

@@ -32,7 +32,6 @@ export const PositionPacket: React.FC<PositionPacketProps> = ({ packet }) => {
icon={<MapPin />} icon={<MapPin />}
iconBgColor="bg-emerald-500" iconBgColor="bg-emerald-500"
label="Position" label="Position"
backgroundColor="bg-emerald-950/5"
> >
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div> <div>

View File

@@ -0,0 +1,89 @@
import React from "react";
import { Packet } from "../../lib/types";
import { PacketCard } from "./PacketCard";
import { RouteIcon } from "lucide-react";
import { Link } from "@tanstack/react-router";
interface TraceroutePacketProps {
packet: Packet;
}
export const TraceroutePacket: React.FC<TraceroutePacketProps> = ({ packet }) => {
const { data } = packet;
const routeDiscovery = data.routeDiscovery;
if (!routeDiscovery) {
return null;
}
// Convert a nodenum to hex format for display and linking
const formatNodeId = (nodeNum: number) => {
return nodeNum.toString(16).toLowerCase();
};
// Renders a node hop with SNR info if available
const renderHop = (nodeNum: number, index: number, snrValues?: number[]) => {
const nodeHex = formatNodeId(nodeNum);
const snr = snrValues && snrValues[index];
return (
<React.Fragment key={`hop-${index}`}>
<Link
to="/node/$nodeId"
params={{ nodeId: nodeHex }}
className="text-blue-400 hover:underline"
>
!{nodeHex}
</Link>
{snr !== undefined && (
<span className="text-neutral-400 text-xs ml-1">
({(snr / 4).toFixed(1)} dB)
</span>
)}
{index < (routeDiscovery.route?.length || 0) - 1 && (
<span className="mx-2 text-neutral-500"></span>
)}
</React.Fragment>
);
};
return (
<PacketCard
packet={packet}
icon={<RouteIcon />}
iconBgColor="bg-purple-700"
label="Traceroute"
>
<div className="space-y-6">
{routeDiscovery.route && routeDiscovery.route.length > 0 && (
<div>
<h3 className="text-neutral-300 font-semibold mb-2">Route to destination:</h3>
<div className="flex flex-wrap items-center text-sm">
{routeDiscovery.route.map((nodeNum, index) =>
renderHop(nodeNum, index, routeDiscovery.snrTowards)
)}
</div>
</div>
)}
{routeDiscovery.routeBack && routeDiscovery.routeBack.length > 0 && (
<div>
<h3 className="text-neutral-300 font-semibold mb-2">Return route:</h3>
<div className="flex flex-wrap items-center text-sm">
{routeDiscovery.routeBack.map((nodeNum, index) =>
renderHop(nodeNum, index, routeDiscovery.snrBack)
)}
</div>
</div>
)}
{(!routeDiscovery.route || routeDiscovery.route.length === 0) &&
(!routeDiscovery.routeBack || routeDiscovery.routeBack.length === 0) && (
<div className="text-neutral-400">
No route information available.
</div>
)}
</div>
</PacketCard>
);
};

View File

@@ -2,6 +2,9 @@ export * from './TextMessagePacket';
export * from './PositionPacket'; export * from './PositionPacket';
export * from './NodeInfoPacket'; export * from './NodeInfoPacket';
export * from './TelemetryPacket'; export * from './TelemetryPacket';
export * from './WaypointPacket';
export * from './MapReportPacket';
export * from './TraceroutePacket';
export * from './GenericPacket'; export * from './GenericPacket';
export * from './ErrorPacket'; export * from './ErrorPacket';
export * from './PacketRenderer'; export * from './PacketRenderer';