diff --git a/clover-hub/src/server/appd/mod.rs b/clover-hub/src/server/appd/mod.rs index 43f3dea..62b3a24 100644 --- a/clover-hub/src/server/appd/mod.rs +++ b/clover-hub/src/server/appd/mod.rs @@ -36,6 +36,8 @@ use tracing::{ // TODO: Create application manifest schema/models +pub const MODULE_EVT_ID: &str = "com/reboot-codes/clover/hub/appdaemon"; + pub async fn gen_user() -> UserConfig { UserConfig { user_type: "com.reboot-codes.com.clover.appd".to_string(), @@ -123,8 +125,8 @@ pub async fn appd_main( ); one_off_message( init_session.clone(), - &"com/reboot-codes/clover/server/appdaemon/status".to_string(), - &"ready:incomplete".to_string(), + &format!("{MODULE_EVT_ID}/status"), + "ready:incomplete", ) .await; } else { @@ -133,8 +135,8 @@ pub async fn appd_main( } one_off_message( init_session.clone(), - &"com/reboot-codes/clover/server/appdaemon/status".to_string(), - &"ready".to_string(), + &format!("{MODULE_EVT_ID}/status"), + "ready", ) .await; } diff --git a/clover-hub/src/server/inference_engine/mod.rs b/clover-hub/src/server/inference_engine/mod.rs index 3d06a4c..5744028 100644 --- a/clover-hub/src/server/inference_engine/mod.rs +++ b/clover-hub/src/server/inference_engine/mod.rs @@ -30,6 +30,8 @@ use crate::{ use super::warehouse::config::models::Config; +pub const MODULE_EVT_ID: &str = "com/reboot-codes/clover/hub/inference_engine"; + pub async fn gen_user() -> UserConfig { UserConfig { user_type: "com.reboot-codes.com.clover.inference-engine".to_string(), @@ -86,12 +88,7 @@ pub async fn inference_engine_main( cancellation_tokens .0 .run_until_cancelled(async move { - one_off_message( - session.clone(), - &"com/reboot-codes/clover/server/inference_engine/status".to_string(), - &"ready".to_string(), - ) - .await; + one_off_message(session.clone(), &format!("{MODULE_EVT_ID}/status"), "ready").await; }) .await; diff --git a/clover-hub/src/server/modman/gestures/command_generator.rs b/clover-hub/src/server/modman/gestures/command_generator.rs index b56b5f9..2fb07ef 100644 --- a/clover-hub/src/server/modman/gestures/command_generator.rs +++ b/clover-hub/src/server/modman/gestures/command_generator.rs @@ -1 +1,41 @@ -pub async fn gesture_command_generator() {} +use tracing::{ + debug, + instrument, +}; + +use crate::server::modman::models::{ + GestureParameters, + GestureState, + GestureStates, +}; + +#[instrument] +pub async fn gesture_command_generator(gesture_id: &String, gesture_state: &GestureStates) { + debug!( + "Cacluating gesture: {}, with: {:?}", + gesture_id, gesture_state + ); + + match gesture_state.current_state { + GestureState::Begin { + intensity, + speed, + background, + } => { + // Get supplemental configuration areas. (E.g. areas from @core.humanoid.furry.canine.domestic-dog.plantigrade in addition to @core, @core.humanoid.pentadactal, @core.humanoid.diopical) + + // Get Union of the gesture's supported areas, the instance's defined areas, and command requested areas. + + // Find all modules under applicable areas. + + // Calculate intensity + + // Calculate speed + + todo!(); + } + _ => { + // Not covered by this function, see `super::ipc::gestures`! + } + } +} diff --git a/clover-hub/src/server/modman/gestures/mod.rs b/clover-hub/src/server/modman/gestures/mod.rs index 64d45f7..04003db 100644 --- a/clover-hub/src/server/modman/gestures/mod.rs +++ b/clover-hub/src/server/modman/gestures/mod.rs @@ -67,17 +67,21 @@ pub mod command_generator; use std::sync::Arc; -use log::{ +use tokio_util::sync::CancellationToken; +use tracing::{ debug, error, + info, + instrument, }; -use tokio_util::sync::CancellationToken; -use crate::server::modman::models::{ - GestureState, - ModManStore, +use crate::server::modman::{ + gestures::command_generator::gesture_command_generator, + models::ModManStore, }; +/// Thread to calculate +#[instrument(skip(store, cancellation_token))] pub async fn gesture_command_generator_manager( store: Arc, cancellation_token: CancellationToken, @@ -96,19 +100,9 @@ pub async fn gesture_command_generator_manager( gesture_index_plus_one += 1; match store.gesture_states.lock().await.get(gesture_id) { - Some(gesture_state) => match gesture_state.current_state { - GestureState::Begin { - intensity, - speed, - background, - } => todo!(), - GestureState::Pause => todo!(), - _ => { - // Not covered by this function, see `super::ipc::gestures`! - } - }, + Some(gesture_state) => gesture_command_generator(gesture_id, gesture_state).await, None => { - error!("Gesture: {}, is not in state map, removing from background gesture array! This state de-sync is not permissable and should be reported as a bug!", gesture_id.clone()); + error!("Gesture: {}, is not in state map, removing from the gesture array! This state de-sync is not permissable and should be reported as a bug!", gesture_id.clone()); gestures_to_remove.push((gesture_index_plus_one - 1, gesture_id.clone())); continue; } @@ -124,4 +118,6 @@ pub async fn gesture_command_generator_manager( } } } + + info!("Stopped generating gesture commands!"); } diff --git a/clover-hub/src/server/modman/ipc/displays.rs b/clover-hub/src/server/modman/ipc/displays.rs new file mode 100644 index 0000000..cff8819 --- /dev/null +++ b/clover-hub/src/server/modman/ipc/displays.rs @@ -0,0 +1,75 @@ +use std::sync::Arc; + +use tokio_util::sync::CancellationToken; +use tracing::{ + debug, + error, + instrument, +}; + +use crate::server::{ + modman::{ + models::{ + CloverComponent, + ModManStore, + }, + MODULE_EVT_ID, + }, + renderer::system_ui::AnyDisplayComponent, +}; + +#[instrument(skip(store, session, cancellation_token))] +pub async fn display_queryable( + store: ModManStore, + session: Arc, + cancellation_token: CancellationToken, +) { + let key_expr = format!("{MODULE_EVT_ID}/displays/get"); + + let queryable = session.declare_queryable(&key_expr).await.unwrap(); + + debug!("Listening on {key_expr}!"); + while !cancellation_token.is_cancelled() { + match queryable.recv_async().await { + Ok(query) => { + debug!("Replying with all displays..."); + + let mut res = vec![]; + + for (_module_id, module_config) in store.modules.lock().await.iter() { + if module_config.initialized { + for (component_id, _is_critical) in &module_config.components { + match store.components.lock().await.get(component_id) { + Some(component_entry) => { + let component_config = component_entry.1.clone(); + + match component_config { + CloverComponent::PhysicalDisplayComponent(physical_display_config) => { + res.push(AnyDisplayComponent::Physical(physical_display_config)); + } + CloverComponent::VirtualDisplayComponent(virtual_display_config) => { + res.push(AnyDisplayComponent::Virtual(virtual_display_config)); + } + _ => {} + } + } + None => todo!(), + } + } + } + } + + match query + .reply(&key_expr, &serde_json_lenient::to_string(&res).unwrap()) + .await + { + Ok(_) => debug!("Successfully replied with all displays."), + Err(err) => error!("Failed to send reply with all registered displays, due to:\n{err}"), + } + } + Err(err) => { + error!("{err}") + } + } + } +} diff --git a/clover-hub/src/server/modman/ipc/gestures.rs b/clover-hub/src/server/modman/ipc/gestures.rs index 4a080c3..ea3023b 100644 --- a/clover-hub/src/server/modman/ipc/gestures.rs +++ b/clover-hub/src/server/modman/ipc/gestures.rs @@ -6,12 +6,17 @@ use log::{ info, warn, }; - -use crate::server::modman::models::{ - GestureCommand, - GestureState, - GestureStates, - ModManStore, +use tokio_util::sync::CancellationToken; +use tracing::instrument; + +use crate::server::modman::{ + models::{ + GestureCommand, + GestureState, + GestureStates, + ModManStore, + }, + MODULE_EVT_ID, }; pub async fn should_be_bg(store: Arc, bg_from_state: Option) -> bool { @@ -21,6 +26,26 @@ pub async fn should_be_bg(store: Arc, bg_from_state: Option) } } +#[instrument(skip(store, cancellation_token, session))] +pub async fn gesture_queryable( + store: ModManStore, + cancellation_token: CancellationToken, + session: Arc, +) { + let key_expr = format!("{MODULE_EVT_ID}/gestures/update"); + + let queryable = session.declare_queryable(&key_expr).await.unwrap(); + + debug!("Listening on {key_expr}!"); + while !cancellation_token.is_cancelled() { + match queryable.recv_async().await { + Ok(query) => {} + Err(e) => {} + } + } +} + +#[instrument(skip(store))] pub async fn handle_gesture_cmd( store: &mut Arc, gesture_id: String, diff --git a/clover-hub/src/server/modman/ipc/mod.rs b/clover-hub/src/server/modman/ipc/mod.rs index 0de5ed6..491c5b0 100644 --- a/clover-hub/src/server/modman/ipc/mod.rs +++ b/clover-hub/src/server/modman/ipc/mod.rs @@ -1,217 +1,38 @@ -mod gestures; +pub mod displays; +pub mod gestures; -use anyhow::anyhow; -use gestures::handle_gesture_cmd; -use log::{ - debug, - error, - warn, -}; -use nexus::{ - server::models::IPCMessageWithId, - user::NexusUser, -}; -use tokio::sync::broadcast::Sender; use tokio_util::sync::CancellationToken; use tracing::instrument; -use url::Url; -use crate::{ - server::{ - modman::models::{ - CloverComponent, - GestureCommand, - ModManStore, - }, - renderer::system_ui::AnyDisplayComponent, +use crate::server::modman::{ + ipc::{ + displays::display_queryable, + gestures::gesture_queryable, }, - utils::deserialize_base64, -}; -use std::{ - str::FromStr, - sync::Arc, + models::ModManStore, }; -#[derive(Debug, PartialEq)] -pub enum Events { - Status, - Gesture, - InitDisplays, - 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), - "/init-displays" => Ok(Events::InitDisplays), - "" => Ok(Events::None), - "/" => Ok(Events::None), - _ => Err(anyhow!("String \"{}\" not part of enum!", input)), - } - } -} +use std::sync::Arc; #[instrument(skip(ipc_token, ipc_session))] -pub async fn handle_ipc(ipc_token: CancellationToken, ipc_session: Arc) { - let subscriber = ipc_session - .declare_subscriber("com/reboot-codes/clover/server/inference_engine/**") - .await - .unwrap(); - - while !ipc_token.is_cancelled() { - match subscriber.recv_async().await { - Ok(sample) => { - // Refer to z_bytes.rs to see how to deserialize different types of message - let payload = sample - .payload() - .try_to_string() - .unwrap_or_else(|e| e.to_string().into()); - - debug!( - ">> [Subscriber] Received {} ('{}': '{}')", - sample.kind(), - sample.key_expr().as_str(), - payload - ); - if let Some(att) = sample.attachment() { - let att = att.try_to_string().unwrap_or_else(|e| e.to_string().into()); - debug!(" ({att})"); - } - } - Err(msg) => { - error!("{}", msg); - } - } - } -} - -/// LEGACY! -pub async fn handle_ipc_msg( +pub async fn handle_ipc( store: ModManStore, - ipc_rx: Sender, - user: Arc, + ipc_token: CancellationToken, + ipc_session: Arc, ) { - 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: \"{}\"...", kind.path()); - - match Events::from_str(kind.path()) { - Ok(event_type) => { - match event_type { - Events::Status => { - debug!("Return status?"); - } - Events::Gesture => { - debug!("Parsing event data..."); - - 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) => { - debug!("Parsed gesture id: {}", gesture_id_str.clone()); - let mut gesture_command = None; - - match deserialize_base64::(msg.message.clone().as_bytes()) { - Ok(obj) => gesture_command = Some(obj), - Err(e) => { - // TODO - error!("Error when parsing gesture command data: {}", e); - } - } - - match gesture_command { - 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??"); - } - } - } - None => { - // TODO reply! - warn!("Gesture ID not included! Use state event instead."); - } - } - } - Events::InitDisplays => { - for (_module_id, module_config) in store.modules.lock().await.iter() { - if module_config.initialized { - for (component_id, _is_critical) in &module_config.components { - match store.components.lock().await.get(component_id) { - Some(component_entry) => { - let component_config = component_entry.1.clone(); - - match component_config { - CloverComponent::PhysicalDisplayComponent(physical_display_config) => { - match user.send( - &"nexus://com.reboot-codes.clover.renderer/register-display" - .to_string(), - &serde_json_lenient::to_string(&AnyDisplayComponent::Physical( - physical_display_config, - )) - .unwrap(), - &None, - ) { - Err(e) => { - error!("Error when attempting to send registered display registration to peers: {}", e); - } - _ => {} - } - } - CloverComponent::VirtualDisplayComponent(virtual_display_config) => { - match user.send( - &"nexus://com.reboot-codes.clover.renderer/register-display" - .to_string(), - &serde_json_lenient::to_string(&AnyDisplayComponent::Virtual( - virtual_display_config, - )) - .unwrap(), - &None, - ) { - Err(e) => { - error!("Error when attempting to send registered display registration to peers: {}", e); - } - _ => {} - } - } - _ => {} - } - } - None => todo!(), - } - } - } - } - } - _ => { - debug!("Blank event... doing nothing."); - } - } - } - Err(e) => { - debug!("Failed to parse path: {}, due to: {}", kind.path(), e); - } - } - } - } + let display_store = store.clone(); + let display_session = ipc_session.clone(); + let display_token = ipc_token.clone(); + let displays_handle = tokio::task::spawn(async move { + display_queryable(display_store, display_session, display_token).await; + }); + + let gesture_store = store.clone(); + let gesture_session = ipc_session.clone(); + let gesture_token = ipc_token.clone(); + let gestures_handle = tokio::task::spawn(async move { + gesture_queryable(gesture_store, gesture_token, gesture_session).await; + }); + + futures::future::join_all(vec![displays_handle, gestures_handle]).await; } diff --git a/clover-hub/src/server/modman/mod.rs b/clover-hub/src/server/modman/mod.rs index d5675cc..f9dbb87 100644 --- a/clover-hub/src/server/modman/mod.rs +++ b/clover-hub/src/server/modman/mod.rs @@ -14,7 +14,6 @@ pub mod models; pub mod modules; use busses::start_busses; -use ipc::handle_ipc_msg; use models::ModManStore; use modules::{ deinit_module, @@ -40,6 +39,8 @@ use crate::{ utils::one_off_message, }; +pub const MODULE_EVT_ID: &str = "com/reboot-codes/clover/hub/modman"; + /// The minimum required permissions and configuration for ModMan to use Nexus. pub async fn gen_user() -> UserConfig { UserConfig { @@ -77,7 +78,8 @@ pub async fn modman_main( let ipc_token = cancellation_tokens.0.clone(); let ipc_session = session.clone(); - let ipc_handle = tokio::task::spawn(handle_ipc(ipc_token, ipc_session)); + let ipc_store = store.clone(); + let ipc_handle = tokio::task::spawn(handle_ipc(ipc_store, ipc_token, ipc_session)); let bus_store = Arc::new(store.clone()); let bus_token = cancellation_tokens.0.clone(); @@ -91,19 +93,6 @@ 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_user = Arc::new(user.clone()); - let ipc_recv_handle = tokio::task::spawn(async move { - tokio::select! { - _ = ipc_recv_token.cancelled() => { - debug!("ipc_recv exited"); - }, - _ = handle_ipc_msg(ipc_recv_store, ipc_rx, ipc_user) => {} - } - }); - let init_session = session.clone(); let init_store = Arc::new(store.clone()); cancellation_tokens @@ -171,8 +160,8 @@ pub async fn modman_main( ); one_off_message( init_session.clone(), - &"com/reboot-codes/clover/server/appdaemon".to_string(), - &"ready:incomplete".to_string(), + &format!("{MODULE_EVT_ID}/status"), + "ready:incomplete", ) .await; } else { @@ -181,8 +170,8 @@ pub async fn modman_main( } one_off_message( init_session.clone(), - &"com/reboot-codes/clover/server/appdaemon/status".to_string(), - &"ready".to_string(), + &format!("{MODULE_EVT_ID}/status"), + "ready", ) .await; } @@ -193,7 +182,6 @@ pub async fn modman_main( tokio::select! { _ = mod_clean_token.cancelled() => { bus_handle.abort(); - ipc_recv_handle.abort(); ipc_handle.abort(); info!("Cleaning up modules..."); diff --git a/clover-hub/src/server/modman/models.rs b/clover-hub/src/server/modman/models.rs index 48088fc..fa1390e 100644 --- a/clover-hub/src/server/modman/models.rs +++ b/clover-hub/src/server/modman/models.rs @@ -40,12 +40,17 @@ use super::components::models::CloverComponentTrait; /// Modules are comprised of [Components](CloverComponent) and their [Metadata](CloverComponentMeta). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Module { + /// RFQDN of the module definition from the manifest database. pub module_type: String, + /// Manifest-defined name for this module (e.g. recognizable model number). pub module_name: String, + /// User defined pretty name with manifest-defined default. pub custom_name: Option, + /// Has communication been established and self-test run? pub initialized: bool, - /// Component ID and if it's critical + /// Vec of Component IDs and if they're critical. pub components: Vec<(String, bool)>, + /// Either `com.reboot-codes.clover.hub` or the RFQDN of the app that manages this module. pub registered_by: String, } @@ -66,12 +71,13 @@ pub struct CloverComponentMeta { /// Is this component required for the module to work? Default: yes. /// If any critical component fails to initalize, the module will fail to initalize entirely. pub critical: bool, - /// Where this component is on/in the user. RFQDN formatted, e.g. `com.reboot-codes.CORE.head.eyes.internal` + /// Where this component is on/in the user. RFQDN formatted, e.g. `com.reboot-codes.CORE.head.eyes.internal` for a HUD display pub location: String, /// Parameters used for gesture events to synthesize commands to send to this component if it supports RX from Nexus. /// This is also used to determine if a gesture is supported by this component. /// Ignored if the component does not support recv. pub base_gesture_parameters: HashMap, + /// If the component is internal, usually inferenced from the `location` parameter. Used by the permissions/privacy rules model. pub internal: bool, } @@ -130,10 +136,17 @@ impl CloverComponentTrait for CloverComponent { /// ) + offset /// ``` pub struct GestureParameters { - min: f64, - max: f64, - multiplier: f64, - offset: f64, + pub min: f64, + pub max: f64, + pub multiplier: f64, + pub offset: f64, +} + +impl GestureParameters { + pub fn calculate_intensity(&self, intensity: f64) -> f64 { + return ((((intensity + 1.0) * (self.max - self.min)) + self.min) * self.multiplier) + + self.offset; + } } /// In memory data-store for components, modules, and any needed configuration. @@ -199,16 +212,28 @@ pub enum GestureState { #[serde(rename = "begin")] #[strum(serialize = "begin")] Begin { + /// Multiplier over the value (y) axis of the gesture's smoothing curve. intensity: f64, + /// Multiplier over the time (x) axis of the gesture's smoothing curve. speed: f64, + /// Background gestures will be calculated before foreground gestures. Foreground gestures will always override background gestures. + /// + /// For example, you can have a background gesture that displays intermittent blinking, but you can start a temporary foreground gesture to show a different shape of the eyes to display an emotion. background: Option, }, + /// Resume calculation of module commands. + /// + /// This state is not saved at all. #[serde(rename = "unpause")] #[strum(serialize = "unpause")] UnPause, + /// Temporarilly freeze the values that were already calculated for module commands as a result of this gesture. + /// + /// This state is not saved. Upon shutdown, if a foreground gesture is paused, the gesture will be removed from the stack upon shutdown; otherwise, background gestures will be saved in the `Begin` state to be automatically resumed upon startup. #[serde(rename = "pause")] #[strum(serialize = "end")] Pause, + /// Removes the gesture from module command calculations entierly. #[serde(rename = "end")] #[strum(serialize = "end")] End, @@ -223,13 +248,7 @@ pub struct GestureCommand { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub enum GestureConfig { - Static(String), - Reactive(ReactiveGestureConfig), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ReactiveGestureConfig { +pub struct GestureConfig { /// The primary gesture pack to use for this component pub primary_gesture_pack: Option, /// The default gesture for the component to use when idle. diff --git a/clover-hub/src/server/modman/modules.rs b/clover-hub/src/server/modman/modules.rs index 708cf4f..12b9ce2 100644 --- a/clover-hub/src/server/modman/modules.rs +++ b/clover-hub/src/server/modman/modules.rs @@ -47,13 +47,16 @@ use super::{ Module, }, }; -use log::{ +use std::sync::Arc; +use tracing::{ + debug, error, info, + instrument, warn, }; -use std::sync::Arc; +#[instrument(skip(store))] pub async fn init_component( store: &ModManStore, module_id: String, @@ -122,6 +125,7 @@ pub async fn init_component( } } +#[instrument(skip(store))] pub async fn init_module(store: &ModManStore, id: String, module: Module) -> (bool, usize) { let mut initialized_module = module.initialized; let mut initialized_module_components = 0; @@ -170,6 +174,8 @@ pub async fn init_module(store: &ModManStore, id: String, module: Module) -> (bo } } + debug!("Module: {id}, Done initializing components!"); + match critical_failiure { Some(failiure) => { let (component_id, e) = failiure; @@ -194,6 +200,7 @@ pub async fn init_module(store: &ModManStore, id: String, module: Module) -> (bo error!("Module: {}, failed to initialize!", id.clone()); } } else { + debug!("Finished initalizing module."); initialized_module = true; } } @@ -201,32 +208,41 @@ pub async fn init_module(store: &ModManStore, id: String, module: Module) -> (bo } } + debug!("Module: {id}, Marked as initialized."); + + // Update the store with new state of the module. if initialized_module { - // Update the store with new state of the module. - if initialized_module { - store.modules.lock().await.insert( - id.clone(), - Module { - module_type: module.module_type.clone(), - module_name: module.module_name.clone(), - custom_name: module.custom_name.clone(), - initialized: true, - components: module.components.clone(), - registered_by: module.registered_by.clone(), - }, - ); + debug!("Module: {id}, Waiting on in-memory store lock..."); + store.modules.lock().await.insert( + id.clone(), + Module { + module_type: module.module_type.clone(), + module_name: module.module_name.clone(), + custom_name: module.custom_name.clone(), + initialized: true, + components: module.components.clone(), + registered_by: module.registered_by.clone(), + }, + ); + debug!("Module: {id}, In-memory store updated!"); - info!( - "Module: {} ({}), Initialized!", - module.get_name(), - id.clone() - ); - } + info!( + "Module: {} ({}), Initialized!", + module.get_name(), + id.clone() + ); + } else { + error!( + "Module: {} ({}), failed to initialize!", + module.get_name(), + id.clone() + ); } (initialized_module, initialized_module_components) } +#[instrument(skip(store))] pub async fn deinit_component( store: &ModManStore, module_id: String, @@ -290,6 +306,7 @@ pub async fn deinit_component( } } +#[instrument(skip(store))] pub async fn deinit_module(store: &ModManStore, id: String, module: Module) -> (bool, usize) { let mut initialized_module = module.initialized; let mut deinitialized_module_components = 0; diff --git a/clover-hub/src/server/renderer/mod.rs b/clover-hub/src/server/renderer/mod.rs index 842fdaa..b51bb6b 100644 --- a/clover-hub/src/server/renderer/mod.rs +++ b/clover-hub/src/server/renderer/mod.rs @@ -12,7 +12,10 @@ pub mod models; pub mod system_ui; use self::system_ui::system_ui_main; -use crate::server::renderer::ipc::handle_ipc; +use crate::server::{ + modman::MODULE_EVT_ID as MODMAN_EVT_ID, + renderer::ipc::handle_ipc, +}; use crate::utils::one_off_message; use crate::utils::RecvSync; use nexus::{ @@ -35,6 +38,8 @@ use tracing::{ use super::warehouse::config::models::Config; +pub const MODULE_EVT_ID: &str = "com/reboot-codes/clover/hub/renderer"; + pub async fn gen_user() -> UserConfig { UserConfig { user_type: "com.reboot-codes.com.clover.renderer".to_string(), @@ -104,31 +109,65 @@ pub async fn renderer_main( // let display_handles = Arc::new(HashMap::new()); let init_session = session.clone(); - let init_user = Arc::new(user.clone()); cancellation_tokens .0 .run_until_cancelled(async move { info!("Requesting displays to setup in SystemUI from ModMan..."); - match init_user.send( - &"nexus://com.reboot-codes.clover.modman/init-displays".to_string(), - &"first-time".to_string(), - &None, - ) { + + match init_session + .get(format!("{MODMAN_EVT_ID}/displays/get")) + .await + { + Ok(reply_fifo) => match reply_fifo.recv_async().await { + Ok(reply) => match reply.result() { + Ok(sample) => { + let payload = sample + .payload() + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); + + debug!("Got displays: {:?}", payload); + + one_off_message( + init_session.clone(), + &format!("{MODULE_EVT_ID}/status"), + "ready", + ) + .await; + } + Err(e) => { + let payload = e + .payload() + .try_to_string() + .unwrap_or_else(|e| e.to_string().into()); + error!(">> Received (ERROR: '{payload}')"); + + one_off_message( + init_session.clone(), + &format!("{MODULE_EVT_ID}/status"), + "ready:incomplete", + ) + .await; + } + }, + Err(_) => { + one_off_message( + init_session.clone(), + &format!("{MODULE_EVT_ID}/status"), + "ready:incomplete", + ) + .await; + } + }, Err(e) => { - error!( - "Error when requesting display configurations from peers: {}", - e - ); + one_off_message( + init_session.clone(), + &format!("{MODULE_EVT_ID}/status"), + "ready:incomplete", + ) + .await; } - _ => {} } - - one_off_message( - init_session.clone(), - &"com/reboot-codes/clover/server/renderer/status".to_string(), - &"ready".to_string(), - ) - .await; }) .await; diff --git a/clover-hub/src/server/renderer/system_ui/mod.rs b/clover-hub/src/server/renderer/system_ui/mod.rs index ace97c7..51052ab 100644 --- a/clover-hub/src/server/renderer/system_ui/mod.rs +++ b/clover-hub/src/server/renderer/system_ui/mod.rs @@ -120,7 +120,7 @@ pub fn system_ui_main(custom_bevy_ipc: SystemUIIPC, disable_winit: Option) .set(WindowPlugin { primary_window: Some(Window { title: "Clover".into(), - resolution: (100.0, 100.0).into(), + resolution: (200.0, 500.0).into(), present_mode: PresentMode::AutoVsync, // Tells Wasm to resize the window according to the available canvas fit_canvas_to_parent: true, diff --git a/clover-hub/src/server/warehouse/ipc.rs b/clover-hub/src/server/warehouse/ipc.rs index 8937f78..99aab8d 100644 --- a/clover-hub/src/server/warehouse/ipc.rs +++ b/clover-hub/src/server/warehouse/ipc.rs @@ -1,3 +1,4 @@ +use super::MODULE_EVT_ID; use std::sync::Arc; use tokio_util::sync::CancellationToken; @@ -10,7 +11,7 @@ use tracing::{ #[instrument(skip(ipc_token, ipc_session))] pub async fn handle_ipc(ipc_token: CancellationToken, ipc_session: Arc) { let subscriber = ipc_session - .declare_subscriber("com/reboot-codes/clover/server/inference_engine/**") + .declare_subscriber(&format!("{MODULE_EVT_ID}/**")) .await .unwrap(); diff --git a/clover-hub/src/server/warehouse/mod.rs b/clover-hub/src/server/warehouse/mod.rs index 586a998..c95b245 100644 --- a/clover-hub/src/server/warehouse/mod.rs +++ b/clover-hub/src/server/warehouse/mod.rs @@ -240,6 +240,8 @@ pub async fn gen_user() -> UserConfig { } } +pub const MODULE_EVT_ID: &str = "com/reboot-codes/clover/hub/warehouse"; + /// Main service function for Warehouse. Maintains an ongoing connection to Zenoh, and will manage filesystem operations as needed. #[instrument(skip(store, user, cancellation_tokens))] pub async fn warehouse_main( @@ -286,8 +288,8 @@ pub async fn warehouse_main( one_off_message( session.clone(), - &"com/reboot-codes/clover/server/warehouse/status".to_string(), - &"ready".to_string(), + "com/reboot-codes/clover/server/warehouse/status", + "ready", ) .await; }) diff --git a/clover-hub/src/utils.rs b/clover-hub/src/utils.rs index 81a9574..f4dea1a 100644 --- a/clover-hub/src/utils.rs +++ b/clover-hub/src/utils.rs @@ -116,17 +116,17 @@ where /// One time publisher to a topic over a Zenoh session. For any longer term publishing, setup a publisher manually! #[instrument(skip(session))] -pub async fn one_off_message(session: Arc, topic: &String, message: &String) { - let publisher = session.declare_publisher(topic.clone()).await.unwrap(); +pub async fn one_off_message(session: Arc, topic: &str, message: &str) { + let publisher = session.declare_publisher(topic).await.unwrap(); - match publisher.put(message.clone()).await { + match publisher.put(message).await { Ok(_) => { - debug!("Sucessfully sent message to topic: {}", &topic); + debug!("Sucessfully sent message to topic: {}", topic); } Err(_) => { error!( "Failed to send message to zenoh topic: {}, this may be a sign of a misconfiguration!!", - &topic + topic ); } } diff --git a/core/gesture-packs/default/gesture-pack.clover.json b/core/gesture-packs/default/gesture-pack.clover.json index 634787a..b2a0dd5 100644 --- a/core/gesture-packs/default/gesture-pack.clover.json +++ b/core/gesture-packs/default/gesture-pack.clover.json @@ -15,10 +15,17 @@ "torso.core.back.spine.tail": { "@animation": { "type": "bounce", - "speed": 1000.0, + "curve": "linear", + "duration": 1000.0, "keyframes": [ - { "x": -45.0, "y": "@inital" }, - { "x": 45.0, "y": "@inital" } + { + "x": -45.0, + "y": "@inital" + }, + { + "x": 45.0, + "y": "@inital" + } ] } }