use crate::nodes::alias::get_original; use crate::nodes::Node; use crate::{core::client::Client, nodes::Message}; use color_eyre::eyre::Result; use once_cell::sync::OnceCell; use parking_lot::Mutex; use rustc_hash::FxHashMap; use serde::Serialize; use stardust_xr::scenegraph; use stardust_xr::scenegraph::ScenegraphError; use stardust_xr::schemas::flex::serialize; use std::future::Future; use std::os::fd::OwnedFd; use std::sync::{Arc, Weak}; use tokio::sync::oneshot; use tracing::{debug, debug_span}; #[derive(Default)] pub struct Scenegraph { pub(super) client: OnceCell>, 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) } } pub type MethodResponse = Result<(Vec, Vec), ScenegraphError>; pub struct MethodResponseSender(oneshot::Sender); impl MethodResponseSender { pub fn send(self, t: Result) { let _ = self.0.send(t.map(|m| (m.data, m.fds))); } // pub fn send_method_return( // self, // result: color_eyre::eyre::Result<(T, Vec)>, // ) { // let _ = self.0.send(map_method_return(result)); // } pub fn wrap_sync color_eyre::eyre::Result>(self, f: F) { self.send(f().map_err(|e| ScenegraphError::MethodError { error: e.to_string(), })) } pub fn wrap_async( self, f: impl Future)>> + Send + 'static, ) { tokio::task::spawn(async move { self.0.send(map_method_return(f.await)) }); } } fn map_method_return( result: color_eyre::eyre::Result<(T, Vec)>, ) -> Result<(Vec, Vec), ScenegraphError> { let (value, fds) = result.map_err(|e| ScenegraphError::MethodError { error: e.to_string(), })?; let serialized_value = serialize(value).map_err(|e| ScenegraphError::MethodError { error: format!("Internal: Serialization failed: {e}"), })?; Ok((serialized_value, fds)) } 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: oneshot::Sender, Vec), ScenegraphError>>, ) { let Some(client) = self.get_client() else { let _ = response.send(Err(ScenegraphError::NodeNotFound)); return; }; debug!(aspect_id, node_id, method, "Handle method"); let Some(node) = self.get_node(node_id) else { let _ = response.send(Err(ScenegraphError::NodeNotFound)); return; }; node.execute_local_method( client, aspect_id, method, Message { data: data.to_vec(), fds, }, MethodResponseSender(response), ); } }