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(dead_code)]
use std::io;
mod sha256;
pub use sha256::Sha256;
@ -18,3 +20,14 @@ pub struct Texture {
pub resolution: (usize, usize),
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
let pos = self
if self
.texture
.iter()
.position(|e| e.id == tex.id || e.name == tex.name);
match pos {
// Texture with same name or id is already stored
Some(_) => false,
.find(|e| e.id == tex.id || e.name == tex.name)
.is_some()
{
// Name or id already in use
Ok(ReplaceTextureStatus::Conflict)
} else {
// Insert it
None => {
if self.has_hash(&tex.texture_hash)? {
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> {
let pos = self.texture.iter().position(|e| e.name == name);
match pos {
Some(idx) => Some(self.texture.get(idx).unwrap()),
None => None,
}
self.texture.iter().find(|e| e.name == name)
}
pub fn by_id<'a, 'b>(&'a self, id: &'b str) -> Option<&'a Texture> {
let pos = self.texture.iter().position(|e| e.id == id);
match pos {
Some(idx) => Some(self.texture.get(idx).unwrap()),
None => None,
}
self.texture.iter().find(|e| e.id == id)
}
pub fn has_hash(&self, hash: &Sha256) -> bool {
// TODO What is the purpose of this function?
// Currently checks for textures in the list with the given hash.
// Should it check for an existing image file instead?
self.texture
.iter()
.position(|e| &e.texture_hash == hash)
.is_some()
/// Check if the texture, given by hash, physically exists on the file system.
pub fn has_hash(&self, hash: &Sha256) -> io::Result<bool> {
let mut texture_path = self.data_dir.clone();
texture_path.push("textures");
texture_path.push(hash.create_hex_string().to_lowercase());
match texture_path.metadata() {
Ok(meta) => {
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 {

View File

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

View File

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