From 4fc84c7dbaba900461b6859de9b5fd0ff152869c Mon Sep 17 00:00:00 2001 From: Youwen Wu Date: Tue, 27 Feb 2024 22:54:06 -0800 Subject: [PATCH] feat: begin work on rust backend with networktables --- client/package-lock.json | 15 ++++++ client/package.json | 1 + client/src-tauri/Cargo.lock | 53 +++++++++++++++++++++ client/src-tauri/Cargo.toml | 1 + client/src-tauri/src/main.rs | 24 ++++++++-- client/src-tauri/src/telemetry.rs | 30 ++++++++++++ client/src/App.svelte | 1 + client/src/lib/utils/initializeTelemetry.ts | 51 +++++++++++++------- 8 files changed, 156 insertions(+), 20 deletions(-) create mode 100644 client/src-tauri/src/telemetry.rs diff --git a/client/package-lock.json b/client/package-lock.json index 218f778..4dd040a 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.0", "dependencies": { "@fontsource/roboto": "^5.0.8", + "@tauri-apps/api": "^1.5.3", "@threlte/core": "^7.1.0", "@threlte/extras": "^8.8.0", "camera-controls": "^2.8.3", @@ -812,6 +813,20 @@ "vite": "^5.0.0" } }, + "node_modules/@tauri-apps/api": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-1.5.3.tgz", + "integrity": "sha512-zxnDjHHKjOsrIzZm6nO5Xapb/BxqUq1tc7cGkFXsFkGTsSWgCPH1D8mm0XS9weJY2OaR73I3k3S+b7eSzJDfqA==", + "engines": { + "node": ">= 14.6.0", + "npm": ">= 6.6.0", + "yarn": ">= 1.19.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, "node_modules/@tauri-apps/cli": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-1.5.10.tgz", diff --git a/client/package.json b/client/package.json index 6c81629..35f83e5 100644 --- a/client/package.json +++ b/client/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "@fontsource/roboto": "^5.0.8", + "@tauri-apps/api": "^1.5.3", "@threlte/core": "^7.1.0", "@threlte/extras": "^8.8.0", "camera-controls": "^2.8.3", diff --git a/client/src-tauri/Cargo.lock b/client/src-tauri/Cargo.lock index a771765..b7c546d 100644 --- a/client/src-tauri/Cargo.lock +++ b/client/src-tauri/Cargo.lock @@ -66,6 +66,7 @@ checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" name = "app" version = "0.1.0" dependencies = [ + "network-tables", "serde", "serde_json", "tauri", @@ -1528,6 +1529,17 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + [[package]] name = "ndk" version = "0.6.0" @@ -1556,6 +1568,20 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "network-tables" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d34242b4ee3505f5d9f6eeb8cc409cfa1f18a517825c78e6001fe304c3977b" +dependencies = [ + "futures-util", + "parking_lot", + "rand 0.8.5", + "thiserror", + "tokio", + "tracing", +] + [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -2399,6 +2425,16 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "socket2" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "soup2" version = "0.2.1" @@ -2895,8 +2931,25 @@ checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", + "libc", + "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", ] [[package]] diff --git a/client/src-tauri/Cargo.toml b/client/src-tauri/Cargo.toml index fe4aa80..635363c 100644 --- a/client/src-tauri/Cargo.toml +++ b/client/src-tauri/Cargo.toml @@ -18,6 +18,7 @@ tauri-build = { version = "1.5.1", features = [] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } tauri = { version = "1.6.0", features = [] } +network-tables = "0.1.3" [features] # this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled. diff --git a/client/src-tauri/src/main.rs b/client/src-tauri/src/main.rs index f5c5be2..1c6f7de 100644 --- a/client/src-tauri/src/main.rs +++ b/client/src-tauri/src/main.rs @@ -1,8 +1,24 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -fn main() { - tauri::Builder::default() - .run(tauri::generate_context!()) - .expect("error while running tauri application"); +use tauri::Manager; + +mod telemetry; + +#[derive(Clone, serde::Serialize)] +struct Payload { + message: String, +} + +fn main() { + tauri::Builder::default() + .setup(|app| { + // create app handle and send it to our event listeners + let app_handle = app.app_handle(); + telemetry::subscribe_topics(&app_handle); + + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("failed to run app") } diff --git a/client/src-tauri/src/telemetry.rs b/client/src-tauri/src/telemetry.rs new file mode 100644 index 0000000..c19dbad --- /dev/null +++ b/client/src-tauri/src/telemetry.rs @@ -0,0 +1,30 @@ +use tauri::{AppHandle, Manager}; + +pub fn subscribe_topics(app: &AppHandle) { + let app_handle = app.clone(); + + app_handle.listen_global("subscribe", |event| { + let parsed: Result = + serde_json::from_str(event.payload().unwrap()); + match parsed { + Ok(value) => { + // handle the successfully parsed value + let topics = value.as_object(); + match topics { + Some(topics) => { + for (key, value) in topics { + println!("{}: {}", key, value); + } + } + None => { + println!("No topics requested!"); + } + } + } + Err(err) => { + // handle the error + println!("{:?}", err); + } + } + }); +} diff --git a/client/src/App.svelte b/client/src/App.svelte index e534fa0..ed0de7e 100644 --- a/client/src/App.svelte +++ b/client/src/App.svelte @@ -13,6 +13,7 @@ import { settingsStore } from './lib/stores/settingsStore' import getSettings from './lib/utils/getSettings' import { Canvas } from '@threlte/core' + import { emit } from '@tauri-apps/api/event' let activeApp: App = 'camera' let topics: TelemetryTopics = { diff --git a/client/src/lib/utils/initializeTelemetry.ts b/client/src/lib/utils/initializeTelemetry.ts index 1782ade..97f9f4a 100644 --- a/client/src/lib/utils/initializeTelemetry.ts +++ b/client/src/lib/utils/initializeTelemetry.ts @@ -1,5 +1,5 @@ -import { io } from 'socket.io-client' import { telemetryStore } from '../stores/telemetryStore' +import { emit, listen } from '@tauri-apps/api/event' /** * Connects to sockets and subscribes to specified topics to receive telemetry data. @@ -14,7 +14,7 @@ const onUpdate = (data: TelemetryData) => { // console.log(data) } -export const initializeTelemetry = ( +export const initializeTelemetry = async ( topics: TelemetryTopics, refreshRate: number ) => { @@ -25,20 +25,39 @@ export const initializeTelemetry = ( ) } - const socket = io('localhost:1280') - socket.on('connect', () => { - console.log('Socket-IO connected!') - socket.emit('subscribe', topics) - console.log(`Subscribing to topics: ${JSON.stringify(topics)}`) + const unlisten = await listen('hello_from_rust', event => { + console.log(event.event) + console.log(event.payload) }) - socket.on('subscribed', () => { - console.log('Successfully subscribed to requested topics!') - socket.emit('request_data', { refresh_rate: refreshRate }) - console.log(`Refreshing at ${refreshRate} Hz`) - }) - - socket.on('telemetry_data', (data: string) => { - onUpdate(JSON.parse(data)) - }) + emit('subscribe', topics) } + +// export const initializeTelemetry = ( +// topics: TelemetryTopics, +// refreshRate: number +// ) => { +// // Make sure refreshRate is valid +// if (!Number.isInteger(refreshRate) || refreshRate < 1) { +// throw new Error( +// 'refreshRate must be an integer greater than or equal to 1.' +// ) +// } + +// const socket = io('localhost:1280') +// socket.on('connect', () => { +// console.log('Socket-IO connected!') +// socket.emit('subscribe', topics) +// console.log(`Subscribing to topics: ${JSON.stringify(topics)}`) +// }) + +// socket.on('subscribed', () => { +// console.log('Successfully subscribed to requested topics!') +// socket.emit('request_data', { refresh_rate: refreshRate }) +// console.log(`Refreshing at ${refreshRate} Hz`) +// }) + +// socket.on('telemetry_data', (data: string) => { +// onUpdate(JSON.parse(data)) +// }) +// }