1
0
mirror of https://github.com/4yn/slidershim.git synced 2024-11-24 14:00:10 +01:00

some error handling

This commit is contained in:
4yn 2022-02-07 15:56:03 +08:00
parent 6f052554ce
commit afa5a46c65
11 changed files with 168 additions and 129 deletions

View File

@ -3,7 +3,7 @@
- major - major
- acio support - acio support
- qol - qol
- proper error handling - more error handling
- comments - comments
- when umiguri comes out - when umiguri comes out
- ouptut websocket - ouptut websocket

View File

@ -41,10 +41,9 @@ fn main() {
{ {
let log_file_path = slider_io::Config::get_log_file_path().unwrap(); let log_file_path = slider_io::Config::get_log_file_path().unwrap();
simple_logging::log_to_file(log_file_path.as_path(), log::LevelFilter::Debug).unwrap(); simple_logging::log_to_file(log_file_path.as_path(), log::LevelFilter::Debug).unwrap();
// simple_logging::log_to_file("./log.txt", log::LevelFilter::Debug).unwrap();
} }
let config = Arc::new(Mutex::new(Some(slider_io::Config::default()))); let config = Arc::new(Mutex::new(Some(slider_io::Config::load())));
let manager = Arc::new(Mutex::new(slider_io::Manager::new())); let manager = Arc::new(Mutex::new(slider_io::Manager::new()));
{ {
let config_handle = config.lock().unwrap(); let config_handle = config.lock().unwrap();

View File

@ -46,24 +46,6 @@ static BROKENITHM_BIN_FILES: phf::Map<&'static str, (&'static [u8], &'static str
}; };
async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> { async fn serve_file(path: &str) -> Result<Response<Body>, Infallible> {
// let mut pb = current_exe().unwrap();
// pb.pop();
// pb.push("res/www");
// pb.push(path);
// pb.clean();
// println!("CWD {:?}", std::env::current_dir());
// match File::open(&pb).await {
// Ok(f) => {
// info!("Serving file {:?}", pb);
// let stream = FramedRead::new(f, BytesCodec::new());
// let body = Body::wrap_stream(stream);
// Ok(Response::new(body))
// }
// Err(_) => error_response().await,
// }
match ( match (
BROKENITHM_STR_FILES.get(path), BROKENITHM_STR_FILES.get(path),
BROKENITHM_BIN_FILES.get(path), BROKENITHM_BIN_FILES.get(path),
@ -120,36 +102,33 @@ async fn handle_brokenithm(
Some(msg) => match msg { Some(msg) => match msg {
Ok(msg) => match msg { Ok(msg) => match msg {
Message::Text(msg) => { Message::Text(msg) => {
let mut chars = msg.chars(); let chars = msg.chars().collect::<Vec<char>>();
let head = chars.next().unwrap();
match head { match chars.len() {
'a' => { 6 => {
if chars[0] == 'a' {
msg_write_handle msg_write_handle
.send(Message::Text("alive".to_string())) .send(Message::Text("alive".to_string()))
.ok(); .ok();
} }
'b' => { }
let flat_state: Vec<bool> = chars 39 => {
.map(|x| match x { if chars[0] == 'b' {
'0' => false,
'1' => true,
_ => unreachable!(),
})
.collect();
let mut controller_state_handle = state_handle.controller_state.lock().unwrap(); let mut controller_state_handle = state_handle.controller_state.lock().unwrap();
for (idx, c) in flat_state[0..32].iter().enumerate() { for (idx, c) in chars[0..32].iter().enumerate() {
controller_state_handle.ground_state[idx] = match c { controller_state_handle.ground_state[idx] = match *c == '1' {
false => 0, false => 0,
true => 255, true => 255,
} }
} }
for (idx, c) in flat_state[32..38].iter().enumerate() { for (idx, c) in chars[32..38].iter().enumerate() {
controller_state_handle.air_state[idx] = match c { controller_state_handle.air_state[idx] = match *c == '1' {
false => 0, false => 0,
true => 1, true => 1,
} }
} }
} }
}
_ => { _ => {
break; break;
} }

View File

@ -213,27 +213,10 @@ impl Config {
}) })
} }
fn factory() -> Self {
Self::from_str(
r#"{
"deviceMode": "none",
"outputMode": "none",
"ledMode": "none",
"keyboardSensitivity": 20,
"outputWebsocketUrl": "localhost:3000",
"outputPolling": "60",
"ledSensitivity": 20,
"ledWebsocketUrl": "localhost:3001",
"ledSerialPort": "COM5"
}"#,
)
.unwrap()
}
pub fn get_log_file_path() -> Option<Box<PathBuf>> { pub fn get_log_file_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap(); let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir(); let config_dir = project_dir.config_dir();
fs::create_dir_all(config_dir).unwrap(); fs::create_dir_all(config_dir).ok()?;
let log_path = config_dir.join("log.txt"); let log_path = config_dir.join("log.txt");
@ -243,7 +226,7 @@ impl Config {
pub fn get_brokenithm_qr_path() -> Option<Box<PathBuf>> { pub fn get_brokenithm_qr_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap(); let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir(); let config_dir = project_dir.config_dir();
fs::create_dir_all(config_dir).unwrap(); fs::create_dir_all(config_dir).ok()?;
let brokenithm_qr_path = config_dir.join("brokenithm.png"); let brokenithm_qr_path = config_dir.join("brokenithm.png");
@ -262,18 +245,35 @@ impl Config {
return Some(Box::new(brokenithm_qr_path)); return Some(Box::new(brokenithm_qr_path));
} }
fn get_saved_path() -> Option<Box<PathBuf>> { fn get_config_path() -> Option<Box<PathBuf>> {
let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap(); let project_dir = ProjectDirs::from("me", "impress labs", "slidershim").unwrap();
let config_dir = project_dir.config_dir(); let config_dir = project_dir.config_dir();
fs::create_dir_all(config_dir).unwrap(); fs::create_dir_all(config_dir).ok()?;
let config_path = config_dir.join("config.json"); let config_path = config_dir.join("config.json");
return Some(Box::new(config_path)); return Some(Box::new(config_path));
} }
fn default() -> Self {
Self::from_str(
r#"{
"deviceMode": "none",
"outputMode": "none",
"ledMode": "none",
"keyboardSensitivity": 20,
"outputWebsocketUrl": "localhost:3000",
"outputPolling": "60",
"ledSensitivity": 20,
"ledWebsocketUrl": "localhost:3001",
"ledSerialPort": "COM5"
}"#,
)
.unwrap()
}
fn load_saved() -> Option<Self> { fn load_saved() -> Option<Self> {
let config_path = Self::get_saved_path()?; let config_path = Self::get_config_path()?;
if !config_path.exists() { if !config_path.exists() {
return None; return None;
} }
@ -282,22 +282,22 @@ impl Config {
return Self::from_str(saved_data.as_str()); return Self::from_str(saved_data.as_str());
} }
pub fn default() -> Self { pub fn load() -> Self {
Self::load_saved() Self::load_saved()
.or_else(|| { .or_else(|| {
warn!("Config loading from file failed, using default"); warn!("Config loading from file failed, using default");
Some(Self::factory()) Some(Self::default())
}) })
.unwrap() .unwrap()
} }
pub fn save(&self) -> Option<()> { pub fn save(&self) -> Option<()> {
info!("Config saving..."); info!("Config saving...");
let config_path = Self::get_saved_path()?; let config_path = Self::get_config_path()?;
info!("Config saving to {:?}", config_path); info!("Config saving to {:?}", config_path);
fs::write(config_path.as_path(), self.raw.as_str()).unwrap(); fs::write(config_path.as_path(), self.raw.as_str()).unwrap();
info!("Config saved"); info!("Config saved");
Some(()) Some(())
} }
} }

View File

@ -185,7 +185,7 @@ impl HidDeviceJob {
} }
} }
fn setup_impl(&mut self) -> Result<(), Box<dyn Error>> { fn get_handle(&mut self) -> Result<(), Box<dyn Error>> {
info!("Device finding vid {} pid {}", self.vid, self.pid); info!("Device finding vid {} pid {}", self.vid, self.pid);
let handle = rusb::open_device_with_vid_pid(self.vid, self.pid); let handle = rusb::open_device_with_vid_pid(self.vid, self.pid);
if handle.is_none() { if handle.is_none() {
@ -212,7 +212,7 @@ const TIMEOUT: Duration = Duration::from_millis(20);
impl ThreadJob for HidDeviceJob { impl ThreadJob for HidDeviceJob {
fn setup(&mut self) -> bool { fn setup(&mut self) -> bool {
match self.setup_impl() { match self.get_handle() {
Ok(_) => { Ok(_) => {
info!("Device OK"); info!("Device OK");
true true
@ -279,8 +279,7 @@ impl ThreadJob for HidDeviceJob {
} }
fn teardown(&mut self) { fn teardown(&mut self) {
if self.handle.is_some() { if let Some(handle) = self.handle.as_mut() {
let handle = self.handle.as_mut().unwrap();
handle.release_interface(0).ok(); handle.release_interface(0).ok();
} }
} }

View File

@ -1,3 +1,5 @@
use log::error;
use std::error::Error;
use vigem_client::{Client, TargetId, XButtons, XGamepad, Xbox360Wired}; use vigem_client::{Client, TargetId, XButtons, XGamepad, Xbox360Wired};
use crate::slider_io::{config::GamepadLayout, output::OutputHandler, voltex::VoltexState}; use crate::slider_io::{config::GamepadLayout, output::OutputHandler, voltex::VoltexState};
@ -9,25 +11,49 @@ pub struct GamepadOutput {
} }
impl GamepadOutput { impl GamepadOutput {
pub fn new(layout: GamepadLayout) -> Self { pub fn new(layout: GamepadLayout) -> Option<Self> {
let client = Client::connect().unwrap(); let target = Self::get_target();
let use_air = match layout { let use_air = match layout {
GamepadLayout::Neardayo => true, GamepadLayout::Neardayo => true,
_ => false, _ => false,
}; };
let mut target = Xbox360Wired::new(client, TargetId::XBOX360_WIRED);
target.plugin().unwrap(); match target {
target.wait_ready().unwrap(); Ok(target) => Some(Self {
Self {
target, target,
use_air, use_air,
gamepad: XGamepad::default(), gamepad: XGamepad::default(),
}),
Err(e) => {
error!("Gamepad connection error: {}", e);
error!("Gamepad connection error: Is ViGEMBus missing?");
None
}
}
}
fn get_target() -> Result<Xbox360Wired<Client>, Box<dyn Error>> {
let client = Client::connect()?;
let mut target = Xbox360Wired::new(client, TargetId::XBOX360_WIRED);
target.plugin()?;
target.wait_ready()?;
Ok(target)
}
fn update(&mut self) -> bool {
match self.target.update(&self.gamepad) {
Ok(_) => true,
Err(e) => {
error!("Gamepad update error: {}", e);
false
}
} }
} }
} }
impl OutputHandler for GamepadOutput { impl OutputHandler for GamepadOutput {
fn tick(&mut self, flat_controller_state: &Vec<bool>) { fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool {
let voltex_state = VoltexState::from_flat(flat_controller_state); let voltex_state = VoltexState::from_flat(flat_controller_state);
let buttons = voltex_state let buttons = voltex_state
@ -84,20 +110,26 @@ impl OutputHandler for GamepadOutput {
dirty = true; dirty = true;
} }
if dirty { match dirty {
self.target.update(&self.gamepad).unwrap(); true => self.update(),
false => true,
} }
} }
fn reset(&mut self) { fn reset(&mut self) {
self.gamepad = XGamepad::default(); self.gamepad = XGamepad::default();
self.target.update(&self.gamepad).unwrap(); self.update();
} }
} }
impl Drop for GamepadOutput { impl Drop for GamepadOutput {
fn drop(&mut self) { fn drop(&mut self) {
self.target.unplug().unwrap(); match self.target.unplug() {
Ok(_) => {}
Err(e) => {
error!("Gamepad unplug error: {}", e);
}
}
} }
} }

View File

@ -165,7 +165,7 @@ impl KeyboardOutput {
} }
impl OutputHandler for KeyboardOutput { impl OutputHandler for KeyboardOutput {
fn tick(&mut self, flat_controller_state: &Vec<bool>) { fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool {
self.next_keys.fill(false); self.next_keys.fill(false);
for (idx, x) in flat_controller_state.iter().enumerate() { for (idx, x) in flat_controller_state.iter().enumerate() {
if *x { if *x {
@ -173,6 +173,7 @@ impl OutputHandler for KeyboardOutput {
} }
} }
self.send(); self.send();
true
} }
fn reset(&mut self) { fn reset(&mut self) {

View File

@ -98,7 +98,11 @@ impl Manager {
impl Drop for Manager { impl Drop for Manager {
fn drop(&mut self) { fn drop(&mut self) {
self.tx_stop.take().unwrap().send(()).unwrap(); if let Some(tx_stop) = self.tx_stop.take() {
self.join_handle.take().unwrap().join().unwrap(); tx_stop.send(()).ok();
}
if let Some(join_handle) = self.join_handle.take() {
join_handle.join().ok();
}
} }
} }

View File

@ -1,3 +1,4 @@
use log::error;
use std::time::Duration; use std::time::Duration;
use crate::slider_io::{ use crate::slider_io::{
@ -6,49 +7,66 @@ use crate::slider_io::{
}; };
pub trait OutputHandler: Send { pub trait OutputHandler: Send {
fn tick(&mut self, flat_controller_state: &Vec<bool>); fn tick(&mut self, flat_controller_state: &Vec<bool>) -> bool;
fn reset(&mut self); fn reset(&mut self);
} }
pub struct OutputJob { pub struct OutputJob {
state: FullState, state: FullState,
mode: OutputMode,
t: u64, t: u64,
sensitivity: u8, sensitivity: u8,
handler: Box<dyn OutputHandler>, handler: Option<Box<dyn OutputHandler>>,
} }
impl OutputJob { impl OutputJob {
pub fn new(state: &FullState, mode: &OutputMode) -> Self { pub fn new(state: &FullState, mode: &OutputMode) -> Self {
match mode { Self {
OutputMode::Keyboard {
layout,
polling,
sensitivity,
} => Self {
state: state.clone(), state: state.clone(),
t: polling.to_t_u64(), mode: mode.clone(),
sensitivity: *sensitivity, t: 0,
handler: Box::new(KeyboardOutput::new(layout.clone())), sensitivity: 0,
}, handler: None,
OutputMode::Gamepad {
layout,
polling,
sensitivity,
} => Self {
state: state.clone(),
t: polling.to_t_u64(),
sensitivity: *sensitivity,
handler: Box::new(GamepadOutput::new(layout.clone())),
},
_ => panic!("Not implemented"),
} }
} }
} }
impl ThreadJob for OutputJob { impl ThreadJob for OutputJob {
fn setup(&mut self) -> bool { fn setup(&mut self) -> bool {
match self.mode {
OutputMode::Keyboard {
layout,
polling,
sensitivity,
} => {
self.t = polling.to_t_u64();
self.sensitivity = sensitivity;
self.handler = Some(Box::new(KeyboardOutput::new(layout.clone())));
true true
} }
OutputMode::Gamepad {
layout,
polling,
sensitivity,
} => {
self.t = polling.to_t_u64();
self.sensitivity = sensitivity;
let handler = GamepadOutput::new(layout.clone());
match handler {
Some(handler) => {
self.handler = Some(Box::new(handler));
true
}
None => false,
}
}
_ => {
error!("Not implemented");
false
}
}
}
fn tick(&mut self) -> bool { fn tick(&mut self) -> bool {
let flat_controller_state: Vec<bool>; let flat_controller_state: Vec<bool>;
@ -57,14 +75,17 @@ impl ThreadJob for OutputJob {
flat_controller_state = controller_state_handle.flat(&self.sensitivity); flat_controller_state = controller_state_handle.flat(&self.sensitivity);
} }
self.handler.tick(&flat_controller_state); if let Some(handler) = self.handler.as_mut() {
// thread::sleep(Duration::from_millis(self.t)); handler.tick(&flat_controller_state);
}
spin_sleep::sleep(Duration::from_micros(self.t)); spin_sleep::sleep(Duration::from_micros(self.t));
true true
} }
fn teardown(&mut self) { fn teardown(&mut self) {
self.handler.reset(); if let Some(handler) = self.handler.as_mut() {
handler.reset();
}
} }
} }

View File

@ -84,9 +84,11 @@ impl LoopTimer {
} }
} }
// pub fn reset(&mut self) { #[allow(dead_code)]
// self.buf = vec![Instant::now(); 100]; pub fn reset(&mut self) {
// } self.buf = vec![Instant::now() - Duration::from_secs(10); 100];
self.cur = 0;
}
pub fn fork(&self) -> Arc<AtomicF64> { pub fn fork(&self) -> Arc<AtomicF64> {
Arc::clone(&self.freq) Arc::clone(&self.freq)

View File

@ -59,9 +59,9 @@ impl Drop for ThreadWorker {
info!("Thread worker stopping {}", self.name); info!("Thread worker stopping {}", self.name);
self.stop_signal.store(true, Ordering::SeqCst); self.stop_signal.store(true, Ordering::SeqCst);
if self.thread.is_some() { if let Some(thread) = self.thread.take() {
self.thread.take().unwrap().join().ok(); thread.join().ok();
} };
} }
} }
@ -88,7 +88,7 @@ impl AsyncWorker {
let task = tokio::spawn(async move { let task = tokio::spawn(async move {
job job
.run(async move { .run(async move {
recv_stop.await.unwrap(); recv_stop.await.ok();
}) })
.await; .await;
}); });
@ -105,7 +105,9 @@ impl Drop for AsyncWorker {
fn drop(&mut self) { fn drop(&mut self) {
info!("Async worker stopping {}", self.name); info!("Async worker stopping {}", self.name);
self.stop_signal.take().unwrap().send(()).unwrap(); if let Some(stop_signal) = self.stop_signal.take() {
stop_signal.send(()).ok();
}
self.task.take(); self.task.take();
} }
} }