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