diff --git a/server/src/bin.rs b/server/src/bin.rs index a40bc6c5..1e9a62be 100644 --- a/server/src/bin.rs +++ b/server/src/bin.rs @@ -8,6 +8,8 @@ extern crate serde; extern crate serde_json; extern crate regex; +pub mod rbx_session; +pub mod id; pub mod web; pub mod core; pub mod project; diff --git a/server/src/id.rs b/server/src/id.rs new file mode 100644 index 00000000..a27a9d8c --- /dev/null +++ b/server/src/id.rs @@ -0,0 +1,21 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +/// A unique identifier, not guaranteed to be generated in any order. +pub type Id = usize; + +lazy_static! { + static ref LAST_ID: AtomicUsize = AtomicUsize::new(0); +} + +/// Generate a new ID, which has no defined ordering. +pub fn get_id() -> Id { + LAST_ID.fetch_add(1, Ordering::SeqCst) +} + +#[test] +fn it_gives_unique_numbers() { + let a = get_id(); + let b = get_id(); + + assert!(a != b); +} diff --git a/server/src/rbx_session.rs b/server/src/rbx_session.rs new file mode 100644 index 00000000..67cbc0ae --- /dev/null +++ b/server/src/rbx_session.rs @@ -0,0 +1,126 @@ +use std::path::{Path, PathBuf}; +use std::collections::HashMap; +use std::io::Read; +use std::fs::{self, File}; + +use id::{Id}; + +#[derive(Debug, Clone)] +struct FileRoute { + partition: String, + route: Vec, +} + +impl FileRoute { + pub fn to_path_buf(&self, partition_path: &Path) -> PathBuf { + let mut result = partition_path.to_path_buf(); + + for route_piece in &self.route { + result.push(route_piece); + } + + result + } + + pub fn extended_with(&self, pieces: &[&str]) -> FileRoute { + let mut result = self.clone(); + + for piece in pieces { + result.route.push(piece.to_string()); + } + + result + } +} + +enum FileItem { + File { + contents: String, + }, + Directory { + children: HashMap, + }, +} + +struct RbxInstance { + parent: Option, +} + +struct RbxSession { + partitions_path: HashMap, + partition_instances: HashMap, +} + +impl RbxSession { + fn load(&self) { + for (partition_name, partition_path) in &self.partitions_path { + } + } + + fn read(&self, route: &FileRoute) -> Result { + let partition_path = self.partitions_path.get(&route.partition) + .ok_or(())?; + let path = route.to_path_buf(partition_path); + + let metadata = fs::metadata(path) + .map_err(|_| ())?; + + if metadata.is_dir() { + self.read_directory(route) + } else if metadata.is_file() { + self.read_file(route) + } else { + Err(()) + } + } + + fn read_file(&self, route: &FileRoute) -> Result { + let partition_path = self.partitions_path.get(&route.partition) + .ok_or(())?; + let path = route.to_path_buf(partition_path); + + let mut file = File::open(path) + .map_err(|_| ())?; + + let mut contents = String::new(); + + file.read_to_string(&mut contents) + .map_err(|_| ())?; + + Ok(FileItem::File { + contents, + }) + } + + fn read_directory(&self, route: &FileRoute) -> Result { + let partition_path = self.partitions_path.get(&route.partition) + .ok_or(())?; + let path = route.to_path_buf(partition_path); + + let reader = fs::read_dir(path) + .map_err(|_| ())?; + + let mut children = HashMap::new(); + + for entry in reader { + let entry = entry + .map_err(|_| ())?; + + let path = entry.path(); + let name = path.file_name().unwrap().to_string_lossy().into_owned(); + + let child_route = route.extended_with(&[&name]); + + match self.read(&child_route) { + Ok(child_item) => { + children.insert(name, child_item); + }, + Err(_) => {}, + } + } + + Ok(FileItem::Directory { + children, + }) + } +}