use super::alias::AliasInfo; use super::fields::Field; use super::spatial::{parse_transform, Spatial}; use super::{Alias, Aspect, Node}; use crate::core::client::Client; use crate::core::node_collections::LifeLinkedNodeMap; use crate::core::registry::Registry; use crate::create_interface; use crate::nodes::fields::FIELD_ALIAS_INFO; use crate::nodes::spatial::Transform; use color_eyre::eyre::{bail, ensure, eyre, Result}; use lazy_static::lazy_static; use nanoid::nanoid; use parking_lot::Mutex; use rustc_hash::FxHashMap; use stardust_xr::schemas::flex::flexbuffers; use stardust_xr::values::Datamap; use std::sync::{Arc, Weak}; lazy_static! { pub static ref KEYMAPS: Mutex> = Mutex::new(FxHashMap::default()); } static PULSE_SENDER_REGISTRY: Registry = Registry::new(); pub static PULSE_RECEIVER_REGISTRY: Registry = Registry::new(); pub fn get_mask(datamap: &Datamap) -> Result> { flexbuffers::Reader::get_root(datamap.raw().as_slice()) .map_err(|_| eyre!("Mask is not a valid flexbuffer"))? .get_map() .map_err(|_| eyre!("Mask is not a valid map")) } pub fn mask_matches(mask_map_lesser: &Datamap, mask_map_greater: &Datamap) -> bool { (|| -> Result<_> { for key in get_mask(mask_map_lesser)?.iter_keys() { let lesser_key = get_mask(mask_map_lesser)?.index(key)?; let greater_key = get_mask(mask_map_greater)?.index(key)?; // otherwise zero-length vectors don't count the same as a single type vector if lesser_key.flexbuffer_type().is_heterogenous_vector() && lesser_key.as_vector().len() == 0 && greater_key.flexbuffer_type().is_vector() { continue; } if !lesser_key.flexbuffer_type().is_null() && lesser_key.flexbuffer_type() != greater_key.flexbuffer_type() { return Err(flexbuffers::ReaderError::InvalidPackedType {}.into()); } } Ok(()) })() .is_ok() } stardust_xr_server_codegen::codegen_data_protocol!(); pub struct PulseSender { node: Weak, pub mask: Datamap, aliases: LifeLinkedNodeMap, } impl PulseSender { pub fn add_to(node: &Arc, mask: Datamap) -> Result> { let sender = PulseSender { node: Arc::downgrade(node), mask, aliases: LifeLinkedNodeMap::default(), }; // ::add_node_members(node); let sender = PULSE_SENDER_REGISTRY.add(sender); node.add_aspect_raw(sender.clone()); for receiver in PULSE_RECEIVER_REGISTRY.get_valid_contents() { sender.handle_new_receiver(&receiver); } Ok(sender.clone()) } fn handle_new_receiver(&self, receiver: &PulseReceiver) { if !mask_matches(&self.mask, &receiver.mask) { return; } let Some(tx_node) = self.node.upgrade() else { return; }; let Some(tx_client) = tx_node.get_client() else { return; }; let Some(rx_node) = receiver.node.upgrade() else { return; }; // Receiver itself let Ok(rx_alias) = Alias::create( &tx_client, tx_node.get_path(), receiver.uid.as_str(), &rx_node, AliasInfo { server_methods: vec!["send_data"], ..Default::default() }, ) else { return; }; self.aliases.add(receiver.uid.clone(), &rx_alias); // Receiver's field let Ok(rx_field_alias) = Alias::create( &tx_client, rx_alias.get_path(), "field", &rx_node.get_aspect::().unwrap().field_node, FIELD_ALIAS_INFO.clone(), ) else { return; }; self.aliases .add(receiver.uid.clone() + "-field", &rx_field_alias); let _ = pulse_sender_client::new_receiver(&tx_node, &receiver.uid, &rx_alias, &rx_field_alias); } fn handle_drop_receiver(&self, receiver: &PulseReceiver) { let uid = receiver.uid.as_str(); self.aliases.remove(uid); self.aliases.remove(&(uid.to_string() + "-field")); let Some(tx_node) = self.node.upgrade() else { return; }; let _ = pulse_sender_client::drop_receiver(&tx_node, uid); } } impl Aspect for PulseSender { const NAME: &'static str = "PulseSender"; } impl PulseSenderAspect for PulseSender {} impl Drop for PulseSender { fn drop(&mut self) { PULSE_SENDER_REGISTRY.remove(self); } } pub struct PulseReceiver { uid: String, pub node: Weak, pub field_node: Arc, pub mask: Datamap, } impl PulseReceiver { pub fn add_to( node: &Arc, field_node: Arc, mask: Datamap, ) -> Result> { let receiver = PulseReceiver { uid: nanoid!(), node: Arc::downgrade(node), field_node, mask, }; let receiver = PULSE_RECEIVER_REGISTRY.add(receiver); ::add_node_members(node); node.add_aspect_raw(receiver.clone()); for sender in PULSE_SENDER_REGISTRY.get_valid_contents() { sender.handle_new_receiver(&receiver); } Ok(receiver) } } impl Aspect for PulseReceiver { const NAME: &'static str = "PulseReceiver"; } impl PulseReceiverAspect for PulseReceiver { fn send_data( node: Arc, _calling_client: Arc, sender: Arc, data: Datamap, ) -> Result<()> { let this_receiver = node.get_aspect::().unwrap(); ensure!( mask_matches(&this_receiver.mask, &data), "Message ({data:?}) does not contain the same keys as the receiver's mask ({:?})", this_receiver.mask ); pulse_receiver_client::data(&node, &sender.uid, &data)?; Ok(()) } } impl Drop for PulseReceiver { fn drop(&mut self) { PULSE_RECEIVER_REGISTRY.remove(self); for sender in PULSE_SENDER_REGISTRY.get_valid_contents() { sender.handle_drop_receiver(self); } } } create_interface!(DataInterface, DataInterfaceAspect, "/data"); struct DataInterface; impl DataInterfaceAspect for DataInterface { fn create_pulse_sender( _node: Arc, calling_client: Arc, name: String, parent: Arc, transform: Transform, mask: Datamap, ) -> Result<()> { get_mask(&mask)?; let node = Node::create_parent_name( &calling_client, Self::CREATE_PULSE_SENDER_PARENT_PATH, &name, true, ); let parent = parent.get_aspect::()?; let transform = transform.to_mat4(true, true, false); let node = node.add_to_scenegraph()?; Spatial::add_to(&node, Some(parent.clone()), transform, false); PulseSender::add_to(&node, mask)?; Ok(()) } fn create_pulse_receiver( _node: Arc, calling_client: Arc, name: String, parent: Arc, transform: Transform, field: Arc, mask: Datamap, ) -> Result<()> { get_mask(&mask)?; let node = Node::create_parent_name( &calling_client, Self::CREATE_PULSE_RECEIVER_PARENT_PATH, &name, true, ); let parent = parent.get_aspect::()?; let transform = parse_transform(transform, true, true, false); let _ = field.get_aspect::()?; let node = node.add_to_scenegraph()?; Spatial::add_to(&node, Some(parent.clone()), transform, false); PulseReceiver::add_to(&node, field, mask)?; Ok(()) } async fn register_keymap( _node: Arc, _calling_client: Arc, keymap: String, ) -> Result { let mut keymaps = KEYMAPS.lock(); if let Some(found_keymap_id) = keymaps .iter() .filter(|(_k, v)| *v == &keymap) .map(|(k, _v)| k) .last() { return Ok(found_keymap_id.clone()); } let generated_id = nanoid!(); keymaps.insert(generated_id.clone(), keymap); Ok(generated_id) } async fn get_keymap( _node: Arc, _calling_client: Arc, keymap_id: String, ) -> Result { let keymaps = KEYMAPS.lock(); let Some(keymap) = keymaps.get(&keymap_id) else { bail!("Could not find keymap. Try registering it") }; Ok(keymap.clone()) } }