From 2b808b12fe037fadaab56c34a8740d4567120036 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Sun, 19 Aug 2018 20:10:57 -0700 Subject: [PATCH] Rewrite progress --- plugin/rojo.json | 8 +- server/src/lib.rs | 5 +- server/src/message_session.rs | 33 ++++++-- server/src/rbx.rs | 66 ++++++++++++---- server/src/serve_session.rs | 37 +++++++++ server/src/web.rs | 142 +++++++++++++--------------------- 6 files changed, 172 insertions(+), 119 deletions(-) create mode 100644 server/src/serve_session.rs diff --git a/plugin/rojo.json b/plugin/rojo.json index 17f5548f..893fc744 100644 --- a/plugin/rojo.json +++ b/plugin/rojo.json @@ -18,14 +18,14 @@ "path": "modules/roact-rodux/lib", "target": "ReplicatedStorage.Rojo.modules.RoactRodux" }, - "modules/testez": { - "path": "modules/testez/lib", - "target": "ReplicatedStorage.TestEZ" - }, "modules/promise": { "path": "modules/promise/lib", "target": "ReplicatedStorage.Rojo.modules.Promise" }, + "modules/testez": { + "path": "modules/testez/lib", + "target": "ReplicatedStorage.TestEZ" + }, "tests": { "path": "tests", "target": "TestService" diff --git a/server/src/lib.rs b/server/src/lib.rs index cbb70e9b..31f9aef0 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -16,6 +16,7 @@ pub mod message_session; pub mod pathext; pub mod project; pub mod rbx; +pub mod roblox_studio; +pub mod serve_session; pub mod web; -pub mod web_util; -pub mod roblox_studio; \ No newline at end of file +pub mod web_util; \ No newline at end of file diff --git a/server/src/message_session.rs b/server/src/message_session.rs index c2821377..840b592a 100644 --- a/server/src/message_session.rs +++ b/server/src/message_session.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::sync::{mpsc, Arc, RwLock, Mutex}; +use std::sync::{mpsc, RwLock, Mutex}; use id::{Id, get_id}; @@ -11,17 +11,16 @@ pub enum Message { }, } -#[derive(Clone)] pub struct MessageSession { - pub messages: Arc>>, - pub message_listeners: Arc>>>, + messages: RwLock>, + message_listeners: Mutex>>, } impl MessageSession { pub fn new() -> MessageSession { MessageSession { - messages: Arc::new(RwLock::new(Vec::new())), - message_listeners: Arc::new(Mutex::new(HashMap::new())), + messages: RwLock::new(Vec::new()), + message_listeners: Mutex::new(HashMap::new()), } } @@ -58,7 +57,25 @@ impl MessageSession { } } - pub fn get_message_cursor(&self) -> i32 { - self.messages.read().unwrap().len() as i32 - 1 + pub fn get_message_cursor(&self) -> u32 { + self.messages.read().unwrap().len() as u32 + } + + pub fn get_messages_since(&self, cursor: u32) -> (u32, Vec) { + let messages = self.messages.read().unwrap(); + + let current_cursor = messages.len() as u32; + + // Cursor is out of bounds + if cursor > current_cursor { + return (current_cursor, Vec::new()); + } + + // No new messages + if cursor == current_cursor { + return (current_cursor, Vec::new()); + } + + (current_cursor, messages[(cursor as usize)..].to_vec()) } } \ No newline at end of file diff --git a/server/src/rbx.rs b/server/src/rbx.rs index fc759123..d3873cb7 100644 --- a/server/src/rbx.rs +++ b/server/src/rbx.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use id::Id; +use id::{Id, get_id}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[serde(tag = "type")] @@ -32,6 +32,12 @@ pub struct RbxInstance { parent: Option, } +impl RbxInstance { + pub fn get_id(&self) -> Id { + self.id + } +} + pub struct Descendants<'a> { tree: &'a RbxTree, ids_to_visit: Vec, @@ -65,12 +71,27 @@ impl<'a> Iterator for Descendants<'a> { pub struct RbxTree { instances: HashMap, + pub root_instance_id: Id, } impl RbxTree { pub fn new() -> RbxTree { + let root_instance_id = get_id(); + let root_instance = RbxInstance { + name: "game".to_string(), + class_name: "DataModel".to_string(), + properties: HashMap::new(), + id: root_instance_id, + children: Vec::new(), + parent: None, + }; + + let mut instances = HashMap::new(); + instances.insert(root_instance_id, root_instance); + RbxTree { - instances: HashMap::new(), + instances, + root_instance_id, } } @@ -82,18 +103,23 @@ impl RbxTree { &self.instances } - pub fn insert_instance(&mut self, instance: RbxInstance) { - if let Some(parent_id) = instance.parent { - match self.instances.get_mut(&parent_id) { - Some(mut parent) => { - if !parent.children.contains(&instance.id) { - parent.children.push(instance.id); + pub fn insert_instance(&mut self, mut instance: RbxInstance) { + match instance.parent { + Some(parent_id) => { + match self.instances.get_mut(&parent_id) { + Some(mut parent) => { + if !parent.children.contains(&instance.id) { + parent.children.push(instance.id); + } + }, + None => { + panic!("Tree consistency error, parent {} was not present in tree.", parent_id); } - }, - None => { - panic!("Tree consistency error, parent {} was not present in tree.", parent_id); } - } + }, + None => { + instance.parent = Some(self.root_instance_id); + }, } self.instances.insert(instance.id, instance); @@ -136,9 +162,19 @@ impl RbxTree { } pub fn iter_descendants<'a>(&'a self, id: Id) -> Descendants<'a> { - Descendants { - tree: self, - ids_to_visit: vec![id], + match self.get_instance(id) { + Some(instance) => { + Descendants { + tree: self, + ids_to_visit: instance.children.clone(), + } + }, + None => { + Descendants { + tree: self, + ids_to_visit: vec![], + } + }, } } } \ No newline at end of file diff --git a/server/src/serve_session.rs b/server/src/serve_session.rs new file mode 100644 index 00000000..30036b5c --- /dev/null +++ b/server/src/serve_session.rs @@ -0,0 +1,37 @@ +use std::{ + sync::Arc, +}; + +use ::{ + message_session::MessageSession, + rbx::RbxTree, + project::Project, +}; + +pub struct ServeSession { + project: Project, + messages: Arc, + tree: Arc, +} + +impl ServeSession { + pub fn new(project: Project) -> ServeSession { + ServeSession { + project, + messages: Arc::new(MessageSession::new()), + tree: Arc::new(RbxTree::new()), + } + } + + pub fn get_project(&self) -> &Project { + &self.project + } + + pub fn get_messages(&self) -> &MessageSession { + &self.messages + } + + pub fn get_tree(&self) -> &RbxTree { + &self.tree + } +} \ No newline at end of file diff --git a/server/src/web.rs b/server/src/web.rs index 5a665c4d..2eefc108 100644 --- a/server/src/web.rs +++ b/server/src/web.rs @@ -3,22 +3,16 @@ use std::collections::HashMap; use std::sync::{mpsc, RwLock, Arc}; use rouille::{self, Request, Response}; +use rand; -use id::Id; -use message_session::{MessageSession, Message}; -use project::Project; -use rbx::RbxInstance; -// use rbx_session::RbxSession; -// use session::Session; +use ::{ + id::Id, + message_session::{MessageSession, Message}, + project::Project, + rbx::RbxInstance, + serve_session::ServeSession, +}; -/// The set of configuration the web server needs to start. -pub struct WebConfig { - pub port: u64, - pub project: Project, - pub server_id: u64, - // pub rbx_session: Arc>, - pub message_session: MessageSession, -} #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -26,23 +20,14 @@ pub struct ServerInfoResponse<'a> { pub server_id: &'a str, pub server_version: &'a str, pub protocol_version: u64, - // pub partitions: HashMap>, -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ReadAllResponse<'a> { - pub server_id: &'a str, - pub message_cursor: i32, - // pub instances: Cow<'a, HashMap>, - // pub partition_instances: Cow<'a, HashMap>, + pub root_instance_id: Id, } #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct ReadResponse<'a> { pub server_id: &'a str, - pub message_cursor: i32, + pub message_cursor: u32, // pub instances: HashMap>, } @@ -50,133 +35,112 @@ pub struct ReadResponse<'a> { #[serde(rename_all = "camelCase")] pub struct SubscribeResponse<'a> { pub server_id: &'a str, - pub message_cursor: i32, + pub message_cursor: u32, pub messages: Cow<'a, [Message]>, } pub struct Server { - config: WebConfig, + session: Arc, server_version: &'static str, server_id: String, } impl Server { - pub fn new(config: WebConfig) -> Server { + pub fn new(session: Arc) -> Server { + let server_id = rand::random::().to_string(); + Server { + session: session, server_version: env!("CARGO_PKG_VERSION"), - server_id: config.server_id.to_string(), - config, + server_id, } } pub fn handle_request(&self, request: &Request) -> Response { router!(request, (GET) (/) => { - Response::text("Rojo up and running!") + Response::text("Rojo is up and running!") }, (GET) (/api/rojo) => { // Get a summary of information about the server. - // let mut partitions = HashMap::new(); - - // for partition in self.config.project.partitions.values() { - // partitions.insert(partition.name.clone(), partition.target.clone()); - // } - Response::json(&ServerInfoResponse { server_version: self.server_version, protocol_version: 2, server_id: &self.server_id, - // partitions: partitions, + root_instance_id: self.session.get_tree().root_instance_id, }) }, - (GET) (/api/subscribe/{ cursor: i32 }) => { + (GET) (/api/subscribe/{ cursor: u32 }) => { // Retrieve any messages past the given cursor index, and if // there weren't any, subscribe to receive any new messages. // Did the client miss any messages since the last subscribe? { - let messages = self.config.message_session.messages.read().unwrap(); + let (new_cursor, new_messages) = self.session.get_messages().get_messages_since(cursor); - if cursor > messages.len() as i32 { + if new_messages.len() > 0 { return Response::json(&SubscribeResponse { server_id: &self.server_id, messages: Cow::Borrowed(&[]), - message_cursor: messages.len() as i32 - 1, - }); - } - - if cursor < messages.len() as i32 - 1 { - let new_messages = &messages[(cursor + 1) as usize..]; - let new_cursor = cursor + new_messages.len() as i32; - - return Response::json(&SubscribeResponse { - server_id: &self.server_id, - messages: Cow::Borrowed(new_messages), message_cursor: new_cursor, - }); + }) } } let (tx, rx) = mpsc::channel(); - let sender_id = self.config.message_session.subscribe(tx); + let sender_id = self.session.get_messages().subscribe(tx); match rx.recv() { Ok(_) => (), Err(_) => return Response::text("error!").with_status_code(500), } - self.config.message_session.unsubscribe(sender_id); + self.session.get_messages().unsubscribe(sender_id); { - let messages = self.config.message_session.messages.read().unwrap(); - let new_messages = &messages[(cursor + 1) as usize..]; - let new_cursor = cursor + new_messages.len() as i32; + let (new_cursor, new_messages) = self.session.get_messages().get_messages_since(cursor); - Response::json(&SubscribeResponse { + return Response::json(&SubscribeResponse { server_id: &self.server_id, - messages: Cow::Borrowed(new_messages), + messages: Cow::Owned(new_messages), message_cursor: new_cursor, }) } }, - (GET) (/api/read_all) => { - // let rbx_session = self.config.rbx_session.read().unwrap(); - - let message_cursor = self.config.message_session.get_message_cursor(); - - Response::json(&ReadAllResponse { - server_id: &self.server_id, - message_cursor, - // instances: Cow::Borrowed(rbx_session.tree.get_all_instances()), - // partition_instances: Cow::Borrowed(&rbx_session.partition_instances), - }) - }, - (GET) (/api/read/{ id_list: String }) => { - let requested_ids = id_list + let requested_ids: Result, _> = id_list .split(",") - .map(str::parse::) - .collect::, _>>(); + .map(str::parse) + .collect(); let requested_ids = match requested_ids { - Ok(v) => v, + Ok(id) => id, Err(_) => return rouille::Response::text("Malformed ID list").with_status_code(400), }; - // let rbx_session = self.config.rbx_session.read().unwrap(); + let rbx_tree = self.session.get_tree(); - let message_cursor = self.config.message_session.get_message_cursor(); + let message_cursor = self.session.get_messages().get_message_cursor(); - // let mut instances = HashMap::new(); + let mut instances = HashMap::new(); - // for requested_id in &requested_ids { - // rbx_session.tree.get_instance_and_descendants(*requested_id, &mut instances); - // } + for &requested_id in &requested_ids { + match rbx_tree.get_instance(requested_id) { + Some(instance) => { + instances.insert(instance.get_id(), instance); + + for descendant in rbx_tree.iter_descendants(requested_id) { + instances.insert(descendant.get_id(), descendant); + } + }, + None => {}, + } + } Response::json(&ReadResponse { server_id: &self.server_id, @@ -188,13 +152,11 @@ impl Server { _ => Response::empty_404() ) } -} -/// Start the Rojo web server, taking over the current thread. -#[allow(unreachable_code)] -pub fn start(config: WebConfig) { - let address = format!("localhost:{}", config.port); - let server = Server::new(config); + // #[allow(unreachable_code)] + pub fn listen(self, port: u64) { + let address = format!("localhost:{}", port); - rouille::start_server(address, move |request| server.handle_request(request)); + rouille::start_server(address, move |request| self.handle_request(request)); + } } \ No newline at end of file