use crate::model::*; use crate::persistency::*; use crate::protocol::*; use crate::search::*; use std::path::Path; use std::sync::*; #[derive(Clone)] pub struct ServerState { data_store: Arc>, } impl ServerState { #[allow(dead_code)] 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 { fn new_connection(&mut self, con: &ClientConnection) { println!("{}: New Connection", con); } fn query(&mut self, con: &ClientConnection, query: &[String]) -> ProtocolResult> { let q = Query::parse(query) .map_err(|e| ProtocolError::BadRequest(format!("Invalid Query String: {:?}", e)))?; let data_store = self .data_store .read() .unwrap_or_else(|_| handle_broken_rwlock()); let mut textures = data_store.borrow_textures(); let found = q.search(&mut textures); println!("{}: Query '{:?}' found: {}", con, query, found.len()); Ok(found) } fn get_texture_by_id( &mut self, con: &ClientConnection, id: &str, ) -> ProtocolResult> { let data_store = self .data_store .read() .unwrap_or_else(|_| handle_broken_rwlock()); let found = data_store.texture_by_id(id); println!( "{}: Texture by id: '{}' found: {}", con, id, found.is_some() ); Ok(found) } fn get_texture_by_name( &mut self, con: &ClientConnection, name: &str, ) -> ProtocolResult> { let data_store = self .data_store .read() .unwrap_or_else(|_| handle_broken_rwlock()); let found = data_store.texture_by_name(name); println!( "{}: Texture by name: '{}' found: {}", con, name, found.is_some() ); Ok(found) } fn get_texture_file( &mut self, con: &ClientConnection, hash: Sha256, ) -> ProtocolResult> { let data_store = self .data_store .read() .unwrap_or_else(|_| handle_broken_rwlock()); let data = data_store.read_texture_file_by_hash(&hash); println!("{}: Texture File: '{}' found: {}", con, &hash, data.is_ok()); Ok(data?) } fn get_texture_preview( &mut self, con: &ClientConnection, hash: Sha256, format: TextureFormat, ) -> ProtocolResult> { let mut data_store = self .data_store .write() .unwrap_or_else(|_| handle_broken_rwlock()); let preview = data_store.get_texture_preview(&hash, format); println!( "{}: Texture Preview: '{}' found: {}", con, &hash, preview.is_ok() ); Ok(preview?) } fn replace_texture( &mut self, con: &ClientConnection, delete: Option, insert: Option, insert_texture_data: Option>, ) -> ProtocolResult { println!("{}: Replace Texture Request", con); let mut data_store = self .data_store .write() .unwrap_or_else(|_| handle_broken_rwlock()); 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(), )); } data_store.flush_metadata()?; Ok(ReplaceTextureStatus::Ok) } (Some(delete), None) => { if !data_store.delete(&delete) { return Err(ProtocolError::Conflict( "Delete Texture was modified!".to_string(), )); } data_store.flush_metadata()?; 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(), )); } data_store.flush_metadata()?; Ok(ReplaceTextureStatus::Ok) } (None, None) => Ok(ReplaceTextureStatus::Ok), } } fn disconnected(&mut self, con: &ClientConnection) { println!("{}: Disconnected", con); } } fn handle_broken_rwlock() -> ! { eprintln!("Panic while data_store lock was acquired."); eprintln!("Representation in memory could be invalid."); eprintln!("Can't recover. Please restart."); std::process::exit(13); }