use crate::{ core::{ client::Client, error::{Result, ServerError}, }, nodes::{Message, Node, alias::get_original}, }; use parking_lot::Mutex; use rustc_hash::FxHashMap; use serde::Serialize; use stardust_xr::{ messenger::MethodResponse, scenegraph::{self, ScenegraphError}, schemas::flex::serialize, }; use std::{ os::fd::OwnedFd, sync::{Arc, OnceLock, Weak}, }; use tracing::{debug, debug_span}; pub struct MethodResponseSender(pub(crate) MethodResponse); impl MethodResponseSender { pub fn send_err(self, error: ScenegraphError) { self.0.send(Err(error)); } pub fn send(self, result: Result) { let data = match result { Ok(d) => d, Err(e) => { self.0.send(Err(ScenegraphError::MemberError { error: e.to_string(), })); return; } }; let Ok(serialized) = stardust_xr::schemas::flex::serialize(data) else { self.0.send(Err(ScenegraphError::MemberError { error: "Internal: Failed to serialize".to_string(), })); return; }; self.0.send(Ok((&serialized, Vec::::new()))); } pub fn wrap Result>(self, f: F) { self.send(f()) } pub fn wrap_async( self, f: impl Future)>> + Send + 'static, ) { tokio::task::spawn(async move { let (value, fds) = match f.await { Ok(d) => d, Err(e) => { self.0.send(Err(ScenegraphError::MemberError { error: e.to_string(), })); return; } }; let Ok(serialized) = serialize(value) else { self.0.send(Err(ScenegraphError::MemberError { error: "Internal: Failed to serialize".to_string(), })); return; }; self.0.send(Ok((&serialized, fds))); }); } } impl std::fmt::Debug for MethodResponseSender { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("TypedMethodResponse").finish() } } #[derive(Default)] pub struct Scenegraph { pub(super) client: OnceLock>, nodes: Mutex>>, } impl Scenegraph { pub fn get_client(&self) -> Option> { self.client.get()?.upgrade() } pub fn add_node(&self, node: Node) -> Arc { let node_arc = Arc::new(node); self.add_node_raw(node_arc.clone()); node_arc } pub fn add_node_raw(&self, node: Arc) { debug!(node = ?&*node, "Add node"); self.nodes.lock().insert(node.get_id(), node); } pub fn get_node(&self, node: u64) -> Option> { let node = self.nodes.lock().get(&node)?.clone(); get_original(node, true) } pub fn remove_node(&self, node: u64) -> Option> { debug!(node, "Remove node"); self.nodes.lock().remove(&node) } } impl scenegraph::Scenegraph for Scenegraph { fn send_signal( &self, node_id: u64, aspect_id: u64, method: u64, data: &[u8], fds: Vec, ) -> Result<(), ScenegraphError> { let Some(client) = self.get_client() else { return Err(ScenegraphError::NodeNotFound); }; debug_span!("Handle signal", aspect_id, node_id, method).in_scope(|| { self.get_node(node_id) .ok_or(ScenegraphError::NodeNotFound)? .send_local_signal( client, aspect_id, method, Message { data: data.to_vec(), fds, }, ) }) } fn execute_method( &self, node_id: u64, aspect_id: u64, method: u64, data: &[u8], fds: Vec, response: MethodResponse, ) { let Some(client) = self.get_client() else { response.send(Err(ScenegraphError::NodeNotFound)); return; }; debug!(aspect_id, node_id, method, "Handle method"); let Some(node) = self.get_node(node_id) else { response.send(Err(ScenegraphError::NodeNotFound)); return; }; node.execute_local_method( client, aspect_id, method, Message { data: data.to_vec(), fds, }, MethodResponseSender(response), ); } }