Rewrite progress

This commit is contained in:
Lucien Greathouse 2018-08-19 20:10:57 -07:00
parent 4df3f7f1ff
commit 2b808b12fe
6 changed files with 172 additions and 119 deletions

View file

@ -18,14 +18,14 @@
"path": "modules/roact-rodux/lib", "path": "modules/roact-rodux/lib",
"target": "ReplicatedStorage.Rojo.modules.RoactRodux" "target": "ReplicatedStorage.Rojo.modules.RoactRodux"
}, },
"modules/testez": {
"path": "modules/testez/lib",
"target": "ReplicatedStorage.TestEZ"
},
"modules/promise": { "modules/promise": {
"path": "modules/promise/lib", "path": "modules/promise/lib",
"target": "ReplicatedStorage.Rojo.modules.Promise" "target": "ReplicatedStorage.Rojo.modules.Promise"
}, },
"modules/testez": {
"path": "modules/testez/lib",
"target": "ReplicatedStorage.TestEZ"
},
"tests": { "tests": {
"path": "tests", "path": "tests",
"target": "TestService" "target": "TestService"

View file

@ -16,6 +16,7 @@ pub mod message_session;
pub mod pathext; pub mod pathext;
pub mod project; pub mod project;
pub mod rbx; pub mod rbx;
pub mod roblox_studio;
pub mod serve_session;
pub mod web; pub mod web;
pub mod web_util; pub mod web_util;
pub mod roblox_studio;

View file

@ -1,5 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{mpsc, Arc, RwLock, Mutex}; use std::sync::{mpsc, RwLock, Mutex};
use id::{Id, get_id}; use id::{Id, get_id};
@ -11,17 +11,16 @@ pub enum Message {
}, },
} }
#[derive(Clone)]
pub struct MessageSession { pub struct MessageSession {
pub messages: Arc<RwLock<Vec<Message>>>, messages: RwLock<Vec<Message>>,
pub message_listeners: Arc<Mutex<HashMap<Id, mpsc::Sender<()>>>>, message_listeners: Mutex<HashMap<Id, mpsc::Sender<()>>>,
} }
impl MessageSession { impl MessageSession {
pub fn new() -> MessageSession { pub fn new() -> MessageSession {
MessageSession { MessageSession {
messages: Arc::new(RwLock::new(Vec::new())), messages: RwLock::new(Vec::new()),
message_listeners: Arc::new(Mutex::new(HashMap::new())), message_listeners: Mutex::new(HashMap::new()),
} }
} }
@ -58,7 +57,25 @@ impl MessageSession {
} }
} }
pub fn get_message_cursor(&self) -> i32 { pub fn get_message_cursor(&self) -> u32 {
self.messages.read().unwrap().len() as i32 - 1 self.messages.read().unwrap().len() as u32
}
pub fn get_messages_since(&self, cursor: u32) -> (u32, Vec<Message>) {
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())
} }
} }

View file

