Skip to content

Commit

Permalink
implement trace routes
Browse files Browse the repository at this point in the history
  • Loading branch information
liamcottle committed Nov 18, 2024
1 parent c72eb05 commit 3869a6b
Show file tree
Hide file tree
Showing 10 changed files with 298 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/components/App.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<template>
<div class="w-full">
<RouterView v-slot="{ Component }">
<RouterView v-slot="{ Component, route }">
<KeepAlive>
<Component :is="Component" />
<Component :is="Component" :key="route.fullPath" />
</KeepAlive>
</RouterView>
</div>
Expand Down
14 changes: 14 additions & 0 deletions src/components/nodes/NodeDropDownMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@
<span>Request Node Info</span>
</DropDownMenuItem>

<!-- trace route button -->
<RouterLink :to="{ name: 'node.traceroutes', params: { nodeId: node.num }}">
<DropDownMenuItem>
<svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 256 256" class="size-5">
<path d="M235.81,75.79A27.91,27.91,0,0,1,216,84a28.49,28.49,0,0,1-5.67-.58l-30.57,56.77,0,0a28,28,0,1,1-44.43,6.49l-26.06-26.06A28.07,28.07,0,0,1,96,124a28.41,28.41,0,0,1-5.67-.58L59.76,180.18l0,0a28,28,0,1,1-39.6,0h0a28,28,0,0,1,25.47-7.61l30.57-56.77,0,0a28.05,28.05,0,0,1,0-39.61h0a28,28,0,0,1,44.43,33.12l26.06,26.06a28.1,28.1,0,0,1,19-2.77l30.57-56.77,0,0a28,28,0,0,1,0-39.6h0a28,28,0,0,1,39.6,39.6Z"></path>
</svg>
<span>Trace Routes</span>
</DropDownMenuItem>
</RouterLink>

