diff --git a/server/texture-sync-server/src/model/mod.rs b/server/texture-sync-server/src/model/mod.rs index 1a7ded7..0f1851a 100644 --- a/server/texture-sync-server/src/model/mod.rs +++ b/server/texture-sync-server/src/model/mod.rs @@ -40,6 +40,10 @@ pub enum ProtocolError { impl From for ProtocolError { fn from(err: io::Error) -> Self { - ProtocolError::InternalServerError(err) + if err.kind() == io::ErrorKind::NotFound { + ProtocolError::FileNotFound("File Not Found!".to_string()) + } else { + ProtocolError::InternalServerError(err) + } } } diff --git a/server/texture-sync-server/src/persistency/mod.rs b/server/texture-sync-server/src/persistency/mod.rs index 1cada6d..052aa07 100644 --- a/server/texture-sync-server/src/persistency/mod.rs +++ b/server/texture-sync-server/src/persistency/mod.rs @@ -11,7 +11,7 @@ mod image_convert; mod metadata_file; mod search; -pub type TextureFileResult = Result>, TextureFileError>; +pub type TextureFileResult = Result, TextureFileError>; pub enum TextureFileError { NotFound, IoError(io::Error), @@ -39,7 +39,7 @@ pub struct DataStore { id_index: HashMap, name_index: HashMap, - preview_cache: HashMap<(TextureFormat, Sha256), Arc>>, + preview_cache: HashMap<(TextureFormat, Sha256), Vec>, } impl DataStore { @@ -75,7 +75,7 @@ impl DataStore { let metadata_file = metadata_file::MetadataFile::load(base_dir)?; for texture in metadata_file.textures.iter() { - match store.insert(texture.clone())? { + match store.insert(texture.clone()) { true => (), false => { panic!("inserting {:#?} failed !!!", texture); // TODO: What should be done? @@ -94,17 +94,17 @@ impl DataStore { self.name_index.get(id).cloned() } - pub fn insert(&mut self, texture: Texture) -> io::Result { + pub fn insert(&mut self, texture: Texture) -> bool { if self.id_index.contains_key(&texture.id) { - return Ok(false); + return false; } if self.name_index.contains_key(&texture.name) { - return Ok(false); + return false; } - if !self.is_texture_file_on_disk(&texture.texture_hash)? { - return Ok(false); + if !self.is_texture_file_on_disk(&texture.texture_hash) { + return false; } self.id_index.insert(texture.id.clone(), texture.clone()); @@ -112,7 +112,7 @@ impl DataStore { .insert(texture.name.clone(), texture.clone()); self.textures.insert(texture.clone()); - Ok(true) + true } /// returns true if successful @@ -132,28 +132,23 @@ impl DataStore { } /// Check if the texture, given by hash, physically exists on the file system. - pub fn is_texture_file_on_disk(&self, hash: &Sha256) -> io::Result { + pub fn is_texture_file_on_disk(&self, hash: &Sha256) -> bool { let file_path = self.texture_file_path(&hash); - Ok(file_path.is_file()) + file_path.is_file() } - // Todo: this return type looks wrong : ImageError can't happen - pub fn read_texture_file_by_hash(&mut self, hash: &Sha256) -> TextureFileResult { + pub fn read_texture_file_by_hash(&self, hash: &Sha256) -> io::Result> { use std::fs::*; use std::io::*; - if !(self.is_texture_file_on_disk(&hash)?) { - return Err(TextureFileError::NotFound); - } - let file_path = self.texture_file_path(&hash); let mut file = File::open(file_path)?; let mut buffer = Vec::new(); file.read_to_end(&mut buffer)?; - Ok(Arc::new(buffer)) + Ok(buffer) } pub fn store_texture_file(&mut self, data: &[u8]) -> io::Result<()> { diff --git a/server/texture-sync-server/src/server_state.rs b/server/texture-sync-server/src/server_state.rs index 24d41c0..4da94c1 100644 --- a/server/texture-sync-server/src/server_state.rs +++ b/server/texture-sync-server/src/server_state.rs @@ -4,13 +4,23 @@ #![allow(dead_code)] use crate::model::*; +use crate::persistency::*; use crate::protocol::*; -use std::sync::Arc; +use std::path::Path; +use std::sync::*; #[derive(Clone)] pub struct ServerState { - // ... + data_store: Arc>, +} + +impl ServerState { + pub fn new(storage_path: &Path) -> std::io::Result { + Ok(Self { + data_store: Arc::new(RwLock::new(DataStore::new(&storage_path)?)), + }) + } } impl ProtocolHandler for ServerState { @@ -19,15 +29,21 @@ impl ProtocolHandler for ServerState { } fn get_texture_by_id(&mut self, id: &str) -> ProtocolResult> { - unimplemented!() + let data_store = self.data_store.read().unwrap(); + Ok(data_store.texture_by_id(id)) } fn get_texture_by_name(&mut self, name: &str) -> ProtocolResult> { - unimplemented!() + let data_store = self.data_store.read().unwrap(); + Ok(data_store.texture_by_name(name)) } fn get_texture_file(&mut self, hash: Sha256) -> ProtocolResult> { - unimplemented!() + let data_store = self.data_store.read().unwrap(); + + let data = data_store.read_texture_file_by_hash(&hash)?; + + Ok(data) } fn get_texture_preview( @@ -35,7 +51,18 @@ impl ProtocolHandler for ServerState { hash: Sha256, format: TextureFormat, ) -> ProtocolResult> { - unimplemented!() + let mut data_store = self.data_store.write().unwrap(); + + match data_store.get_texture_preview(&hash, format) { + Ok(data) => Ok(data), + Err(TextureFileError::NotFound) => Err(ProtocolError::FileNotFound( + "Texture not found!".to_string(), + )), + Err(TextureFileError::ImageError(_)) => Err(ProtocolError::FileNotFound( + "Didn't Find valid Texture File".to_string(), + )), + Err(TextureFileError::IoError(err)) => Err(ProtocolError::InternalServerError(err)), + } } fn replace_texture( @@ -44,7 +71,63 @@ impl ProtocolHandler for ServerState { insert: Option, insert_texture_data: Option>, ) -> ProtocolResult { - // NOTE: must also check if insert_texture_data fits sha256! - unimplemented!() + let mut data_store = self.data_store.write().unwrap(); + + match insert_texture_data { + Some(data) => { + data_store.store_texture_file(&data)?; + } + None => (), + } + + match (delete, insert) { + (Some(delete), Some(insert)) => { + if !data_store.is_texture_file_on_disk(&insert.texture_hash) { + return Ok(ReplaceTextureStatus::NeedTextureData(insert.texture_hash)); + } + + if !data_store.delete(&delete) { + return Err(ProtocolError::Conflict( + "Delete Texture was modified!".to_string(), + )); + } + + if !data_store.insert(insert) { + // undo delete + // panics if texture file is delete during delete and reinsert. + // unlikely to happen. + assert!(data_store.insert(delete)); + return Err(ProtocolError::Conflict( + "Name or Id already taken.".to_string(), + )); + } + + Ok(ReplaceTextureStatus::Ok) + } + (Some(delete), None) => { + if !data_store.delete(&delete) { + return Err(ProtocolError::Conflict( + "Delete Texture was modified!".to_string(), + )); + } + + Ok(ReplaceTextureStatus::Ok) + } + (None, Some(insert)) => { + if !data_store.is_texture_file_on_disk(&insert.texture_hash) { + return Ok(ReplaceTextureStatus::NeedTextureData(insert.texture_hash)); + } + + if !data_store.insert(insert) { + // undo delete + return Err(ProtocolError::Conflict( + "Name or Id already taken.".to_string(), + )); + } + + Ok(ReplaceTextureStatus::Ok) + } + (None, None) => Ok(ReplaceTextureStatus::Ok), + } } }