Implement more persistency logic
This commit is contained in:
parent
f5dcd52454
commit
96c2864a07
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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))?;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue