From dc33f5ec82ba26257fc461fc4635d12b84b96b23 Mon Sep 17 00:00:00 2001 From: liamcottle Date: Tue, 19 Nov 2024 01:58:21 +1300 Subject: [PATCH] implement database persistence for trace routes --- src/components/messages/MessageViewer.vue | 2 +- .../pages/NodeRunTraceRoutePage.vue | 21 ++-- src/components/pages/NodeTraceRoutesPage.vue | 64 ++++++----- src/components/pages/TraceRoutePage.vue | 42 ++++---- src/js/Connection.js | 5 +- src/js/Database.js | 102 +++++++++++++++++- src/js/GlobalState.js | 1 - 7 files changed, 170 insertions(+), 67 deletions(-) diff --git a/src/components/messages/MessageViewer.vue b/src/components/messages/MessageViewer.vue index 5c30368..e279772 100644 --- a/src/components/messages/MessageViewer.vue +++ b/src/components/messages/MessageViewer.vue @@ -214,7 +214,7 @@ export default { onMessagesUpdated(messages) { // update messages in ui - this.messages = messages; + this.messages = messages.map((message) => message.toJSON()); // auto scroll to bottom if we want to if(this.autoScrollOnNewMessage){ diff --git a/src/components/pages/NodeRunTraceRoutePage.vue b/src/components/pages/NodeRunTraceRoutePage.vue index 5729ce1..ba12cc6 100644 --- a/src/components/pages/NodeRunTraceRoutePage.vue +++ b/src/components/pages/NodeRunTraceRoutePage.vue @@ -71,6 +71,7 @@ import Page from "./Page.vue"; import NodeUtils from "../../js/NodeUtils.js"; import NodeAPI from "../../js/NodeAPI.js"; import Connection from "../../js/Connection.js"; +import Database from "../../js/Database.js"; export default { name: 'NodeTracesRoutePage', @@ -115,9 +116,6 @@ export default { }, methods: { getNodeLongName: (nodeId) => NodeUtils.getNodeLongName(nodeId), - onNewTraceRouteClick(node) { - NodeAPI.traceRoute(node.num); - }, async runTraceRoute(node) { // do nothing if already running @@ -129,7 +127,11 @@ export default { this.isRunningTraceRoute = true; // run trace route - await NodeAPI.traceRoute(node.num); + try { + await NodeAPI.traceRoute(node.num); + } catch(e) { + // don't care about timeout + } }, onIgnoreResultClick() { @@ -142,18 +144,25 @@ export default { } } }, - onTraceRouteComplete(traceRoute) { + async onTraceRouteComplete(traceRoute) { // no longer running trace route this.isRunningTraceRoute = false; + // find latest trace route by packet id + const databaseTraceRoute = await Database.TraceRoute.findTraceRouteByPacketId(traceRoute.id).exec(); + if(!databaseTraceRoute){ + return; + } + // go to trace route page this.$router.push({ name: "traceroute", params: { - traceRouteId: traceRoute.id, + traceRouteId: databaseTraceRoute.id, }, }); + }, onClientNotification(clientNotification) { diff --git a/src/components/pages/NodeTraceRoutesPage.vue b/src/components/pages/NodeTraceRoutesPage.vue index 5051b6f..e2211cd 100644 --- a/src/components/pages/NodeTraceRoutesPage.vue +++ b/src/components/pages/NodeTraceRoutesPage.vue @@ -18,22 +18,24 @@ -
-
- -
-
-
- {{ getNodeLongName(traceRoute.to) || '???' }} - to - {{ getNodeLongName(traceRoute.from) || '???' }} -
-
- {{ getTimeAgo(traceRoute.rxTime) }} • {{ traceRoute.data.route.length }} hop(s) on channel {{ getChannelName(traceRoute.channel) }} +
+
+
+ +
+
+
+ {{ getNodeLongName(traceRoute.to) || '???' }} + to + {{ getNodeLongName(traceRoute.from) || '???' }} +
+
+ {{ getTimeAgo(new Date(traceRoute.timestamp)) }} • {{ traceRoute.data.route.length }} hop(s) on channel {{ getChannelName(traceRoute.channel) }} +
-
- + +
@@ -47,9 +49,9 @@ 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"; +import Database from "../../js/Database.js"; export default { name: 'NodeTracesRoutePage', @@ -62,23 +64,26 @@ export default { props: { nodeId: String | Number, }, + data() { + return { + traceRoutes: [], + traceRoutesSubscription: null, + }; + }, mounted() { - // redirect to main page if node not found - if(!this.node){ - this.$router.push({ - name: "main", - }); - return; - } + // init database subscription for trace routes + this.traceRoutesSubscription = Database.TraceRoute.getTraceRoutesByNodeId(this.nodeId).$.subscribe((traceRoutes) => { + this.traceRoutes = traceRoutes.map((traceRoute) => traceRoute.toJSON()).reverse(); + }); }, + unmounted() { + this.traceRoutesSubscription?.unsubscribe(); + }, methods: { getNodeLongName: (nodeId) => NodeUtils.getNodeLongName(nodeId), getTimeAgo: (date) => TimeUtils.getTimeAgo(date), - onNewTraceRouteClick(node) { - NodeAPI.traceRoute(node.num); - }, getChannelName: (channelId) => { return ChannelUtils.getChannelName(channelId) || `#${channelId}`; }, @@ -90,15 +95,6 @@ export default { 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(); - }, }, } diff --git a/src/components/pages/TraceRoutePage.vue b/src/components/pages/TraceRoutePage.vue index f4d26c1..647cb0c 100644 --- a/src/components/pages/TraceRoutePage.vue +++ b/src/components/pages/TraceRoutePage.vue @@ -19,18 +19,18 @@
- +
-
{{ getNodeLongName(this.traceRoute.to) || '???' }}
-
{{ getNodeHexId(this.traceRoute.to) }}
+
{{ getNodeLongName(traceRoute.to) || '???' }}
+
{{ getNodeHexId(traceRoute.to) }}
Started the traceroute
-
  • +
  • @@ -47,19 +47,19 @@
  • -
  • +
  • - +
    -
    {{ getNodeLongName(this.traceRoute.from) || '???' }}
    -
    {{ getNodeHexId(this.traceRoute.from) }}
    +
    {{ getNodeLongName(traceRoute.from) || '???' }}
    +
    {{ getNodeHexId(traceRoute.from) }}
    Replied to traceroute
  • @@ -72,7 +72,7 @@
    Raw Data
    -
    {{ JSON.stringify(this.traceRoute, null, 4) }}
    +
    {{ JSON.stringify(traceRoute, null, 4) }}
    @@ -91,6 +91,7 @@ import NodeIcon from "../nodes/NodeIcon.vue"; import moment from "moment"; import ChannelUtils from "../../js/ChannelUtils.js"; import TimeUtils from "../../js/TimeUtils.js"; +import Database from "../../js/Database.js"; export default { name: 'TraceRoutePage', @@ -102,17 +103,23 @@ export default { props: { traceRouteId: String | Number, }, + data() { + return { + traceRoute: null, + traceRouteSubscription: null, + }; + }, mounted() { - // redirect to main page if trace route not found - if(!this.traceRoute){ - this.$router.push({ - name: "main", - }); - return; - } + // find trace route by id + this.traceRouteSubscription = Database.TraceRoute.findTraceRouteById(this.traceRouteId).$.subscribe((traceRoute) => { + this.traceRoute = traceRoute?.toJSON(); + }); }, + beforeUnmount() { + this.traceRouteSubscription?.unsubscribe(); + }, methods: { getNodeHexId: (nodeId) => NodeUtils.getNodeHexId(nodeId), getNodeLongName: (nodeId) => NodeUtils.getNodeLongName(nodeId), @@ -125,9 +132,6 @@ export default { }, }, 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)}`; diff --git a/src/js/Connection.js b/src/js/Connection.js index 568b855..3743128 100644 --- a/src/js/Connection.js +++ b/src/js/Connection.js @@ -244,10 +244,9 @@ class Connection { }); // listen for trace routes - GlobalState.traceRoutesById = {}; - connection.events.onTraceRoutePacket.subscribe((data) => { + connection.events.onTraceRoutePacket.subscribe(async (data) => { console.log("onTraceRoutePacket", data); - GlobalState.traceRoutesById[data.id] = data; + await Database.TraceRoute.insert(data); for(const traceRouteListener of this.traceRouteListeners){ try { traceRouteListener(data); diff --git a/src/js/Database.js b/src/js/Database.js index 747b23a..d28cbd7 100644 --- a/src/js/Database.js +++ b/src/js/Database.js @@ -49,6 +49,7 @@ async function initDatabase(nodeId) { from: { type: 'integer', }, + // todo channel hash for when a channel changes slots, or is deleted then recreated later channel: { type: 'integer', }, @@ -67,6 +68,37 @@ async function initDatabase(nodeId) { }, } }, + traceroutes: { + schema: { + version: 0, + primaryKey: 'id', + type: 'object', + properties: { + id: { + type: 'string', + maxLength: 36, + }, + packet_id: { + type: 'integer', + }, + to: { + type: 'integer', + }, + from: { + type: 'integer', + }, + channel: { + type: 'integer', + }, + data: { + type: 'object', + }, + timestamp: { + type: 'integer', + }, + }, + } + }, }); } @@ -102,7 +134,7 @@ class Message { }, sort: [ { - timestamp: "asc", + timestamp: "desc", }, ], }); @@ -126,7 +158,7 @@ class Message { }, sort: [ { - timestamp: "asc", + timestamp: "desc", }, ], }); @@ -153,7 +185,7 @@ class Message { }, sort: [ { - timestamp: "asc", + timestamp: "desc", }, ], }); @@ -219,7 +251,71 @@ class Message { } +class TraceRoute { + + // insert a traceroute into the database + static async insert(data) { + return await database.traceroutes.insert({ + id: v4(), + packet_id: data.id, + to: data.to, + from: data.from, + channel: data.channel, + data: data.data, + timestamp: data.rxTime.getTime(), + }); + } + + // get traceroute responses from the provided node id + static getTraceRoutesByNodeId(nodeId) { + return database.traceroutes.find({ + selector: { + to: { + $eq: GlobalState.myNodeId, + }, + from: { + $eq: parseInt(nodeId), + }, + }, + sort: [ + { + timestamp: "asc", + }, + ], + }); + } + + // find traceroute by id + static findTraceRouteById(id) { + return database.traceroutes.findOne({ + selector: { + id: { + $eq: id, + }, + }, + }); + } + + // find traceroute by packet id + static findTraceRouteByPacketId(packetId) { + return database.traceroutes.findOne({ + selector: { + packet_id: { + $eq: packetId, + }, + }, + sort: [ + { + timestamp: "desc", + }, + ], + }); + } + +} + export default { initDatabase, Message, + TraceRoute, }; diff --git a/src/js/GlobalState.js b/src/js/GlobalState.js index 312d0fc..7b2706e 100644 --- a/src/js/GlobalState.js +++ b/src/js/GlobalState.js @@ -14,7 +14,6 @@ const globalState = reactive({ channelsByIndex: {}, nodesById: {}, - traceRoutesById: {}, });