mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-25 13:24:08 +00:00
Rewrite progress
This commit is contained in:
parent
4df3f7f1ff
commit
2b808b12fe
6 changed files with 172 additions and 119 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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;
|
|
||||||
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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![],
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
37
server/src/serve_session.rs
Normal file
37
server/src/serve_session.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue