Implement more persistency logic

This commit is contained in:
Lukas Fürderer 2019-05-03 11:19:34 +02:00
parent f5dcd52454
commit 96c2864a07
4 changed files with 84 additions and 33 deletions

View File

@ -3,6 +3,8 @@
#![allow(unused_variables)] #![allow(unused_variables)]
#![allow(dead_code)] #![allow(dead_code)]
use std::io;
mod sha256; mod sha256;
pub use sha256::Sha256; pub use sha256::Sha256;
@ -18,3 +20,14 @@ pub struct Texture {
pub resolution: (usize, usize), pub resolution: (usize, usize),
pub texture_hash: Sha256, pub texture_hash: Sha256,
} }
pub enum ReplaceTextureStatus {
// Done.
Ok,
// Call Again With Texture Binary
NeedTextureData(Sha256),
// Name or id already in use
Conflict,
}

View File

@ -70,47 +70,85 @@ impl DataStore {
} }
} }
pub fn insert(&mut self, tex: Texture) -> bool { /// * `data` The content of the texture file, if available.
pub fn insert(
&mut self,
tex: Texture,
data: Option<Arc<Vec<u8>>>,
) -> io::Result<ReplaceTextureStatus> {
use io::Write;
// Check for collisions // Check for collisions
let pos = self if self
.texture .texture
.iter() .iter()
.position(|e| e.id == tex.id || e.name == tex.name); .find(|e| e.id == tex.id || e.name == tex.name)
match pos { .is_some()
// Texture with same name or id is already stored {
Some(_) => false, // Name or id already in use
Ok(ReplaceTextureStatus::Conflict)
} else {
// Insert it // Insert it
None => { if self.has_hash(&tex.texture_hash)? {
self.texture.push(tex); self.texture.push(tex);
true Ok(ReplaceTextureStatus::Ok)
} else {
match data {
None => Ok(ReplaceTextureStatus::NeedTextureData(tex.texture_hash)),
Some(blob) => {
let mut tmp_image_path = self.data_dir.clone();
tmp_image_path.push("textures");
tmp_image_path.push(format!(
"{}_new",
tex.texture_hash.create_hex_string().to_lowercase()
));
let mut final_image_path = self.data_dir.clone();
final_image_path.push("textures");
final_image_path.push(tex.texture_hash.create_hex_string().to_lowercase());
{
let mut writer = fs::File::create(&tmp_image_path)?;
writer.write_all(&blob)?;
}
fs::rename(tmp_image_path, final_image_path)?;
Ok(ReplaceTextureStatus::Ok)
}
}
} }
} }
} }
pub fn by_name<'a>(&'a self, name: &str) -> Option<&'a Texture> { pub fn by_name<'a>(&'a self, name: &str) -> Option<&'a Texture> {
let pos = self.texture.iter().position(|e| e.name == name); self.texture.iter().find(|e| e.name == name)
match pos {
Some(idx) => Some(self.texture.get(idx).unwrap()),
None => None,
}
} }
pub fn by_id<'a, 'b>(&'a self, id: &'b str) -> Option<&'a Texture> { pub fn by_id<'a, 'b>(&'a self, id: &'b str) -> Option<&'a Texture> {
let pos = self.texture.iter().position(|e| e.id == id); self.texture.iter().find(|e| e.id == id)
match pos {
Some(idx) => Some(self.texture.get(idx).unwrap()),
None => None,
}
} }
pub fn has_hash(&self, hash: &Sha256) -> bool { /// Check if the texture, given by hash, physically exists on the file system.
// TODO What is the purpose of this function? pub fn has_hash(&self, hash: &Sha256) -> io::Result<bool> {
// Currently checks for textures in the list with the given hash. let mut texture_path = self.data_dir.clone();
// Should it check for an existing image file instead? texture_path.push("textures");
self.texture texture_path.push(hash.create_hex_string().to_lowercase());
.iter() match texture_path.metadata() {
.position(|e| &e.texture_hash == hash) Ok(meta) => {
.is_some() if meta.is_file() {
Ok(true)
} else {
Err(io::Error::new(
io::ErrorKind::Other,
format!("{:?} exists but is not a regular file.", texture_path),
))
}
}
Err(e) => {
if e.kind() == io::ErrorKind::NotFound {
Ok(false)
} else {
Err(e)
}
}
}
} }
pub fn get_texture_file(&mut self, hash: &Sha256) -> TextureFileResult { pub fn get_texture_file(&mut self, hash: &Sha256) -> TextureFileResult {

View File

@ -1,12 +1,5 @@
use crate::model::*; use crate::model::*;
pub enum ReplaceTextureStatus {
// Call Again With Texture Binary
NeedTextureData(Sha256),
// Done.
Ok,
}
pub type ProtocolResult<T> = Result<T, ProtocolError>; pub type ProtocolResult<T> = Result<T, ProtocolError>;
pub enum ProtocolError { pub enum ProtocolError {
BadRequest(String), BadRequest(String),

View File

@ -109,6 +109,10 @@ where
panic!("Contract Violation: handler must not return NeedTextureData \ panic!("Contract Violation: handler must not return NeedTextureData \
when data is given."); when data is given.");
} }
Ok(ReplaceTextureStatus::Conflict) => {
connection
.send(&Package::Error(409, "Conflict".to_string()))?;
}
Err(err) => { Err(err) => {
connection.send(&Package::from(err))?; connection.send(&Package::from(err))?;
} }
@ -125,6 +129,9 @@ where
} }
} }
} }
Ok(ReplaceTextureStatus::Conflict) => {
connection.send(&Package::Error(409, "Conflict".to_string()))?;
}
Err(err) => { Err(err) => {
connection.send(&Package::from(err))?; connection.send(&Package::from(err))?;
} }