diff --git a/Cargo.toml b/Cargo.toml index 10f4adb..ef42000 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,8 @@ members = [ "core/libs/carbon-fiber" ] -[profile.dev] -opt-level = 1 - -[profile.dev.package."*"] -opt-level = 3 +# [profile.dev] +# opt-level = 1 +# +# [profile.dev.package."*"] +# opt-level = 3 diff --git a/clover-hub/src/server/appd/ipc.rs b/clover-hub/src/server/appd/ipc.rs index be94496..d6c11a0 100644 --- a/clover-hub/src/server/appd/ipc.rs +++ b/clover-hub/src/server/appd/ipc.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use log::{ debug, info, @@ -7,18 +8,26 @@ use serde::{ Deserialize, Serialize, }; +use std::str::FromStr; use strum::VariantNames; use tokio::sync::broadcast::Sender; use url::Url; -#[derive(Deserialize, Serialize, VariantNames)] +#[derive(Debug, PartialEq)] pub enum Events { - #[serde(rename = "/status")] - #[strum(serialize = "/status")] - Status, - #[serde(rename = "/gesture/begin")] - #[strum(serialize = "/gesture/begin")] - GestureBegin, + None, +} + +impl FromStr for Events { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + match input { + "" => Ok(Events::None), + "/" => Ok(Events::None), + _ => Err(anyhow!("String \"{}\" not part of enum!", input)), + } + } } pub async fn handle_ipc_msg(ipc_rx: Sender) { @@ -29,34 +38,18 @@ pub async fn handle_ipc_msg(ipc_rx: Sender) { if kind.host().unwrap() == url::Host::Domain("com.reboot-codes.clover.appd") { debug!("Processing: {}", msg.kind.clone()); - match serde_json_lenient::from_str::(&format!("\"{}\"", kind.path())) { + match Events::from_str(kind.path()) { Ok(event_type) => { match event_type { - Events::Status => { - debug!("Return status?"); - } - Events::GestureBegin => { - let mut gesture_id = None; - for (key, val) in kind.query_pairs() { - if key == "gesture_id" { - gesture_id = Some(val.to_string()); - } - } - - match gesture_id { - Some(gesture_id_str) => { - info!("Begining gesture \"{}\"...", gesture_id_str.clone()); - } - Option::None => { - // TODO - } - } + _ => { + // TODO + debug!("TODO"); } } } Err(_e) => { // TODO: return error reply! - todo!(); + debug!("TODO"); } } } diff --git a/clover-hub/src/server/inference_engine/ipc.rs b/clover-hub/src/server/inference_engine/ipc.rs index 662ab0f..ae2800f 100644 --- a/clover-hub/src/server/inference_engine/ipc.rs +++ b/clover-hub/src/server/inference_engine/ipc.rs @@ -1,3 +1,4 @@ +use anyhow::anyhow; use log::{ debug, info, @@ -7,18 +8,26 @@ use serde::{ Deserialize, Serialize, }; +use std::str::FromStr; use strum::VariantNames; use tokio::sync::broadcast::Sender; use url::Url; -#[derive(Deserialize, Serialize, VariantNames)] +#[derive(Debug, PartialEq)] pub enum Events { - #[serde(rename = "/status")] - #[strum(serialize = "/status")] - Status, - #[serde(rename = "/gesture/begin")] - #[strum(serialize = "/gesture/begin")] - GestureBegin, + None, +} + +impl FromStr for Events { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + match input { + "" => Ok(Events::None), + "/" => Ok(Events::None), + _ => Err(anyhow!("String \"{}\" not part of enum!", input)), + } + } } pub async fn handle_ipc_msg(ipc_rx: Sender) { @@ -29,34 +38,18 @@ pub async fn handle_ipc_msg(ipc_rx: Sender) { if kind.host().unwrap() == url::Host::Domain("com.reboot-codes.clover.inference-engine") { debug!("Processing: {}", msg.kind.clone()); - match serde_json_lenient::from_str::(&format!("\"{}\"", kind.path())) { + match Events::from_str(kind.path()) { Ok(event_type) => { match event_type { - Events::Status => { - debug!("Return status?"); - } - Events::GestureBegin => { - let mut gesture_id = None; - for (key, val) in kind.query_pairs() { - if key == "gesture_id" { - gesture_id = Some(val.to_string()); - } - } - - match gesture_id { - Some(gesture_id_str) => { - info!("Begining gesture \"{}\"...", gesture_id_str.clone()); - } - Option::None => { - // TODO - } - } + _ => { + // TODO + debug!("TODO"); } } } Err(_e) => { // TODO - todo!(); + debug!("TODO"); } } } diff --git a/clover-hub/src/server/modman/ipc/gestures.rs b/clover-hub/src/server/modman/ipc/gestures.rs index ceb7cc1..e04225b 100644 --- a/clover-hub/src/server/modman/ipc/gestures.rs +++ b/clover-hub/src/server/modman/ipc/gestures.rs @@ -63,14 +63,177 @@ Default area specification - pinky */ -use log::info; +use std::sync::Arc; -use crate::server::modman::models::GestureCommand; +use log::{ + debug, + error, + info, + warn, +}; -pub fn handle_gesture_cmd(gesture_id: String, command: GestureCommand) { +use crate::server::modman::models::{ + GestureCommand, + GestureState, + GestureStates, + ModManStore, +}; + +pub async fn should_be_bg(store: Arc, bg_from_state: Option) -> bool { + match bg_from_state { + Some(should_be_bg_period) => should_be_bg_period, + None => store.config.lock().await.modman.gestures_bg_by_default, + } +} + +pub async fn handle_gesture_cmd( + store: &mut Arc, + gesture_id: String, + command: GestureCommand, +) { info!( - "Handling gesture \"{}\" and state: {:#?}", + "Handling gesture \"{}\" and state command: {:#?}", gesture_id.clone(), command.clone() ); + + let mut gesture_state_map = store.gesture_states.lock().await; + let mut modded_gesture_state = None; + + let stored_states = match gesture_state_map.get(&gesture_id.clone()) { + Some(stored_states_from_map) => { + if stored_states_from_map.current_state == command.state { + warn!("Sent gesture state command which matches current state, this is a no-op!"); + // TODO: Send reply! + return; + } else { + stored_states_from_map + } + } + None => { + match command.state { + GestureState::Begin { + intensity: _, + speed: _, + background: _, + } => &GestureStates { + prev_state: None, + current_state: GestureState::End, + next_state: None, + paused: false, + }, + _ => { + error!("Command: {:#?}, is not applicable since this gesture was not cached in the first place!", command.state); + // TODO: Send reply! + return; + } + } + } + }; + + match command.state { + GestureState::Begin { + intensity: _, + speed: _, + background, + } => { + // When begining a gesture (or setting new parameters), move it to the top of either back/foreground application list. + let mut priority_vec; + + if should_be_bg(store.clone(), background).await { + priority_vec = store.background_gesture_priority.lock().await; + } else { + priority_vec = store.foreground_gesture_priority.lock().await; + } + + match { + let mut ret = None; + let mut index: usize = 0; + + for item in priority_vec.iter() { + if item == &gesture_id.clone() { + ret = Some((index, item.clone())); + break; + } + index += 1; + } + + ret + } { + Some((index, _item)) => { + priority_vec.remove(index); + } + None => {} + } + + priority_vec.push(gesture_id.clone()); + + modded_gesture_state = Some(GestureStates { + prev_state: stored_states.prev_state.clone(), + current_state: command.state, + next_state: stored_states.next_state.clone(), + paused: false, + }); + } + GestureState::Pause => { + modded_gesture_state = Some(GestureStates { + prev_state: stored_states.prev_state.clone(), + current_state: stored_states.current_state.clone(), + next_state: stored_states.next_state.clone(), + paused: true, + }); + } + GestureState::End => { + // Remove the gesture from either gesture priority vec. + let priority_vecs = vec![ + store.background_gesture_priority.lock().await, + store.foreground_gesture_priority.lock().await, + ]; + + for mut priority_vec in priority_vecs { + match { + let mut ret = None; + let mut index: usize = 0; + + for item in priority_vec.iter() { + if item == &gesture_id.clone() { + ret = Some((index, item.clone())); + break; + } + index += 1; + } + + ret + } { + Some((index, _item)) => { + priority_vec.remove(index); + } + // Wasn't in the vecs at all, so it's a no-op. + None => {} + } + } + } + GestureState::UnPause => { + modded_gesture_state = Some(GestureStates { + prev_state: stored_states.prev_state.clone(), + current_state: stored_states.current_state.clone(), + next_state: stored_states.next_state.clone(), + paused: false, + }); + } + } + + // Since we already checked that the state command is different, either apply the changes or remove the gesture from the state map + match modded_gesture_state { + Some(state_to_insert) => { + gesture_state_map.insert(gesture_id.clone(), state_to_insert); + } + None => { + gesture_state_map.remove(&gesture_id.clone()); + } + } + + debug!("Gesture ID: {}, state set!", gesture_id.clone()); + + // TODO: Send reply! } diff --git a/clover-hub/src/server/modman/ipc/mod.rs b/clover-hub/src/server/modman/ipc/mod.rs index 80c095b..5a2aac3 100644 --- a/clover-hub/src/server/modman/ipc/mod.rs +++ b/clover-hub/src/server/modman/ipc/mod.rs @@ -1,5 +1,6 @@ mod gestures; +use anyhow::anyhow; use gestures::handle_gesture_cmd; use log::{ debug, @@ -16,29 +17,49 @@ use tokio::sync::broadcast::Sender; use url::Url; use crate::{ - server::modman::models::GestureCommand, + server::modman::models::{ + GestureCommand, + ModManStore, + }, utils::deserialize_base64, }; +use std::{ + str::FromStr, + sync::Arc, +}; -#[derive(Deserialize, Serialize, VariantNames)] +#[derive(Debug, PartialEq)] pub enum Events { - #[serde(rename = "/status")] - #[strum(serialize = "/status")] Status, - #[serde(rename = "/gesture")] - #[strum(serialize = "/gesture")] Gesture, + None, +} + +impl FromStr for Events { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + match input { + "/gesture" => Ok(Events::Gesture), + "/status" => Ok(Events::Status), + "" => Ok(Events::None), + "/" => Ok(Events::None), + _ => Err(anyhow!("String \"{}\" not part of enum!", input)), + } + } } -pub async fn handle_ipc_msg(ipc_rx: Sender) { +pub async fn handle_ipc_msg(store: ModManStore, ipc_rx: Sender) { + let store_arc = Arc::new(store.clone()); + while let Ok(msg) = ipc_rx.subscribe().recv().await { let kind = Url::parse(&msg.kind.clone()).unwrap(); // Verify that we care about this event. if kind.host().unwrap() == url::Host::Domain("com.reboot-codes.clover.modman") { - debug!("Processing: {}", msg.kind.clone()); + debug!("Processing: \"{}\"...", kind.path()); - match serde_json_lenient::from_str::(&format!("\"{}\"", kind.path())) { + match Events::from_str(kind.path()) { Ok(event_type) => { match event_type { Events::Status => { @@ -68,7 +89,14 @@ pub async fn handle_ipc_msg(ipc_rx: Sender) { } match gesture_command { - Some(cmd) => handle_gesture_cmd(gesture_id_str.clone(), cmd.clone()), + Some(cmd) => { + handle_gesture_cmd( + &mut store_arc.clone(), + gesture_id_str.clone(), + cmd.clone(), + ) + .await + } None => { error!("Parsed gesture ID and data, but it was not set??"); } @@ -80,9 +108,14 @@ pub async fn handle_ipc_msg(ipc_rx: Sender) { } } } + _ => { + debug!("Blank event... doing nothing."); + } } } - Err(e) => {} + Err(e) => { + debug!("Failed to parse path: {}, due to: {}", kind.path(), e); + } } } } diff --git a/clover-hub/src/server/modman/mod.rs b/clover-hub/src/server/modman/mod.rs index 403f3aa..f75a5c8 100644 --- a/clover-hub/src/server/modman/mod.rs +++ b/clover-hub/src/server/modman/mod.rs @@ -110,12 +110,13 @@ pub async fn modman_main( let ipc_recv_token = cancellation_tokens.0.clone(); let (ipc_rx, ipc_handle) = user.subscribe(); + let ipc_recv_store = store.clone(); let ipc_recv_handle = tokio::task::spawn(async move { tokio::select! { _ = ipc_recv_token.cancelled() => { debug!("ipc_recv exited"); }, - _ = handle_ipc_msg(ipc_rx) => {} + _ = handle_ipc_msg(ipc_recv_store, ipc_rx) => {} } }); diff --git a/clover-hub/src/server/modman/models.rs b/clover-hub/src/server/modman/models.rs index 12a4d75..9c414f5 100644 --- a/clover-hub/src/server/modman/models.rs +++ b/clover-hub/src/server/modman/models.rs @@ -136,6 +136,9 @@ pub struct ModManStore { pub modules: Arc>>, pub components: Arc>>>, pub config: Arc>, + pub gesture_states: Arc>>, + pub foreground_gesture_priority: Arc>>, + pub background_gesture_priority: Arc>>, /// Used for [Bus](super::busses::models::Bus) statuses, etc pub port_statuses: PortStatuses, } @@ -150,6 +153,9 @@ impl ModManStore { ModManStore { modules: Arc::new(Mutex::new(HashMap::new())), components: Arc::new(Mutex::new(HashMap::new())), + gesture_states: Arc::new(Mutex::new(HashMap::new())), + foreground_gesture_priority: Arc::new(Mutex::new(Vec::new())), + background_gesture_priority: Arc::new(Mutex::new(Vec::new())), port_statuses: PortStatuses { uart: Arc::new(Mutex::new(HashMap::new())), }, @@ -181,14 +187,19 @@ pub enum PortStatus { Unavailable(String), } -#[derive(Serialize, Deserialize, Clone, Debug, VariantNames)] +#[derive(Serialize, Deserialize, Clone, Debug, VariantNames, PartialEq)] +#[serde(tag = "command")] pub enum GestureState { #[serde(rename = "begin")] #[strum(serialize = "begin")] - Begin, - #[serde(rename = "continue")] - #[strum(serialize = "continue")] - Continue, + Begin { + intensity: f64, + speed: f64, + background: Option, + }, + #[serde(rename = "unpause")] + #[strum(serialize = "unpause")] + UnPause, #[serde(rename = "pause")] #[strum(serialize = "end")] Pause, @@ -197,12 +208,12 @@ pub enum GestureState { End, } -#[derive(Serialize, Deserialize, Clone, Debug)] +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] pub struct GestureCommand { - state: GestureState, - intensity: f64, - speed: f64, - areas: Option>, + pub state: GestureState, + pub auto_switch: Option, + pub is_from_system: bool, + pub areas: Option>, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -232,4 +243,19 @@ pub struct GestureOverride { #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct ModManConfig { pub uart_ports: Vec<(String, u32)>, + pub restart_gestures: bool, + pub gesture_states: HashMap, + pub gestures_bg_by_default: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GestureStates { + /// Previous state of the gesture if we'd like to temporarily move back. + pub prev_state: Option, + /// Is this gesture paused? + pub paused: bool, + /// The current state of the gesture. + pub current_state: GestureState, + /// The next state to switch to (pre-loaded into Renderer and Modules if it loads resources), with a delay if we want to switch automatically. + pub next_state: Option<(f64, GestureState)>, } diff --git a/clover-hub/src/server/renderer/ipc.rs b/clover-hub/src/server/renderer/ipc.rs index fadf518..5f00fc7 100644 --- a/clover-hub/src/server/renderer/ipc.rs +++ b/clover-hub/src/server/renderer/ipc.rs @@ -1,24 +1,25 @@ -use log::{ - debug, - info, -}; +use anyhow::anyhow; +use log::debug; use nexus::server::models::IPCMessageWithId; -use serde::{ - Deserialize, - Serialize, -}; -use strum::VariantNames; +use std::str::FromStr; use tokio::sync::broadcast::Sender; use url::Url; -#[derive(Deserialize, Serialize, VariantNames)] +#[derive(Debug, PartialEq)] pub enum Events { - #[serde(rename = "/status")] - #[strum(serialize = "/status")] - Status, - #[serde(rename = "/gesture/begin")] - #[strum(serialize = "/gesture/begin")] - GestureBegin, + None, +} + +impl FromStr for Events { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + match input { + "" => Ok(Events::None), + "/" => Ok(Events::None), + _ => Err(anyhow!("String \"{}\" not part of enum!", input)), + } + } } pub async fn handle_ipc_msg(ipc_rx: Sender) { @@ -29,34 +30,18 @@ pub async fn handle_ipc_msg(ipc_rx: Sender) { if kind.host().unwrap() == url::Host::Domain("com.reboot-codes.clover.renderer") { debug!("Processing: {}", msg.kind.clone()); - match serde_json_lenient::from_str::(&format!("\"{}\"", kind.path())) { + match Events::from_str(kind.path()) { Ok(event_type) => { match event_type { - Events::Status => { - debug!("Return status?"); - } - Events::GestureBegin => { - let mut gesture_id = None; - for (key, val) in kind.query_pairs() { - if key == "gesture_id" { - gesture_id = Some(val.to_string()); - } - } - - match gesture_id { - Some(gesture_id_str) => { - info!("Begining gesture \"{}\"...", gesture_id_str.clone()); - } - Option::None => { - // TODO - } - } + _ => { + // TODO + debug!("TODO!"); } } } Err(_e) => { // TODO - todo!(); + debug!("No match!"); } } } diff --git a/clover-hub/src/server/renderer/mod.rs b/clover-hub/src/server/renderer/mod.rs index 62d367a..3bdd794 100644 --- a/clover-hub/src/server/renderer/mod.rs +++ b/clover-hub/src/server/renderer/mod.rs @@ -79,7 +79,7 @@ pub async fn renderer_main( cancellation_tokens .0 .run_until_cancelled(async move { - init_user.send( + let _ = init_user.send( &"nexus://com.reboot-codes.clover.renderer/status".to_string(), &"finished-init".to_string(), &None, diff --git a/clover-hub/src/server/renderer/system_ui/mod.rs b/clover-hub/src/server/renderer/system_ui/mod.rs index cbe0e6f..b496153 100644 --- a/clover-hub/src/server/renderer/system_ui/mod.rs +++ b/clover-hub/src/server/renderer/system_ui/mod.rs @@ -26,7 +26,6 @@ use systems::{ pub enum ExitState { Success, - Error, } unsafe impl Sync for ExitState {} diff --git a/clover-hub/src/server/warehouse/ipc.rs b/clover-hub/src/server/warehouse/ipc.rs index db84b12..0744e29 100644 --- a/clover-hub/src/server/warehouse/ipc.rs +++ b/clover-hub/src/server/warehouse/ipc.rs @@ -1,3 +1,6 @@ +use std::str::FromStr; + +use anyhow::anyhow; use log::{ debug, info, @@ -11,14 +14,21 @@ use strum::VariantNames; use tokio::sync::broadcast::Sender; use url::Url; -#[derive(Deserialize, Serialize, VariantNames)] +#[derive(Debug, PartialEq)] pub enum Events { - #[serde(rename = "/status")] - #[strum(serialize = "/status")] - Status, - #[serde(rename = "/gesture/begin")] - #[strum(serialize = "/gesture/begin")] - GestureBegin, + None, +} + +impl FromStr for Events { + type Err = anyhow::Error; + + fn from_str(input: &str) -> Result { + match input { + "" => Ok(Events::None), + "/" => Ok(Events::None), + _ => Err(anyhow!("String \"{}\" not part of enum!", input)), + } + } } pub async fn handle_ipc_msg(ipc_rx: Sender) { @@ -29,32 +39,19 @@ pub async fn handle_ipc_msg(ipc_rx: Sender) { if kind.host().unwrap() == url::Host::Domain("com.reboot-codes.clover.warehouse") { debug!("Processing: {}", msg.kind.clone()); - match serde_json_lenient::from_str::(&format!("\"{}\"", kind.path())) { + match Events::from_str(kind.path()) { Ok(event_type) => { match event_type { - Events::Status => { - debug!("Return status?"); - } - Events::GestureBegin => { - let mut gesture_id = None; - for (key, val) in kind.query_pairs() { - if key == "gesture_id" { - gesture_id = Some(val.to_string()); - } - } - - match gesture_id { - Some(gesture_id_str) => { - info!("Begining gesture \"{}\"...", gesture_id_str.clone()); - } - None => { - // TODO - } - } + _ => { + // TODO + debug!("TODO"); } } } - Err(e) => {} + Err(e) => { + // TODO + debug!("TODO"); + } } } } diff --git a/toolbox/ratchet/src/screens/configurator/gestures/gesture_detail.rs b/toolbox/ratchet/src/screens/configurator/gestures/gesture_detail.rs new file mode 100644 index 0000000..2d55d93 --- /dev/null +++ b/toolbox/ratchet/src/screens/configurator/gestures/gesture_detail.rs @@ -0,0 +1,92 @@ +use anyhow::Context; +use iced::{ + Element, + alignment, + widget::{ + button, + horizontal_space, + row, + text, + }, +}; +use iced_fonts::{ + REQUIRED_FONT, + required::{ + RequiredIcons, + icon_to_string, + }, +}; +use log::debug; + +use crate::{ + Message, + screens::configurator::{ + ConfiguratorScreen, + ConfiguratorTab, + }, +}; + +pub fn gesture_detail_tab( + configurator_screen: &ConfiguratorScreen, + content: &mut Vec>, + repo_id: &String, + gesture_pack_id: &String, + gesture_id: &String, + prev_screen: &Box, +) { + debug!("Gesture Detail Tab"); + + let repo = configurator_screen + .repos + .get(repo_id) + .with_context(|| { + format!( + "ConfiguratorScreen::update() should've ensured that repo: \"{}\" existed in the repo cache", + repo_id + ) + }) + .unwrap(); + + let gesture = repo + .gesture_packs + .get(gesture_pack_id) + .with_context(|| { + format!( + "ConfiguratorScreen::update() should've ensured that gesture pack: \"{}\" existed in the repo cache", + gesture_pack_id + ) + }) + .unwrap() + .gestures + .get(gesture_id) + .with_context(|| { + format!( + "ConfiguratorScreen::update() should've ensured that gesture: \"{}\" existed in the repo cache", + gesture_id + ) + }) + .unwrap(); + + content.push( + row(vec![ + (match &**prev_screen { + ConfiguratorTab::None => horizontal_space().into(), + _ => button(row(vec![ + text(icon_to_string(RequiredIcons::CaretLeftFill)) + .font(REQUIRED_FONT) + .width(iced::Length::Shrink) + .align_y(alignment::Vertical::Center) + .into(), + text("Back").into(), + ])) + .on_press(Message::SetConfiguratorTab(*prev_screen.clone())) + .into(), + }), + horizontal_space().into(), + button("Settings").into(), + ]) + .into(), + ); + + content.push(text(gesture.name.clone()).size(24).into()); +}