RbxSession refactoring stuff

This commit is contained in:
Lucien Greathouse
2018-11-16 23:14:32 -08:00
parent 9ad0eabb85
commit e09d23d6c2
5 changed files with 242 additions and 139 deletions

View File

@@ -18,6 +18,7 @@ pub mod commands;
pub mod message_queue; pub mod message_queue;
pub mod pathext; pub mod pathext;
pub mod project; pub mod project;
pub mod rbx_session;
pub mod session; pub mod session;
pub mod session_id; pub mod session_id;
pub mod vfs; pub mod vfs;

View File

@@ -12,7 +12,7 @@ pub static PROJECT_FILENAME: &'static str = "roblox-project.json";
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)] #[serde(untagged)]
enum SourceProjectNode { enum SourceProjectNode {
Regular { Instance {
#[serde(rename = "$className")] #[serde(rename = "$className")]
class_name: String, class_name: String,
@@ -31,17 +31,17 @@ enum SourceProjectNode {
impl SourceProjectNode { impl SourceProjectNode {
pub fn into_project_node(self, project_file_location: &Path) -> ProjectNode { pub fn into_project_node(self, project_file_location: &Path) -> ProjectNode {
match self { match self {
SourceProjectNode::Regular { class_name, mut children } => { SourceProjectNode::Instance { class_name, mut children } => {
let mut new_children = HashMap::new(); let mut new_children = HashMap::new();
for (node_name, node) in children.drain() { for (node_name, node) in children.drain() {
new_children.insert(node_name, node.into_project_node(project_file_location)); new_children.insert(node_name, node.into_project_node(project_file_location));
} }
ProjectNode::Regular { ProjectNode::Instance(InstanceProjectNode {
class_name, class_name,
children: new_children, children: new_children,
} })
}, },
SourceProjectNode::SyncPoint { path: source_path } => { SourceProjectNode::SyncPoint { path: source_path } => {
let path = if Path::new(&source_path).is_absolute() { let path = if Path::new(&source_path).is_absolute() {
@@ -51,9 +51,9 @@ impl SourceProjectNode {
project_folder_location.join(source_path) project_folder_location.join(source_path)
}; };
ProjectNode::SyncPoint { ProjectNode::SyncPoint(SyncPointProjectNode {
path, path,
} })
}, },
} }
} }
@@ -139,15 +139,21 @@ impl fmt::Display for ProjectSaveError {
#[derive(Debug)] #[derive(Debug)]
pub enum ProjectNode { pub enum ProjectNode {
Regular { Instance(InstanceProjectNode),
class_name: String, SyncPoint(SyncPointProjectNode),
children: HashMap<String, ProjectNode>, }
// properties: HashMap<String, RbxValue>,
// ignore_unknown: bool, #[derive(Debug)]
}, pub struct InstanceProjectNode {
SyncPoint { pub class_name: String,
path: PathBuf, pub children: HashMap<String, ProjectNode>,
}, // properties: HashMap<String, RbxValue>,
// ignore_unknown: bool,
}
#[derive(Debug)]
pub struct SyncPointProjectNode {
pub path: PathBuf,
} }
#[derive(Debug)] #[derive(Debug)]

160
server/src/rbx_session.rs Normal file
View File

@@ -0,0 +1,160 @@
use std::{
collections::HashMap,
path::{Path, PathBuf},
sync::{Arc, Mutex},
str,
};
use rbx_tree::{RbxTree, RbxId, RbxInstance, RbxValue};
use crate::{
project::{Project, ProjectNode, InstanceProjectNode},
message_queue::MessageQueue,
vfs::{Vfs, VfsItem},
};
pub struct RbxSession {
tree: RbxTree,
paths_to_ids: HashMap<PathBuf, RbxId>,
message_queue: Arc<MessageQueue>,
vfs: Arc<Mutex<Vfs>>,
project: Arc<Project>,
}
impl RbxSession {
pub fn new(project: Arc<Project>, vfs: Arc<Mutex<Vfs>>, message_queue: Arc<MessageQueue>) -> RbxSession {
let (tree, paths_to_ids) = {
let temp_vfs = vfs.lock().unwrap();
construct_initial_tree(&project, &temp_vfs)
};
{
use serde_json;
println!("{}", serde_json::to_string(&tree).unwrap());
}
RbxSession {
tree,
paths_to_ids,
message_queue,
vfs,
project,
}
}
pub fn path_created_or_updated(&mut self, path: &Path) {
println!("Path changed: {}", path.display());
}
pub fn path_removed(&mut self, path: &Path) {
println!("Path removed: {}", path.display());
}
pub fn path_renamed(&mut self, from_path: &Path, to_path: &Path) {
println!("Path renamed from {} to {}", from_path.display(), to_path.display());
}
pub fn get_tree(&self) -> &RbxTree {
&self.tree
}
}
fn construct_initial_tree(
project: &Project,
vfs: &Vfs,
) -> (RbxTree, HashMap<PathBuf, RbxId>) {
let mut paths_to_ids = HashMap::new();
let mut tree = RbxTree::new(RbxInstance {
name: "this isn't supposed to be here".to_string(),
class_name: "ahhh, help me".to_string(),
properties: HashMap::new(),
});
let root_id = tree.get_root_id();
construct_initial_tree_node(&mut tree, vfs, &mut paths_to_ids, root_id, "<<<ROOT>>>", &project.tree);
(tree, paths_to_ids)
}
fn construct_initial_tree_node(
tree: &mut RbxTree,
vfs: &Vfs,
paths_to_ids: &mut HashMap<PathBuf, RbxId>,
parent_instance_id: RbxId,
instance_name: &str,
project_node: &ProjectNode,
) {
match project_node {
ProjectNode::Instance(node) => {
construct_instance_node(tree, vfs, paths_to_ids, parent_instance_id, instance_name, node);
},
ProjectNode::SyncPoint(node) => {
construct_sync_point_node(tree, vfs, paths_to_ids, parent_instance_id, instance_name, &node.path);
},
}
}
fn construct_instance_node(
tree: &mut RbxTree,
vfs: &Vfs,
paths_to_ids: &mut HashMap<PathBuf, RbxId>,
parent_instance_id: RbxId,
instance_name: &str,
project_node: &InstanceProjectNode,
) {
let instance = RbxInstance {
class_name: project_node.class_name.clone(),
name: instance_name.to_string(),
properties: HashMap::new(),
};
let id = tree.insert_instance(instance, parent_instance_id);
for (child_name, child_project_node) in &project_node.children {
construct_initial_tree_node(tree, vfs, paths_to_ids, id, child_name, child_project_node);
}
}
fn construct_sync_point_node(
tree: &mut RbxTree,
vfs: &Vfs,
paths_to_ids: &mut HashMap<PathBuf, RbxId>,
parent_instance_id: RbxId,
instance_name: &str,
file_path: &Path,
) {
match vfs.get(&file_path) {
Some(VfsItem::File(file)) => {
let contents = str::from_utf8(vfs.get_contents(&file.path).unwrap()).unwrap();
let mut properties = HashMap::new();
properties.insert("Source".to_string(), RbxValue::String { value: contents.to_string() });
let instance = RbxInstance {
class_name: "ModuleScript".to_string(),
name: instance_name.to_string(),
properties,
};
let id = tree.insert_instance(instance, parent_instance_id);
paths_to_ids.insert(file.path.clone(), id);
},
Some(VfsItem::Directory(directory)) => {
let instance = RbxInstance {
class_name: "Folder".to_string(),
name: instance_name.to_string(),
properties: HashMap::new(),
};
let id = tree.insert_instance(instance, parent_instance_id);
paths_to_ids.insert(directory.path.clone(), id);
for child_path in &directory.children {
let child_instance_name = child_path.file_name().unwrap().to_str().unwrap();
construct_sync_point_node(tree, vfs, paths_to_ids, id, child_instance_name, child_path);
}
},
None => panic!("Couldn't read {} from disk", file_path.display()),
}
}

View File

@@ -1,15 +1,10 @@
use std::{ use std::{
collections::HashMap, sync::{Arc, Mutex, mpsc},
sync::{Arc, RwLock, Mutex, mpsc},
path::{Path, PathBuf},
thread, thread,
io, io,
time::Duration, time::Duration,
str,
}; };
use serde_json;
use notify::{ use notify::{
self, self,
DebouncedEvent, DebouncedEvent,
@@ -18,142 +13,66 @@ use notify::{
Watcher, Watcher,
}; };
use rbx_tree::{RbxId, RbxTree, RbxInstance, RbxValue};
use crate::{ use crate::{
message_queue::MessageQueue, message_queue::MessageQueue,
project::{Project, ProjectNode}, project::{Project, ProjectNode},
vfs::{Vfs, VfsItem}, vfs::Vfs,
session_id::SessionId, session_id::SessionId,
rbx_session::RbxSession,
}; };
const WATCH_TIMEOUT_MS: u64 = 100; const WATCH_TIMEOUT_MS: u64 = 100;
pub struct Session { pub struct Session {
project: Project, project: Arc<Project>,
pub session_id: SessionId, pub session_id: SessionId,
pub message_queue: Arc<MessageQueue>, pub message_queue: Arc<MessageQueue>,
pub tree: Arc<RwLock<RbxTree>>, pub rbx_session: Arc<Mutex<RbxSession>>,
paths_to_ids: HashMap<PathBuf, RbxId>,
vfs: Arc<Mutex<Vfs>>, vfs: Arc<Mutex<Vfs>>,
watchers: Vec<RecommendedWatcher>, watchers: Vec<RecommendedWatcher>,
} }
fn add_sync_points(vfs: &mut Vfs, project_node: &ProjectNode) -> io::Result<()> { fn add_sync_points(vfs: &mut Vfs, project_node: &ProjectNode) -> io::Result<()> {
match project_node { match project_node {
ProjectNode::Regular { children, .. } => { ProjectNode::Instance(node) => {
for child in children.values() { for child in node.children.values() {
add_sync_points(vfs, child)?; add_sync_points(vfs, child)?;
} }
}, },
ProjectNode::SyncPoint { path } => { ProjectNode::SyncPoint(node) => {
vfs.add_root(path)?; vfs.add_root(&node.path)?;
}, },
} }
Ok(()) Ok(())
} }
fn read_sync_to_rbx(
tree: &mut RbxTree,
vfs: &Vfs,
paths_to_ids: &mut HashMap<PathBuf, RbxId>,
parent_node_id: RbxId,
project_node_name: &str,
path: &Path
) {
match vfs.get(path) {
Some(VfsItem::File(file)) => {
let contents = str::from_utf8(vfs.get_contents(&file.path).unwrap()).unwrap();
let mut properties = HashMap::new();
properties.insert("Source".to_string(), RbxValue::String { value: contents.to_string() });
let instance = RbxInstance {
class_name: "ModuleScript".to_string(),
name: project_node_name.to_string(),
properties,
};
let id = tree.insert_instance(instance, parent_node_id);
paths_to_ids.insert(path.to_path_buf(), id);
},
Some(VfsItem::Directory(directory)) => {
let instance = RbxInstance {
class_name: "Folder".to_string(),
name: project_node_name.to_string(),
properties: HashMap::new(),
};
let id = tree.insert_instance(instance, parent_node_id);
paths_to_ids.insert(path.to_path_buf(), id);
for child_path in &directory.children {
let child_name = child_path.file_name().unwrap().to_str().unwrap();
read_sync_to_rbx(tree, vfs, paths_to_ids, id, child_name, child_path);
}
},
None => panic!("Couldn't read {} from disk", path.display()),
}
}
fn read_to_rbx(
tree: &mut RbxTree,
vfs: &Vfs,
paths_to_ids: &mut HashMap<PathBuf, RbxId>,
parent_node_id: RbxId,
project_node_name: &str,
project_node: &ProjectNode
) {
match project_node {
ProjectNode::Regular { children, class_name, .. } => {
let instance = RbxInstance {
class_name: class_name.clone(),
name: project_node_name.to_string(),
properties: HashMap::new(),
};
let id = tree.insert_instance(instance, parent_node_id);
for (child_name, child_project_node) in children {
read_to_rbx(tree, vfs, paths_to_ids, id, child_name, child_project_node);
}
},
ProjectNode::SyncPoint { path } => {
read_sync_to_rbx(tree, vfs, paths_to_ids, parent_node_id, project_node_name, path);
},
}
}
impl Session { impl Session {
pub fn new(project: Project) -> io::Result<Session> { pub fn new(project: Project) -> io::Result<Session> {
let mut vfs = Vfs::new(); let project = Arc::new(project);
let message_queue = Arc::new(MessageQueue::new());
let vfs = Arc::new(Mutex::new(Vfs::new()));
let (change_tx, change_rx) = mpsc::channel(); {
let mut vfs = vfs.lock().unwrap();
add_sync_points(&mut vfs, &project.tree)
.expect("Could not add sync points when starting new Rojo session");
}
add_sync_points(&mut vfs, &project.tree) let rbx_session = Arc::new(Mutex::new(RbxSession::new(
.expect("Could not add sync points when starting new Rojo session"); Arc::clone(&project),
Arc::clone(&vfs),
Arc::clone(&message_queue),
)));
let mut tree = RbxTree::new(RbxInstance {
name: "ahhhh".to_string(),
class_name: "ahhh help me".to_string(),
properties: HashMap::new(),
});
let mut paths_to_ids = HashMap::new();
let root_id = tree.get_root_id();
read_to_rbx(&mut tree, &vfs, &mut paths_to_ids, root_id, "root", &project.tree);
println!("tree:\n{}", serde_json::to_string(&tree).unwrap());
let vfs = Arc::new(Mutex::new(vfs));
let mut watchers = Vec::new(); let mut watchers = Vec::new();
{ {
let vfs_temp = vfs.lock().unwrap(); let vfs_temp = vfs.lock().unwrap();
for root in vfs_temp.get_roots() { for root in vfs_temp.get_roots() {
println!("Watching {}", root.display());
let (watch_tx, watch_rx) = mpsc::channel(); let (watch_tx, watch_rx) = mpsc::channel();
let mut watcher = notify::watcher(watch_tx, Duration::from_millis(WATCH_TIMEOUT_MS)).unwrap(); let mut watcher = notify::watcher(watch_tx, Duration::from_millis(WATCH_TIMEOUT_MS)).unwrap();
@@ -163,8 +82,8 @@ impl Session {
watchers.push(watcher); watchers.push(watcher);
let change_tx = change_tx.clone();
let vfs = Arc::clone(&vfs); let vfs = Arc::clone(&vfs);
let rbx_session = Arc::clone(&rbx_session);
thread::spawn(move || { thread::spawn(move || {
loop { loop {
@@ -172,23 +91,40 @@ impl Session {
Ok(event) => { Ok(event) => {
match event { match event {
DebouncedEvent::Create(path) | DebouncedEvent::Write(path) => { DebouncedEvent::Create(path) | DebouncedEvent::Write(path) => {
let mut vfs = vfs.lock().unwrap(); {
vfs.add_or_update(&path).unwrap(); let mut vfs = vfs.lock().unwrap();
change_tx.send(path.clone()).unwrap(); vfs.add_or_update(&path).unwrap();
}
{
let mut rbx_session = rbx_session.lock().unwrap();
rbx_session.path_created_or_updated(&path);
}
}, },
DebouncedEvent::Remove(path) => { DebouncedEvent::Remove(path) => {
let mut vfs = vfs.lock().unwrap(); {
vfs.remove(&path); let mut vfs = vfs.lock().unwrap();
change_tx.send(path.clone()).unwrap(); vfs.remove(&path);
}
{
let mut rbx_session = rbx_session.lock().unwrap();
rbx_session.path_removed(&path);
}
}, },
DebouncedEvent::Rename(from_path, to_path) => { DebouncedEvent::Rename(from_path, to_path) => {
let mut vfs = vfs.lock().unwrap(); {
vfs.remove(&from_path); let mut vfs = vfs.lock().unwrap();
vfs.add_or_update(&to_path).unwrap(); vfs.remove(&from_path);
change_tx.send(from_path.clone()).unwrap(); vfs.add_or_update(&to_path).unwrap();
change_tx.send(to_path.clone()).unwrap(); }
{
let mut rbx_session = rbx_session.lock().unwrap();
rbx_session.path_renamed(&from_path, &to_path);
}
}, },
_ => continue, _ => {},
}; };
}, },
Err(_) => break, Err(_) => break,
@@ -199,17 +135,15 @@ impl Session {
} }
} }
let message_queue = Arc::new(MessageQueue::new());
let session_id = SessionId::new(); let session_id = SessionId::new();
Ok(Session { Ok(Session {
session_id, session_id,
paths_to_ids, rbx_session,
project, project,
message_queue, message_queue,
tree: Arc::new(RwLock::new(tree)),
vfs, vfs,
watchers: Vec::new(), watchers,
}) })
} }

View File

@@ -63,7 +63,8 @@ impl Server {
(GET) (/api/rojo) => { (GET) (/api/rojo) => {
// Get a summary of information about the server. // Get a summary of information about the server.
let tree = self.session.tree.read().unwrap(); let rbx_session = self.session.rbx_session.lock().unwrap();
let tree = rbx_session.get_tree();
Response::json(&ServerInfoResponse { Response::json(&ServerInfoResponse {
server_version: self.server_version, server_version: self.server_version,
@@ -127,7 +128,8 @@ impl Server {
None => return rouille::Response::text("Malformed ID list").with_status_code(400), None => return rouille::Response::text("Malformed ID list").with_status_code(400),
}; };
let tree = self.session.tree.read().unwrap(); let rbx_session = self.session.rbx_session.lock().unwrap();
let tree = rbx_session.get_tree();
let message_cursor = message_queue.get_message_cursor(); let message_cursor = message_queue.get_message_cursor();