<!-- direct message button -->
<div class="border-t">
<a :href="`https://meshtastic.liamcottle.net/?node_id=${node.num}`" target="_blank">
Expand Down Expand Up @@ -102,6 +112,10 @@ export default {
alert("A request has been sent to the node to send its info back to us.");
},
onTraceRouteClick(node) {
// todo show loading screen
NodeAPI.traceRoute(node.num);
},
onDeleteNode(node) {
// confirm user wants to remove this node
Expand Down
102 changes: 102 additions & 0 deletions src/components/pages/NodeTraceRoutesPage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<template>
<Page>

<!-- app bar -->
<AppBar title="Trace Routes" :subtitle="subtitle">
<template v-slot:leading>
<NodeIcon v-if="node" :node="node" class="mr-3"/>
</template>
<template v-slot:trailing>
<IconButton v-if="node" @click="onNewTraceRouteClick(node)" class="mx-2 bg-transparent text-gray-700">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
</svg>
</IconButton>
</template>
</AppBar>

<!-- list -->
<div class="h-full w-full overflow-hidden">
<div v-for="traceRoute of reversedTraceRoutes" class="w-full">
<RouterLink :to="{ name: 'traceroute', params: { traceRouteId: traceRoute.id} }">
<div class="flex p-2 bg-white hover:bg-gray-50">
<div>
<div class="text-sm text-gray-900">
<span class="font-medium">{{ getNodeLongName(traceRoute.to) || '???' }}</span>
<span> to </span>
<span class="font-medium">{{ getNodeLongName(traceRoute.from) || '???' }}</span>
</div>
<div class="text-sm text-gray-700">
{{ getTimeAgo(traceRoute.rxTime) }} • {{ traceRoute.data.route.length }} hop(s) on channel {{ getChannelName(traceRoute.channel) }}
</div>
</div>
</div>
</RouterLink>
</div>
</div>

</Page>
</template>

<script>
import GlobalState from "../../js/GlobalState.js";
import AppBar from "../AppBar.vue";
import NodeIcon from "../nodes/NodeIcon.vue";
import Page from "./Page.vue";
import NodeUtils from "../../js/NodeUtils.js";
import IconButton from "../IconButton.vue";
import NodeAPI from "../../js/NodeAPI.js";
import ChannelUtils from "../../js/ChannelUtils.js";
import TimeUtils from "../../js/TimeUtils.js";
export default {
name: 'NodeTracesRoutePage',
components: {
Page,
AppBar,
IconButton,
NodeIcon,
},
props: {
nodeId: String | Number,
},
mounted() {
// redirect to main page if node not found
if(!this.node){
this.$router.push({
name: "main",
});
return;
}
},
methods: {
getNodeLongName: (nodeId) => NodeUtils.getNodeLongName(nodeId),
getTimeAgo: (date) => TimeUtils.getTimeAgo(date),
onNewTraceRouteClick(node) {
NodeAPI.traceRoute(node.num);
},
getChannelName: (channelId) => {
return ChannelUtils.getChannelName(channelId) || `#${channelId}`;
},
},
computed: {
node() {
return GlobalState.nodesById[this.nodeId];
},
subtitle() {
return this.node ? this.getNodeLongName(this.node.num) : "Unknown Node";
},
traceRoutes() {
// return traceroute responses from this node to us
return Object.values(GlobalState.traceRoutesById).filter((traceRoute) => {
return traceRoute.from === this.node.num && traceRoute.to === GlobalState.myNodeId;
});
},
reversedTraceRoutes() {
return this.traceRoutes.reverse();
},
},
}
</script>
140 changes: 140 additions & 0 deletions src/components/pages/TraceRoutePage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<template>
<Page>

<!-- app bar -->
<AppBar title="TraceRoute" :subtitle="subtitle"/>

<!-- list -->
<div v-if="traceRoute" class="flex flex-col h-full w-full overflow-hidden">
<div class="overflow-y-auto">

<!-- details -->
<div class="p-2 bg-white">
<ul role="list" class="space-y-3">

<!-- node that initiated traceroute -->
<li class="relative flex gap-x-4">
<div class="absolute left-0 top-0 flex w-12 justify-center top-3 -bottom-3">
<div class="w-px bg-gray-200"></div>
</div>
<div class="my-auto relative flex flex-none items-center justify-center">
<div>
<NodeIcon :node="findNodeById(this.traceRoute.to)"/>
</div>
</div>
<div class="flex-auto py-0.5 text-sm leading-5 text-gray-500">
<div class="font-medium text-gray-900">{{ getNodeLongName(this.traceRoute.to) || '???' }}</div>
<div>{{ getNodeHexId(this.traceRoute.to) }}</div>
<div>Started the traceroute</div>
</div>
</li>

<!-- middleman nodes -->
<li v-for="route of this.traceRoute.data.route" class="relative flex gap-x-4">
<div class="absolute left-0 top-0 flex w-12 justify-center -bottom-3">
<div class="w-px bg-gray-200"></div>
</div>
<div class="my-auto relative flex flex-none items-center justify-center">
<div>
<NodeIcon :node="findNodeById(route)"/>
</div>
</div>
<div class="flex-auto py-0.5 text-sm leading-5 text-gray-500">
<div class="font-medium text-gray-900">{{ getNodeLongName(route) || '???' }}</div>
<div>{{ getNodeHexId(route) }}</div>
<div>Forwarded the packet</div>
</div>
</li>

<!-- node that replied to traceroute -->
<li v-if="this.traceRoute.from" class="relative flex gap-x-4">
<div class="absolute left-0 top-0 flex w-12 justify-center h-6">
<div class="w-px bg-gray-200"></div>
</div>
<div class="my-auto relative flex flex-none items-center justify-center">
<div>
<NodeIcon :node="findNodeById(this.traceRoute.from)"/>
</div>
</div>
<div class="flex-auto py-0.5 text-sm leading-5 text-gray-500">

<div class="font-medium text-gray-900">{{ getNodeLongName(this.traceRoute.from) || '???' }}</div>
<div>{{ getNodeHexId(this.traceRoute.from) }}</div>
<div>Replied to traceroute</div>
</div>
</li>

</ul>

</div>

<!-- raw data -->
<div>
<div class="bg-gray-200 p-2 font-semibold">Raw Data</div>
<div class="text-sm text-gray-700">
<pre class="bg-white p-2 overflow-x-auto">{{ JSON.stringify(this.traceRoute, null, 4) }}</pre>
</div>
</div>

</div>
</div>

</Page>
</template>

<script>
import GlobalState from "../../js/GlobalState.js";
import AppBar from "../AppBar.vue";
import Page from "./Page.vue";
import NodeUtils from "../../js/NodeUtils.js";
import NodeIcon from "../nodes/NodeIcon.vue";
import moment from "moment";
import ChannelUtils from "../../js/ChannelUtils.js";
import TimeUtils from "../../js/TimeUtils.js";
export default {
name: 'TraceRoutePage',
components: {
NodeIcon,
Page,
AppBar,
},
props: {
traceRouteId: String | Number,
},
mounted() {
// redirect to main page if trace route not found
if(!this.traceRoute){
this.$router.push({
name: "main",
});
return;
}
},
methods: {
getNodeHexId: (nodeId) => NodeUtils.getNodeHexId(nodeId),
getNodeLongName: (nodeId) => NodeUtils.getNodeLongName(nodeId),
findNodeById(nodeId){
return GlobalState.nodesById[nodeId];
},
getTimeAgo: (date) => TimeUtils.getTimeAgo(date),
getChannelName: (channelId) => {
return ChannelUtils.getChannelName(channelId) || `#${channelId}`;
},
},
computed: {
traceRoute() {
return GlobalState.traceRoutesById[this.traceRouteId];
},
subtitle() {
if(this.traceRoute){
return `${this.getTimeAgo(this.traceRoute.rxTime)}${this.traceRoute.data.route.length} hop(s) on channel ${this.getChannelName(this.traceRoute.channel)}`;
} else {
return `#${this.traceRouteId}`;
}
},
},
}
</script>
12 changes: 12 additions & 0 deletions src/js/ChannelUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import GlobalState from "./GlobalState.js";

class ChannelUtils {

static getChannelName(channelId) {
const channel = GlobalState.channelsByIndex[channelId];
return channel?.settings?.name;
}

}

export default ChannelUtils;
7 changes: 7 additions & 0 deletions src/js/Connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,13 @@ class Connection {

});

