219 lines
6.0 KiB
Rust
219 lines
6.0 KiB
Rust
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<RwLock<DataStore>>,
|
|
}
|
|
|
|
impl ServerState {
|
|
#[allow(dead_code)]
|
|
pub fn new(storage_path: &Path) -> std::io::Result<Self> {
|
|
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<Vec<Texture>> {
|
|
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<Option<Texture>> {
|
|
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<Option<Texture>> {
|
|
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<Vec<u8>> {
|
|
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<Vec<u8>> {
|
|
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<Texture>,
|
|
insert: Option<Texture>,
|
|
insert_texture_data: Option<Vec<u8>>,
|
|
) -> ProtocolResult<ReplaceTextureStatus> {
|
|
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);
|
|
}
|