From 0fcf27a77f2996b1eae2746875a1a0d95cc37e0f Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Sun, 1 Jan 2023 01:23:30 +1100 Subject: [PATCH] device store cleanup & peers page improvements --- package.json | 3 +- pnpm-lock.yaml | 23 +- .../PageComponents/Config/Network.tsx | 2 - .../PageComponents/Messages/ChannelChat.tsx | 7 +- .../PageComponents/Messages/Message.tsx | 13 +- src/core/stores/deviceStore.ts | 204 ++++++++---------- src/core/subscriptions.ts | 20 +- src/pages/Peers.tsx | 6 +- 8 files changed, 132 insertions(+), 146 deletions(-) diff --git a/package.json b/package.json index cce101d6..cb7b69d2 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "@heroicons/react": "^2.0.13", "@hookform/error-message": "^2.0.1", "@hookform/resolvers": "^2.9.10", - "@meshtastic/meshtasticjs": "^0.9.2", + "@meshtastic/meshtasticjs": "^0.9.7", "@tailwindcss/line-clamp": "^0.4.2", "@tailwindcss/typography": "^0.5.8", "@turf/turf": "^6.5.0", @@ -52,6 +52,7 @@ "react-map-gl": "^7.0.20", "react-qrcode-logo": "^2.8.0", "rfc4648": "^1.5.2", + "timeago-react": "^3.0.5", "zustand": "4.1.5" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 89a6d4f9..233f15b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,7 +6,7 @@ specifiers: '@heroicons/react': ^2.0.13 '@hookform/error-message': ^2.0.1 '@hookform/resolvers': ^2.9.10 - '@meshtastic/meshtasticjs': ^0.9.2 + '@meshtastic/meshtasticjs': ^0.9.7 '@tailwindcss/forms': ^0.5.3 '@tailwindcss/line-clamp': ^0.4.2 '@tailwindcss/typography': ^0.5.8 @@ -56,6 +56,7 @@ specifiers: rollup-plugin-visualizer: ^5.9.0 tailwindcss: ^3.2.4 tar: ^6.1.13 + timeago-react: ^3.0.5 tslib: ^2.4.1 typescript: ^4.9.4 unimported: ^1.24.0 @@ -70,7 +71,7 @@ dependencies: '@heroicons/react': 2.0.13_react@18.2.0 '@hookform/error-message': 2.0.1_7yhncxxycytkes3mwygyjxyp6u '@hookform/resolvers': 2.9.10_react-hook-form@7.41.3 - '@meshtastic/meshtasticjs': 0.9.2 + '@meshtastic/meshtasticjs': 0.9.7 '@tailwindcss/line-clamp': 0.4.2_tailwindcss@3.2.4 '@tailwindcss/typography': 0.5.8_tailwindcss@3.2.4 '@turf/turf': 6.5.0 @@ -95,6 +96,7 @@ dependencies: react-map-gl: 7.0.20_6eczaga5xxiwzxtfiyk6fioasq react-qrcode-logo: 2.8.0_biqbaboplfbrettd7655fr4n2y rfc4648: 1.5.2 + timeago-react: 3.0.5_react@18.2.0 zustand: 4.1.5_immer@9.0.16+react@18.2.0 devDependencies: @@ -1710,8 +1712,8 @@ packages: engines: {node: '>=6.0.0'} dev: false - /@meshtastic/meshtasticjs/0.9.2: - resolution: {integrity: sha512-rS/dK3RekRC9R930/RbNgdcktQ/XZv/bPpFZ6/6PJ61+8NjguN6SeNE3GP007TS5GSkp0zu3IgfOHn+pEL94KA==} + /@meshtastic/meshtasticjs/0.9.7: + resolution: {integrity: sha512-FQAfgJ2FeC55HbmOR1Z7Y3iIyXN32YO5OmtsviPolaZWivE7cCCfwSQGOHrtQUwXUSRv6Up0ucJ0eW7teaXxhA==} dependencies: '@protobuf-ts/runtime': 2.8.2 glob: 8.0.3 @@ -6430,6 +6432,19 @@ packages: readable-stream: 3.6.0 dev: true + /timeago-react/3.0.5_react@18.2.0: + resolution: {integrity: sha512-1k/aDt+ADpcABCmg3BIBuZSa7aSxolmuYFkdcpL7mlNkFcDAK/KwuxLf68gowhM7Oq3vWTE7LPeq3kLkSt45Jg==} + peerDependencies: + react: ^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + timeago.js: 4.0.2 + dev: false + + /timeago.js/4.0.2: + resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==} + dev: false + /tiny-glob/0.2.9: resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} dependencies: diff --git a/src/components/PageComponents/Config/Network.tsx b/src/components/PageComponents/Config/Network.tsx index df6abb12..17c0e12a 100644 --- a/src/components/PageComponents/Config/Network.tsx +++ b/src/components/PageComponents/Config/Network.tsx @@ -52,8 +52,6 @@ export const Network = (): JSX.Element => { }, [reset, config.network]); const onSubmit = handleSubmit((data) => { - console.log(data); - if (connection) { void toast.promise( connection diff --git a/src/components/PageComponents/Messages/ChannelChat.tsx b/src/components/PageComponents/Messages/ChannelChat.tsx index bd692a64..7e57fd88 100644 --- a/src/components/PageComponents/Messages/ChannelChat.tsx +++ b/src/components/PageComponents/Messages/ChannelChat.tsx @@ -22,12 +22,9 @@ export const ChannelChat = ({ channel }: ChannelChatProps): JSX.Element => { lastMsgSameUser={ index === 0 ? false - : channel.messages[index - 1].packet.from === - message.packet.from - } - sender={ - nodes.find((node) => node.data.num === message.packet.from)?.data + : channel.messages[index - 1].from === message.from } + sender={nodes.find((node) => node.data.num === message.from)?.data} /> ))} diff --git a/src/components/PageComponents/Messages/Message.tsx b/src/components/PageComponents/Messages/Message.tsx index 3b8857d2..57ecba7d 100644 --- a/src/components/PageComponents/Messages/Message.tsx +++ b/src/components/PageComponents/Messages/Message.tsx @@ -25,12 +25,12 @@ export const Message = ({ const { setPeerInfoOpen, setActivePeer, connection } = useDevice(); const openPeer = (): void => { - setActivePeer(message.packet.from); + setActivePeer(message.from); setPeerInfoOpen(true); }; return lastMsgSameUser ? ( -
+
{message.state === "ack" ? ( ) : message.state === "waiting" ? ( @@ -46,7 +46,7 @@ export const Message = ({ message.state === "ack" ? "text-textPrimary" : "text-textSecondary" }`} > - {message.text} + {message.data} )}
@@ -63,14 +63,13 @@ export const Message = ({ {sender?.user?.longName ?? "UNK"} - {new Date(message.packet.rxTime).toLocaleTimeString(undefined, { + {message.rxTime.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" })}
-
- {/* */} +
{message.state === "ack" ? ( ) : message.state === "waiting" ? ( @@ -88,7 +87,7 @@ export const Message = ({ : "text-textSecondary" }`} > - {message.text} + {message.data} )}
diff --git a/src/core/stores/deviceStore.ts b/src/core/stores/deviceStore.ts index 2a13348a..860ca1b5 100644 --- a/src/core/stores/deviceStore.ts +++ b/src/core/stores/deviceStore.ts @@ -15,12 +15,12 @@ export type Page = | "info" | "logs"; -export interface MessageWithState extends Types.MessagePacket { +export interface MessageWithState extends Types.PacketMetadata { state: MessageState; } export interface WaypointIDWithState - extends Omit { + extends Omit, "data"> { waypointID: number; state: MessageState; } @@ -42,6 +42,12 @@ export interface Node { data: Protobuf.NodeInfo; } +export interface processPacketParams { + from: number; + snr: number; + time: number; +} + export interface Device { id: number; ready: boolean; @@ -69,20 +75,22 @@ export interface Device { setConfig: (config: Protobuf.Config) => void; setModuleConfig: (config: Protobuf.ModuleConfig) => void; setHardware: (hardware: Protobuf.MyNodeInfo) => void; - setMetrics: (metrics: Types.TelemetryPacket) => void; + setMetrics: (metrics: Types.PacketMetadata) => void; setActivePage: (page: Page) => void; setPeerInfoOpen: (open: boolean) => void; setActivePeer: (peer: number) => void; setPendingSettingsChanges: (state: boolean) => void; addChannel: (channel: Channel) => void; addWaypoint: (waypoint: Protobuf.Waypoint) => void; - addNodeInfo: (nodeInfo: Types.NodeInfoPacket) => void; - addUser: (user: Types.UserPacket) => void; - addPosition: (position: Types.PositionPacket) => void; + addNodeInfo: (nodeInfo: Protobuf.NodeInfo) => void; + addUser: (user: Types.PacketMetadata) => void; + addPosition: (position: Types.PacketMetadata) => void; addConnection: (connection: Types.ConnectionType) => void; addMessage: (message: MessageWithState) => void; addWaypointMessage: (message: WaypointIDWithState) => void; - addDeviceMetadataMessage: (metadata: Types.DeviceMetadataPacket) => void; + addDeviceMetadataMessage: ( + metadata: Types.PacketMetadata + ) => void; setMessageState: ( channelIndex: number, messageId: number, @@ -92,6 +100,7 @@ export interface Device { setQRDialogOpen: (open: boolean) => void; setShutdownDialogOpen: (open: boolean) => void; setRebootDialogOpen: (open: boolean) => void; + processPacket: (data: processPacketParams) => void; } export interface DeviceState { @@ -237,27 +246,13 @@ export const useDeviceStore = create((set, get) => ({ }) ); }, - setMetrics: (metrics: Types.TelemetryPacket) => { + setMetrics: (metrics: Types.PacketMetadata) => { set( produce((draft) => { const device = draft.devices.get(id); let node = device?.nodes.find( - (n) => n.data.num === metrics.packet.from + (n) => n.data.num === metrics.from ); - if (device && !node) { - node = { - data: Protobuf.NodeInfo.create({ - num: metrics.packet.from, - snr: metrics.packet.rxSnr, - lastHeard: Date.now() - }), - metadata: undefined, - deviceMetrics: [], - environmentMetrics: [] - }; - - device.nodes.push(node); - } if (node) { switch (metrics.data.variant.oneofKind) { case "deviceMetrics": @@ -283,19 +278,13 @@ export const useDeviceStore = create((set, get) => ({ } node.deviceMetrics.push({ ...metrics.data.variant.deviceMetrics, - timestamp: - metrics.packet.rxTime === 0 - ? new Date() - : new Date(metrics.packet.rxTime * 1000) + timestamp: metrics.rxTime }); break; case "environmentMetrics": node.environmentMetrics.push({ ...metrics.data.variant.environmentMetrics, - timestamp: - metrics.packet.rxTime === 0 - ? new Date() - : new Date(metrics.packet.rxTime * 1000) + timestamp: metrics.rxTime }); break; } @@ -364,30 +353,18 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { const device = draft.devices.get(id); - if (device) { - const node = device.nodes.find( - (node) => node.data.num === nodeInfo.data.num - ); - if (node) { - node.data = nodeInfo.data; - node.data.lastHeard = - nodeInfo.packet.rxTime !== 0 - ? nodeInfo.packet.rxTime * 1000 - : Date.now(); - } else { - device.nodes.push({ - data: Protobuf.NodeInfo.create({ - ...nodeInfo.data, - lastHeard: - nodeInfo.packet.rxTime !== 0 - ? nodeInfo.packet.rxTime * 1000 - : Date.now() - }), - metadata: undefined, - deviceMetrics: [], - environmentMetrics: [] - }); - } + const node = device?.nodes.find( + (node) => node.data.num === nodeInfo.num + ); + if (node) { + node.data = nodeInfo; + } else { + device?.nodes.push({ + data: nodeInfo, + metadata: undefined, + deviceMetrics: [], + environmentMetrics: [] + }); } }) ); @@ -416,29 +393,11 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { const device = draft.devices.get(id); - if (device) { - const node = device.nodes.find( - (node) => node.data.num === user.packet.from - ); - if (node) { - node.data.user = user.data; - // if (action.payload.packet.rxTime) { - // node.data.lastHeard = new Date( - // action.payload.packet.rxTime * 1000, - // ).getTime(); - // } - } else { - device.nodes.push({ - data: Protobuf.NodeInfo.create({ - num: user.packet.from, - snr: user.packet.rxSnr, - user: user.data - }), - metadata: undefined, - deviceMetrics: [], - environmentMetrics: [] - }); - } + const node = device?.nodes.find( + (node) => node.data.num === user.from + ); + if (node) { + node.data.user = user.data; } }) ); @@ -447,28 +406,11 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { const device = draft.devices.get(id); - if (device) { - const node = device.nodes.find( - (node) => node.data.num === position.packet.from - ); - if (node) { - node.data.position = position.data; - // if (action.payload.packet.rxTime) { - // node.data.lastHeard = new Date( - // action.payload.packet.rxTime * 1000, - // ).getTime(); - // } - } else { - device.nodes.push({ - data: Protobuf.NodeInfo.create({ - num: position.packet.from, - position: position.data - }), - metadata: undefined, - deviceMetrics: [], - environmentMetrics: [] - }); - } + const node = device?.nodes.find( + (node) => node.data.num === position.from + ); + if (node) { + node.data.position = position.data; } }) ); @@ -487,11 +429,9 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { const device = draft.devices.get(id); - if (device) { - device.channels - .find((ch) => ch.config.index === message.packet.channel) - ?.messages.push(message); - } + device?.channels + .find((ch) => ch.config.index === message.channel) + ?.messages.push(message); }) ); }, @@ -499,11 +439,9 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { const device = draft.devices.get(id); - if (device) { - device.channels - .find((ch) => ch.config.index === waypointID.packet.channel) - ?.messages.push(waypointID); - } + device?.channels + .find((ch) => ch.config.index === waypointID.channel) + ?.messages.push(waypointID); }) ); }, @@ -511,15 +449,11 @@ export const useDeviceStore = create((set, get) => ({ set( produce((draft) => { const device = draft.devices.get(id); - if (device) { - const node = device.nodes.find( - (n) => n.data.num === metadata.packet.from - ); - if (node) { - node.metadata = metadata.data; - } else { - console.log("Node not found!"); - } + const node = device?.nodes.find( + (n) => n.data.num === metadata.from + ); + if (node) { + node.metadata = metadata.data; } }) ); @@ -537,7 +471,7 @@ export const useDeviceStore = create((set, get) => ({ (ch) => ch.config.index === channelIndex ); const message = channel?.messages.find( - (msg) => msg.packet.id === messageId + (msg) => msg.id === messageId ); if (message) { message.state = state; @@ -584,6 +518,36 @@ export const useDeviceStore = create((set, get) => ({ } }) ); + }, + processPacket(data: processPacketParams) { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + const node = device.nodes.find((n) => n.data.num === data.from); + if (!node) { + device.nodes.push({ + data: Protobuf.NodeInfo.create({ + num: data.from, + lastHeard: data.time, + snr: data.snr + }), + metadata: undefined, + deviceMetrics: [], + environmentMetrics: [] + }); + return; + } else { + node.data = { + ...node.data, + lastHeard: data.time, + snr: data.snr + }; + } + }) + ); } }); }) diff --git a/src/core/subscriptions.ts b/src/core/subscriptions.ts index 36964d59..22322289 100644 --- a/src/core/subscriptions.ts +++ b/src/core/subscriptions.ts @@ -65,7 +65,7 @@ export const subscribeAll = ( device.addWaypoint(data); device.addWaypointMessage({ waypointID: data.id, - state: rest.packet.from !== myNodeNum ? "ack" : "waiting", + state: rest.from !== myNodeNum ? "ack" : "waiting", ...rest }); }); @@ -84,7 +84,7 @@ export const subscribeAll = ( }); connection.events.onNodeInfoPacket.subscribe((nodeInfo) => { - toast(`New Node Discovered: ${nodeInfo.data.user?.shortName ?? "UNK"}`, { + toast(`New Node Discovered: ${nodeInfo.user?.shortName ?? "UNK"}`, { icon: "🔎" }); device.addNodeInfo(nodeInfo); @@ -92,26 +92,34 @@ export const subscribeAll = ( connection.events.onChannelPacket.subscribe((channel) => { device.addChannel({ - config: channel.data, + config: channel, lastInterraction: new Date(), messages: [] }); }); connection.events.onConfigPacket.subscribe((config) => { - device.setConfig(config.data); + device.setConfig(config); }); connection.events.onModuleConfigPacket.subscribe((moduleConfig) => { - device.setModuleConfig(moduleConfig.data); + device.setModuleConfig(moduleConfig); }); connection.events.onMessagePacket.subscribe((messagePacket) => { device.addMessage({ ...messagePacket, - state: messagePacket.packet.from !== myNodeNum ? "ack" : "waiting" + state: messagePacket.from !== myNodeNum ? "ack" : "waiting" }); }); connection.events.onPendingSettingsChange.subscribe((state) => { device.setPendingSettingsChanges(state); }); + + connection.events.onMeshPacket.subscribe((meshPacket) => { + device.processPacket({ + from: meshPacket.from, + snr: meshPacket.rxSnr, + time: meshPacket.rxTime + }); + }); }; diff --git a/src/pages/Peers.tsx b/src/pages/Peers.tsx index 8808e782..b8d0449c 100644 --- a/src/pages/Peers.tsx +++ b/src/pages/Peers.tsx @@ -12,6 +12,7 @@ import { EllipsisHorizontalIcon } from "@heroicons/react/24/outline"; import { Protobuf } from "@meshtastic/meshtasticjs"; +import TimeAgo from "timeago-react"; export const PeersPage = (): JSX.Element => { const { connection, nodes } = useDevice(); @@ -98,7 +99,10 @@ export const PeersPage = (): JSX.Element => { )} - {new Date(node.data.lastHeard).toLocaleTimeString()} + {node.data.snr}db