pub mod alias; pub mod audio; pub mod data; pub mod drawable; pub mod fields; pub mod input; pub mod items; pub mod root; pub mod spatial; use self::alias::Alias; use crate::core::client::Client; use crate::core::registry::Registry; use crate::core::scenegraph::MethodResponseSender; use color_eyre::eyre::{eyre, Result}; use parking_lot::Mutex; use portable_atomic::{AtomicBool, Ordering}; use rustc_hash::FxHashMap; use serde::{de::DeserializeOwned, Serialize}; use spatial::Spatial; use stardust_xr::messenger::MessageSenderHandle; use stardust_xr::scenegraph::ScenegraphError; use stardust_xr::schemas::flex::{deserialize, serialize}; use std::any::Any; use std::fmt::Debug; use std::os::fd::OwnedFd; use std::sync::{Arc, Weak}; use std::vec::Vec; #[derive(Default)] pub struct Message { pub data: Vec, pub fds: Vec, } impl From> for Message { fn from(data: Vec) -> Self { Message { data, fds: Vec::new(), } } } impl AsRef<[u8]> for Message { fn as_ref(&self) -> &[u8] { &self.data } } stardust_xr_server_codegen::codegen_node_protocol!(); pub struct Owned; impl Aspect for Owned { impl_aspect_for_owned_aspect! {} } impl OwnedAspect for Owned { fn set_enabled(node: Arc, _calling_client: Arc, enabled: bool) -> Result<()> { node.set_enabled(enabled); Ok(()) } fn destroy(node: Arc, _calling_client: Arc) -> Result<()> { if node.destroyable { node.destroy(); } Ok(()) } } pub struct OwnedNode(pub Arc); impl Drop for OwnedNode { fn drop(&mut self) { self.0.destroy(); } } pub struct Node { enabled: AtomicBool, id: u64, client: Weak, message_sender_handle: Option, aliases: Registry, aspects: Aspects, destroyable: bool, } impl Node { pub fn get_client(&self) -> Option> { self.client.upgrade() } pub fn get_id(&self) -> u64 { self.id } pub fn generate(client: &Arc, destroyable: bool) -> Self { Self::from_id(client, client.generate_id(), destroyable) } pub fn from_id(client: &Arc, id: u64, destroyable: bool) -> Self { let node = Node { enabled: AtomicBool::new(true), client: Arc::downgrade(client), message_sender_handle: client.message_sender_handle.clone(), id, aliases: Default::default(), aspects: Default::default(), destroyable, }; node.aspects.add(Owned); node } pub fn add_to_scenegraph(self) -> Result> { Ok(self .get_client() .ok_or_else(|| eyre!("Internal: Unable to get client"))? .scenegraph .add_node(self)) } pub fn add_to_scenegraph_owned(self) -> Result { Ok(OwnedNode( self.get_client() .ok_or_else(|| eyre!("Internal: Unable to get client"))? .scenegraph .add_node(self), )) } pub fn enabled(&self) -> bool { self.enabled.load(Ordering::Relaxed) && if let Ok(spatial) = self.get_aspect::() { spatial .global_transform() .to_scale_rotation_translation() .0 .length_squared() > 0.0 } else { true } } pub fn set_enabled(&self, enabled: bool) { self.enabled.store(enabled, Ordering::Relaxed) } pub fn destroy(&self) { if let Some(client) = self.get_client() { client.scenegraph.remove_node(self.get_id()); } } // very much up for debate if we should allow this, as you can match objects using this // pub fn get_client_pid_flex( // node: Arc, // _calling_client: Arc, // _message: Message, // ) -> Result { // let client = node // .client // .upgrade() // .ok_or_else(|| eyre!("Could not get client for node?"))?; // let pid = client.pid.ok_or_else(|| eyre!("Client PID is unknown"))?; // Ok(serialize(pid)?.into()) // } pub fn add_aspect(&self, aspect: A) -> Arc { self.aspects.add(aspect) } pub fn add_aspect_raw(&self, aspect: Arc) { self.aspects.add_raw(aspect) } pub fn get_aspect(&self) -> Result> { self.aspects.get() } pub fn send_local_signal( self: Arc, calling_client: Arc, aspect_id: u64, method: u64, message: Message, ) -> Result<(), ScenegraphError> { if let Ok(alias) = self.get_aspect::() { if !alias.info.server_signals.iter().any(|e| *e == method) { return Err(ScenegraphError::SignalNotFound); } alias .original .upgrade() .ok_or(ScenegraphError::BrokenAlias)? .send_local_signal(calling_client, aspect_id, method, message) } else { let aspect = self .aspects .0 .lock() .get(&aspect_id) .ok_or(ScenegraphError::AspectNotFound)? .clone(); aspect .run_signal(calling_client, self.clone(), method, message) .map_err(|error| ScenegraphError::SignalError { error: error.to_string(), }) } } pub fn execute_local_method( self: Arc, calling_client: Arc, aspect_id: u64, method: u64, message: Message, response: MethodResponseSender, ) { if let Ok(alias) = self.get_aspect::() { if !alias.info.server_methods.iter().any(|e| *e == method) { response.send(Err(ScenegraphError::MethodNotFound)); return; } let Some(alias) = alias.original.upgrade() else { response.send(Err(ScenegraphError::BrokenAlias)); return; }; alias.execute_local_method( calling_client, aspect_id, method, Message { data: message.data.clone(), fds: Vec::new(), }, response, ) } else { let Some(aspect) = self.aspects.0.lock().get(&aspect_id).cloned() else { response.send(Err(ScenegraphError::AspectNotFound)); return; }; aspect.run_method(calling_client, self.clone(), method, message, response); } } pub fn send_remote_signal( &self, aspect_id: u64, method: u64, message: impl Into, ) -> Result<()> { let message = message.into(); self.aliases .get_valid_contents() .iter() .filter(|alias| alias.info.client_signals.iter().any(|e| e == &method)) .filter_map(|alias| alias.node.upgrade()) .for_each(|node| { // Beware! file descriptors will not be sent to aliases!!! let _ = node.send_remote_signal( aspect_id, method, Message { data: message.data.clone(), fds: Vec::new(), }, ); }); if let Some(handle) = self.message_sender_handle.as_ref() { handle.signal(self.id, aspect_id, method, &message.data, message.fds)?; } Ok(()) } pub async fn execute_remote_method_typed( &self, aspect_id: u64, method: u64, input: S, fds: Vec, ) -> Result<(D, Vec)> { let message_sender_handle = self .message_sender_handle .as_ref() .ok_or(eyre!("Messenger does not exist for this node"))?; let serialized = serialize(input)?; let result = message_sender_handle .method(self.id, aspect_id, method, &serialized, fds)? .await .map_err(|e| eyre!(e))?; let (message, fds) = result.into_components(); let deserialized: D = deserialize(&message)?; Ok((deserialized, fds)) } } impl Debug for Node { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Node") .field("id", &self.id) .field("destroyable", &self.destroyable) .finish() } } impl Drop for Node { fn drop(&mut self) { // Debug breakpoint } } pub trait Aspect: Any + Send + Sync + 'static { fn name(&self) -> String; fn id(&self) -> u64; fn as_any(self: Arc) -> Arc; fn run_signal( &self, calling_client: Arc, node: Arc, signal: u64, message: Message, ) -> Result<(), stardust_xr::scenegraph::ScenegraphError>; fn run_method( &self, calling_client: Arc, node: Arc, method: u64, message: Message, response: MethodResponseSender, ); } #[derive(Default)] struct Aspects(Mutex>>); impl Aspects { fn add(&self, t: A) -> Arc { let aspect = Arc::new(t); self.add_raw(aspect.clone()); aspect } fn add_raw(&self, aspect: Arc) { let id = aspect.id(); self.0.lock().insert(id, aspect); } fn get(&self) -> Result> { self.0 .lock() .values() .find_map(|a| Arc::downcast(a.clone().as_any()).ok()) .ok_or(eyre!("Couldn't get aspect")) } } impl Drop for Aspects { fn drop(&mut self) { self.0.lock().clear() } }