@ -1,6 +1,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use id::Id; use id::{Id, get_id};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
@ -32,6 +32,12 @@ pub struct RbxInstance {
parent: Option<Id>, parent: Option<Id>,
} }
impl RbxInstance {
pub fn get_id(&self) -> Id {
self.id
}
}
pub struct Descendants<'a> { pub struct Descendants<'a> {
tree: &'a RbxTree, tree: &'a RbxTree,
ids_to_visit: Vec<Id>, ids_to_visit: Vec<Id>,
@ -65,12 +71,27 @@ impl<'a> Iterator for Descendants<'a> {
pub struct RbxTree { pub struct RbxTree {
instances: HashMap<Id, RbxInstance>, instances: HashMap<Id, RbxInstance>,
pub root_instance_id: Id,
} }
impl RbxTree { impl RbxTree {
pub fn new() -> 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 { RbxTree {
instances: HashMap::new(), instances,
root_instance_id,
} }
} }
@ -82,8 +103,9 @@ impl RbxTree {
&self.instances &self.instances
} }
pub fn insert_instance(&mut self, instance: RbxInstance) { pub fn insert_instance(&mut self, mut instance: RbxInstance) {
if let Some(parent_id) = instance.parent { match instance.parent {
Some(parent_id) => {
match self.instances.get_mut(&parent_id) { match self.instances.get_mut(&parent_id) {
Some(mut parent) => { Some(mut parent) => {
if !parent.children.contains(&instance.id) { if !parent.children.contains(&instance.id) {
@ -94,6 +116,10 @@ impl RbxTree {
panic!("Tree consistency error, parent {} was not present in tree.", parent_id); 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); self.instances.insert(instance.id, instance);
@ -136,9 +162,19 @@ impl RbxTree {
} }
pub fn iter_descendants<'a>(&'a self, id: Id) -> Descendants<'a> { pub fn iter_descendants<'a>(&'a self, id: Id) -> Descendants<'a> {
match self.get_instance(id) {
Some(instance) => {
Descendants { Descendants {
tree: self, tree: self,
ids_to_visit: vec![id], ids_to_visit: instance.children.clone(),
}
},
None => {
Descendants {
tree: self,
ids_to_visit: vec![],
}
},
} }
} }
} }

View file

@ -0,0 +1,37 @@
use std::{
sync::Arc,
};
use ::{
message_session::MessageSession,
rbx::RbxTree,
project::Project,
};
pub struct ServeSession {
project: Project,
messages: Arc<MessageSession>,
tree: Arc<RbxTree>,
}
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
}
}

View file

@ -3,22 +3,16 @@ use std::collections::HashMap;
use std::sync::{mpsc, RwLock, Arc}; use std::sync::{mpsc, RwLock, Arc};
use rouille::{self, Request, Response}; use rouille::{self, Request, Response};
use rand;
use id::Id; use ::{
use message_session::{MessageSession, Message}; id::Id,
use project::Project; message_session::{MessageSession, Message},
use rbx::RbxInstance; project::Project,
// use rbx_session::RbxSession; rbx::RbxInstance,
// use session::Session; 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<RwLock<RbxSession>>,
pub message_session: MessageSession,
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
@ -26,23 +20,14 @@ pub struct ServerInfoResponse<'a> {
pub server_id: &'a str, pub server_id: &'a str,
pub server_version: &'a str, pub server_version: &'a str,
pub protocol_version: u64, pub protocol_version: u64,
// pub partitions: HashMap<String, Vec<String>>, pub root_instance_id: Id,
}
#[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<Id, RbxInstance>>,
// pub partition_instances: Cow<'a, HashMap<String, Id>>,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct ReadResponse<'a> { pub struct ReadResponse<'a> {
pub server_id: &'a str, pub server_id: &'a str,
pub message_cursor: i32, pub message_cursor: u32,
// pub instances: HashMap<Id, Cow<'a, RbxInstance>>, // pub instances: HashMap<Id, Cow<'a, RbxInstance>>,
} }
@ -50,133 +35,112 @@ pub struct ReadResponse<'a> {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct SubscribeResponse<'a> { pub struct SubscribeResponse<'a> {
pub server_id: &'a str, pub server_id: &'a str,
pub message_cursor: i32, pub message_cursor: u32,
pub messages: Cow<'a, [Message]>, pub messages: Cow<'a, [Message]>,
} }
pub struct Server { pub struct Server {
config: WebConfig, session: Arc<ServeSession>,
server_version: &'static str, server_version: &'static str,
server_id: String, server_id: String,
} }
impl Server { impl Server {
pub fn new(config: WebConfig) -> Server { pub fn new(session: Arc<ServeSession>) -> Server {
let server_id = rand::random::<u64>().to_string();
Server { Server {
session: session,
server_version: env!("CARGO_PKG_VERSION"), server_version: env!("CARGO_PKG_VERSION"),
server_id: config.server_id.to_string(), server_id,
config,
} }
} }
pub fn handle_request(&self, request: &Request) -> Response { pub fn handle_request(&self, request: &Request) -> Response {
router!(request, router!(request,
(GET) (/) => { (GET) (/) => {
Response::text("Rojo up and running!") Response::text("Rojo is up and running!")
}, },
(GET) (/api/rojo) => { (GET) (/api/rojo) => {
// Get a summary of information about the server. // 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 { Response::json(&ServerInfoResponse {
server_version: self.server_version, server_version: self.server_version,
protocol_version: 2, protocol_version: 2,
server_id: &self.server_id, 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 // Retrieve any messages past the given cursor index, and if
// there weren't any, subscribe to receive any new messages. // there weren't any, subscribe to receive any new messages.
// Did the client miss any messages since the last subscribe? // 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 { return Response::json(&SubscribeResponse {
server_id: &self.server_id, server_id: &self.server_id,
messages: Cow::Borrowed(&[]), 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, message_cursor: new_cursor,
}); })
} }
} }
let (tx, rx) = mpsc::channel(); 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() { match rx.recv() {
Ok(_) => (), Ok(_) => (),
Err(_) => return Response::text("error!").with_status_code(500), 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_cursor, new_messages) = self.session.get_messages().get_messages_since(cursor);
let new_messages = &messages[(cursor + 1) as usize..];
let new_cursor = cursor + new_messages.len() as i32;
Response::json(&SubscribeResponse { return Response::json(&SubscribeResponse {
server_id: &self.server_id, server_id: &self.server_id,
messages: Cow::Borrowed(new_messages), messages: Cow::Owned(new_messages),
message_cursor: new_cursor, 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 }) => { (GET) (/api/read/{ id_list: String }) => {
let requested_ids = id_list let requested_ids: Result<Vec<Id>, _> = id_list
.split(",") .split(",")
.map(str::parse::<Id>) .map(str::parse)
.collect::<Result<Vec<Id>, _>>(); .collect();
let requested_ids = match requested_ids { let requested_ids = match requested_ids {
Ok(v) => v, Ok(id) => id,
Err(_) => return rouille::Response::text("Malformed ID list").with_status_code(400), 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 { for &requested_id in &requested_ids {
// rbx_session.tree.get_instance_and_descendants(*requested_id, &mut instances); 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 { Response::json(&ReadResponse {
server_id: &self.server_id, server_id: &self.server_id,
@ -188,13 +152,11 @@ impl Server {
_ => Response::empty_404() _ => Response::empty_404()
) )
} }
}
/// Start the Rojo web server, taking over the current thread. // #[allow(unreachable_code)]
#[allow(unreachable_code)] pub fn listen(self, port: u64) {
pub fn start(config: WebConfig) { let address = format!("localhost:{}", port);
let address = format!("localhost:{}", config.port);
let server = Server::new(config);
rouille::start_server(address, move |request| server.handle_request(request)); rouille::start_server(address, move |request| self.handle_request(request));
}
} }