From 9966f889939fb3786c7d5b5a89b54481ec7f562e Mon Sep 17 00:00:00 2001 From: Jade Turner Date: Mon, 2 Sep 2024 17:12:55 +0800 Subject: [PATCH] Better error handling in backend and migrate to async --- src-tauri/Cargo.lock | 6 +- src-tauri/Cargo.toml | 2 + src-tauri/src/main.rs | 142 +++++++++++++++++++++++++----------------- 3 files changed, 91 insertions(+), 59 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index dc6c14b..aaa4051 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -611,9 +611,11 @@ version = "0.1.0" dependencies = [ "ds", "gilrs", + "once_cell", "serde", "tauri", "tauri-build", + "tokio", ] [[package]] @@ -3162,9 +3164,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ba52b89..8c6b8fb 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -15,6 +15,8 @@ tauri = { version = "1", features = ["shell-open"] } serde = { version = "1", features = ["derive"] } ds = { git = "https://github.com/spacey-sooty/ds-rs.git", branch = "updatedeps" } gilrs = { version = "0.10.9", features = ["serde", "serde-serialize"] } +tokio = "1.40.0" +once_cell = "1.19.0" [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 6992024..0ada4e7 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,14 +1,11 @@ // Prevents additional console window on Windows in release, DO NOT REMOVE!! #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] -use std::{ - fmt, - fs::File, - io::Write, - sync::{Mutex, MutexGuard}, - thread, - time::Duration, -}; +use std::{fmt, fs::File, io::Write, thread, time::Duration}; + +use once_cell::sync::Lazy; +use tauri::async_runtime::Mutex; +use tokio::sync::MutexGuard; use ds::{DriverStation, JoystickValue, Mode}; use gilrs::{Axis, Button, Gilrs}; @@ -16,6 +13,7 @@ use serde::{ de::{self, Visitor}, Deserialize, Serialize, }; + use tauri::{api::path::app_config_dir, Manager, State}; #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] @@ -101,7 +99,10 @@ fn send_packet_no_last( let change_team_num = connection.team_num != packet.team_num; let change_position = connection.position != packet.position; let change_colour = connection.colour != packet.colour; - let ds = &mut connection.ds.as_mut().unwrap(); + let ds = &mut match connection.ds.as_mut() { + Some(ds) => ds, + None => return, + }; if change_team_num { ds.set_team_number(packet.team_num); @@ -131,34 +132,53 @@ fn send_packet_no_last( } #[tauri::command] -fn send_packet(last_packet: State>, packet: Packet) { - *last_packet.lock().unwrap() = packet; +async fn send_packet( + last_packet: State<'_, Lazy>>, + packet: Packet, +) -> Result<(), ()> { + *last_packet.lock().await = packet; + + Ok(()) } #[tauri::command] -fn restart_code(state: State>) { - state.lock().unwrap().ds.as_mut().unwrap().restart_code(); +async fn restart_code(state: State<'_, Lazy>>) -> Result<(), ()> { + match state.lock().await.ds.as_mut() { + Some(ds) => ds.restart_code(), + None => { + println!("Can't restart code, DriverStationState doesn't exist yet."); + return Ok(()); + } + } + + Ok(()) } #[tauri::command] -fn estop(last_packet: State>) { - let mut packet = last_packet.lock().unwrap().clone(); +async fn estop(last_packet: State<'_, Lazy>>) -> Result<(), ()> { + let mut packet = last_packet.lock().await.clone(); packet.state = RobotState::Enabled; - send_packet(last_packet, packet); + send_packet(last_packet, packet).await.unwrap(); + + Ok(()) } #[tauri::command] -fn disable(last_packet: State>) { - let mut packet = last_packet.lock().unwrap().clone(); +async fn disable(last_packet: State<'_, Lazy>>) -> Result<(), ()> { + let mut packet = last_packet.lock().await.clone(); packet.state = RobotState::Disabled; - send_packet(last_packet, packet); + send_packet(last_packet, packet).await.unwrap(); + + Ok(()) } #[tauri::command] -fn enable(last_packet: State>) { - let mut packet = last_packet.lock().unwrap().clone(); +async fn enable(last_packet: State<'_, Lazy>>) -> Result<(), ()> { + let mut packet = last_packet.lock().await.clone(); packet.state = RobotState::Enabled; - send_packet(last_packet, packet); + send_packet(last_packet, packet).await.unwrap(); + + Ok(()) } // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command @@ -167,19 +187,23 @@ fn greet(name: &str) -> String { format!("Hello, {}! You've been greeted from Rust!", name) } -static LAST_PACKET: Mutex = Mutex::new(Packet { - colour: AllianceColour::Red, - mode: RobotMode(Mode::Teleoperated), - position: 1, - state: RobotState::Disabled, - team_num: 4788, +static LAST_PACKET: Lazy> = Lazy::new(|| { + Mutex::new(Packet { + colour: AllianceColour::Red, + mode: RobotMode(Mode::Teleoperated), + position: 1, + state: RobotState::Disabled, + team_num: 4788, + }) }); -static DRIVERSTATION_STATE: Mutex = Mutex::new(DriverStationState { - ds: None, - colour: AllianceColour::Red, - position: 1, - team_num: 4788, +static DRIVERSTATION_STATE: Lazy> = Lazy::new(|| { + Mutex::new(DriverStationState { + ds: None, + colour: AllianceColour::Red, + position: 1, + team_num: 4788, + }) }); const AXIS: [Axis; 4] = [ @@ -216,38 +240,48 @@ fn main() { tauri::Builder::default() .setup(|app| { - let config_dir = app_config_dir(&app.config()).unwrap(); + let config_dir = + app_config_dir(&app.config()).expect("Should be able to get config dir."); let _ = std::fs::create_dir_all(&config_dir); - let location = config_dir.to_str().unwrap().to_string() + "/team_num"; + let location = config_dir + .to_str() + .expect("Config directory should be valid string.") + .to_string() + + "/team_num"; let team_num_string = std::fs::read_to_string(&location); let team_num: u32 = match team_num_string { - Ok(string) => string.parse().unwrap(), + Ok(string) => string + .parse() + .expect("Saved team number should be a number."), Err(_) => { - File::create_new(&location).unwrap().write(b"4788").unwrap(); + File::create_new(&location) + .expect("Team number file doesn't exist, so should be creatable.") + .write_all(b"4788") + .expect("Should be able to write to team number file."); 4788 } }; - { - LAST_PACKET.lock().unwrap().team_num = team_num; - let mut ds = DRIVERSTATION_STATE.lock().unwrap(); + tauri::async_runtime::spawn(async move { + LAST_PACKET.lock().await.team_num = team_num; + let mut ds = DRIVERSTATION_STATE.lock().await; ds.ds = Some(DriverStation::new_team(team_num, ds::Alliance::new_red(1))); ds.team_num = team_num; - let driverstation = ds.ds.as_mut().unwrap(); + let driverstation = ds.ds.as_mut().expect("Driverstation should exist."); driverstation.set_use_usb(false); driverstation.set_joystick_supplier(|| { - let gilrs = Gilrs::new().unwrap(); + let gilrs = Gilrs::new().expect("Should be able to load Gilrs."); let mut out: Vec> = vec![]; for (_id, gamepad) in gilrs.gamepads() { let mut values: Vec = vec![]; - for i in BUTTONS.clone() { + for i in BUTTONS { values.push(JoystickValue::Button { id: i as u8, pressed: gamepad.is_pressed(i), }) } - for i in AXIS.clone() { + for i in AXIS { values.push(JoystickValue::Axis { id: i as u8, value: gamepad.value(i), @@ -256,25 +290,19 @@ fn main() { out.push(values); } - return out; + out }); - } + }); app.manage(&DRIVERSTATION_STATE); app.manage(&LAST_PACKET); - thread::Builder::new() - .name("background sender".to_string()) - .spawn(move || loop { - { - send_packet_no_last( - LAST_PACKET.lock().unwrap(), - DRIVERSTATION_STATE.lock().unwrap(), - ); - } + tauri::async_runtime::spawn(async move { + loop { + send_packet_no_last(LAST_PACKET.lock().await, DRIVERSTATION_STATE.lock().await); thread::sleep(Duration::from_millis(15)); - }) - .unwrap(); + } + }); Ok(()) })