From cbfd4c13c2a9e47b225a1d47ad1d2fe75c0c1da8 Mon Sep 17 00:00:00 2001 From: Nova Date: Mon, 16 May 2022 14:19:08 -0400 Subject: [PATCH] feat: basic scenegraph, node, and spatial --- Cargo.lock | 23 +++++++++++++ Cargo.toml | 4 ++- src/core/client.rs | 2 +- src/core/eventloop.rs | 22 ++++++++++--- src/core/mod.rs | 1 + src/core/scenegraph.rs | 66 +++++++++++++++++++++++++++++++++++++ src/main.rs | 11 +++++++ src/nodes/core.rs | 74 ++++++++++++++++++++++++++++++++++++++++++ src/nodes/mod.rs | 1 + src/nodes/spatial.rs | 0 10 files changed, 197 insertions(+), 7 deletions(-) create mode 100644 src/core/scenegraph.rs create mode 100644 src/nodes/core.rs create mode 100644 src/nodes/mod.rs create mode 100644 src/nodes/spatial.rs diff --git a/Cargo.lock b/Cargo.lock index d983db6..3d57670 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -66,6 +66,16 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "ctrlc" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b37feaa84e6861e00a1f5e5aa8da3ee56d605c9992d33e082786754828e20865" +dependencies = [ + "nix", + "winapi", +] + [[package]] name = "dirs" version = "4.0.0" @@ -193,6 +203,17 @@ dependencies = [ "rand", ] +[[package]] +name = "nix" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f17df307904acd05aa8e32e97bb20f2a0df1728bbc2d771ae8f9a90463441e9" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -349,9 +370,11 @@ name = "stardust-xr" version = "0.9.0" dependencies = [ "anyhow", + "ctrlc", "libstardustxr", "mio", "slab", + "thiserror", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index dccddc1..ea2162e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,7 @@ version = "0.9.0" [dependencies] libstardustxr = {path = "../libstardustxr-rs"} anyhow = "1.0.57" +ctrlc = "3.2.2" mio = {version = "0.8.3", features = ["net", "os-poll", "os-ext"]} -slab = "0.4.6" \ No newline at end of file +slab = "0.4.6" +thiserror = "1.0.31" diff --git a/src/core/client.rs b/src/core/client.rs index c7bfb33..6a49d77 100644 --- a/src/core/client.rs +++ b/src/core/client.rs @@ -1,4 +1,4 @@ -use libstardustxr::fusion::scenegraph::Scenegraph; +use super::scenegraph::Scenegraph; use libstardustxr::messenger::Messenger; use mio::net::UnixStream; use std::rc::{Rc, Weak}; diff --git a/src/core/eventloop.rs b/src/core/eventloop.rs index 74ca3e8..7c26487 100644 --- a/src/core/eventloop.rs +++ b/src/core/eventloop.rs @@ -22,7 +22,7 @@ impl EventLoop { let mut socket = UnixListener::bind(socket_path.clone())?; let (sender, mut receiver) = pipe::new()?; let join_handle = Some(thread::spawn(move || -> Result<()> { - let mut clients: Slab = Slab::new(); + let mut clients: Slab> = Slab::new(); let mut poll = Poll::new()?; let mut events = Events::with_capacity(1024); const LISTENER: Token = Token(usize::MAX - 1); @@ -37,8 +37,15 @@ impl EventLoop { match event.token() { LISTENER => loop { match socket.accept() { - Ok((socket, _)) => { - clients.insert(Client::from_connection(socket)); + Ok((mut socket, _)) => { + let client_number = clients.insert(None); + poll.registry().register( + &mut socket, + Token(client_number), + Interest::READABLE, + )?; + let client = Client::from_connection(socket); + *clients.get_mut(client_number).unwrap() = Some(client); } Err(e) => { if e.kind() == std::io::ErrorKind::WouldBlock { @@ -50,7 +57,7 @@ impl EventLoop { }, STOP => return Ok(()), token => loop { - match clients.get(token.0).unwrap().dispatch() { + match clients.get(token.0).unwrap().as_ref().unwrap().dispatch() { Ok(_) => continue, Err(e) => { if e.kind() == std::io::ErrorKind::WouldBlock { @@ -76,6 +83,11 @@ impl Drop for EventLoop { fn drop(&mut self) { let buf: [u8; 1] = [1; 1]; let _ = self.stop_write.write(buf.as_slice()); - let _ = self.join_handle.take().unwrap().join(); + let _ = self + .join_handle + .take() + .unwrap() + .join() + .expect("Couldn't join the event loop thread at drop"); } } diff --git a/src/core/mod.rs b/src/core/mod.rs index cd46d1c..91c4c83 100644 --- a/src/core/mod.rs +++ b/src/core/mod.rs @@ -1,2 +1,3 @@ pub mod client; pub mod eventloop; +pub mod scenegraph; diff --git a/src/core/scenegraph.rs b/src/core/scenegraph.rs new file mode 100644 index 0000000..2e28973 --- /dev/null +++ b/src/core/scenegraph.rs @@ -0,0 +1,66 @@ +use crate::nodes::core::Node; +use anyhow::Result; +use libstardustxr::scenegraph; +use libstardustxr::scenegraph::ScenegraphError; +use std::{cell::RefCell, collections::HashMap, rc::Weak}; + +#[derive(Default)] +pub struct Scenegraph<'a> { + nodes: RefCell>>>, +} + +impl<'a> Scenegraph<'a> { + pub fn new() -> Self { + Default::default() + } + + pub fn add_node(&self, node: Weak>) { + let node_ref = node.upgrade(); + if node_ref.is_none() { + return; + } + self.nodes + .borrow_mut() + .insert(String::from(node_ref.unwrap().get_path()), node); + } + + pub fn remove_node(&self, node: Weak>) { + let node_ref = node.upgrade(); + if node_ref.is_none() { + return; + } + self.nodes.borrow_mut().remove(node_ref.unwrap().get_path()); + } + + pub fn get_node(&self, path: &str) -> Weak> { + self.nodes.borrow().get(path).cloned().unwrap_or_default() + } +} + +impl<'a> scenegraph::Scenegraph for Scenegraph<'a> { + fn send_signal(&self, path: &str, method: &str, data: &[u8]) -> Result<(), ScenegraphError> { + self.nodes + .borrow() + .get(path) + .ok_or(ScenegraphError::NodeNotFound)? + .upgrade() + .ok_or(ScenegraphError::NodeNotFound)? + .send_local_signal(method, data) + .map_err(|_| ScenegraphError::MethodNotFound) + } + fn execute_method( + &self, + path: &str, + method: &str, + data: &[u8], + ) -> Result, ScenegraphError> { + self.nodes + .borrow() + .get(path) + .ok_or(ScenegraphError::NodeNotFound)? + .upgrade() + .ok_or(ScenegraphError::NodeNotFound)? + .execute_local_method(method, data) + .map_err(|_| ScenegraphError::MethodNotFound) + } +} diff --git a/src/main.rs b/src/main.rs index f7ec431..ee213c4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,19 @@ mod core; +mod nodes; use self::core::eventloop::EventLoop; +use ctrlc; +use std::sync::mpsc::channel; + fn main() { + let (tx, rx) = channel(); + + ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel.")) + .expect("Error setting Ctrl-C handler"); + println!("Setting up Stardust socket..."); let event_loop = EventLoop::new(None).expect("Couldn't create server socket"); println!("Stardust socket created at {}", event_loop.socket_path); + + rx.recv().expect("Could not receive from channel."); } diff --git a/src/nodes/core.rs b/src/nodes/core.rs new file mode 100644 index 0000000..482211b --- /dev/null +++ b/src/nodes/core.rs @@ -0,0 +1,74 @@ +use crate::core::client::Client; +use anyhow::{anyhow, ensure, Result}; +use libstardustxr::messenger::Messenger; +use std::{ + collections::HashMap, + rc::{Rc, Weak}, + vec::Vec, +}; + +type Signal<'a> = dyn Fn(&[u8]) + 'a; +type Method<'a> = dyn Fn(&[u8]) -> Vec + 'a; + +pub struct Node<'a> { + path: String, + trailing_slash_pos: usize, + pub messenger: Weak>, + local_signals: HashMap>>, + local_methods: HashMap>>, +} + +impl<'a> Node<'a> { + pub fn get_name(&self) -> &str { + &self.path[self.trailing_slash_pos + 1..] + } + pub fn get_path(&self) -> &str { + self.path.as_str() + } + + pub fn from_path(client: &Client<'a>, path: &str) -> Result> { + ensure!(path.starts_with('/'), "Invalid path {}", path); + let node = Node { + path: path.to_string(), + trailing_slash_pos: path.rfind('/').ok_or(anyhow!("Invalid path {}", path))?, + messenger: client.get_weak_messenger(), + local_signals: HashMap::new(), + local_methods: HashMap::new(), + }; + let node_ref = Rc::new(node); + client.scenegraph.add_node(Rc::downgrade(&node_ref)); + Ok(node_ref) + } + + pub fn send_local_signal(&self, method: &str, data: &[u8]) -> Result<()> { + self.local_signals + .get(method) + .ok_or(anyhow!("Signal {} not found", method))?(data); + Ok(()) + } + pub fn execute_local_method(&self, method: &str, data: &[u8]) -> Result> { + Ok(self + .local_methods + .get(method) + .ok_or(anyhow!("Method {} not found", method))?(data)) + } + pub fn send_remote_signal(&self, method: &str, data: &[u8]) -> Result<()> { + self.messenger + .upgrade() + .ok_or(anyhow!("Invalid messenger"))? + .send_remote_signal(self.path.as_str(), method, data) + .map_err(|_| anyhow!("Unable to write in messenger")) + } + pub fn execute_remote_method( + &self, + method: &str, + data: &[u8], + callback: Box, + ) -> Result<()> { + self.messenger + .upgrade() + .ok_or(anyhow!("Invalid messenger"))? + .execute_remote_method(self.path.as_str(), method, data, callback) + .map_err(|_| anyhow!("Unable to write in messenger")) + } +} diff --git a/src/nodes/mod.rs b/src/nodes/mod.rs new file mode 100644 index 0000000..5a7ca06 --- /dev/null +++ b/src/nodes/mod.rs @@ -0,0 +1 @@ +pub mod core; diff --git a/src/nodes/spatial.rs b/src/nodes/spatial.rs new file mode 100644 index 0000000..e69de29