// listen for trace routes
GlobalState.traceRoutesById = {};
connection.events.onTraceRoutePacket.subscribe((data) => {
console.log("onTraceRoutePacket", data);
GlobalState.traceRoutesById[data.id] = data;
});

}

static onPacketAck(requestId, ackedByNodeId) {
Expand Down
1 change: 1 addition & 0 deletions src/js/GlobalState.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const globalState = reactive({
channelsByIndex: {},
nodesById: {},
messages: [],
traceRoutesById: {},

});

Expand Down
4 changes: 4 additions & 0 deletions src/js/NodeAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ class NodeAPI {
return await GlobalState.connection.removeNodeByNum(nodeId);
}

static async traceRoute(nodeId) {
return await GlobalState.connection.traceRoute(nodeId);
}

}

export default NodeAPI;
4 changes: 4 additions & 0 deletions src/js/TimeUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import moment from "moment";

class TimeUtils {

static getTimeAgo(date) {
return moment(date).fromNow();
};

static getTimeAgoShortHand(date) {

// get duration between now and provided date
Expand Down
12 changes: 12 additions & 0 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,18 @@ const router = createRouter({
props: true,
component: () => import("./components/pages/NodeMessagesPage.vue"),
},
{
name: "node.traceroutes",
path: '/nodes/:nodeId/traceroutes',
props: true,
component: () => import("./components/pages/NodeTraceRoutesPage.vue"),
},
{
name: "traceroute",
path: '/traceroutes/:traceRouteId',
props: true,
component: () => import("./components/pages/TraceRoutePage.vue"),
},
],
});

Expand Down

0 comments on commit 3869a6b

Please sign in to comment.