Implement more persistency logic
This commit is contained in:
		@ -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))?;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user