From 77cecebe522d90de010713ffea3f7e5489d0c03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20F=C3=BCrderer?= Date: Wed, 8 May 2019 16:34:55 +0200 Subject: [PATCH] Implement garbage collect on the server --- .../texture-sync-server/src/model/sha256.rs | 32 +++++++------- .../src/persistency/mod.rs | 44 +++++++++++++++++-- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/server/texture-sync-server/src/model/sha256.rs b/server/texture-sync-server/src/model/sha256.rs index cbb0181..0aed6ba 100644 --- a/server/texture-sync-server/src/model/sha256.rs +++ b/server/texture-sync-server/src/model/sha256.rs @@ -33,6 +33,20 @@ impl Sha256 { Sha256(hash_arr) } + + pub fn from_hex(hex_str: &str) -> Option { + if hex_str.len() != 32 * 2 { + return None; // String has wrong length + } + + let mut out = [0u8; 32]; + for (i, byte) in out.iter_mut().enumerate() { + let string_index = i * 2; + *byte = u8::from_str_radix(&hex_str[string_index..=string_index + 1], 16).ok()?; + } + + Some(Sha256(out)) + } } fn as_hex(hash: &[u8; 32], serializer: S) -> Result @@ -48,22 +62,10 @@ where { use serde::de::Error; - fn hex2bytes(s: &str) -> Option<[u8; 32]> { - if s.len() != 32 * 2 { - return None; // String has wrong length - } - - let mut out = [0u8; 32]; - for (i, byte) in out.iter_mut().enumerate() { - let string_index = i * 2; - *byte = u8::from_str_radix(&s[string_index..=string_index + 1], 16).ok()?; - } - - return Some(out); - } - String::deserialize(deserializer).and_then(|string| { - hex2bytes(&string).ok_or_else(|| Error::custom("Invalid HEX String!".to_string())) + Ok(Sha256::from_hex(&string) + .ok_or_else(|| Error::custom("Invalid HEX String!".to_string()))? + .0) }) } diff --git a/server/texture-sync-server/src/persistency/mod.rs b/server/texture-sync-server/src/persistency/mod.rs index 0fb4b4d..8339025 100644 --- a/server/texture-sync-server/src/persistency/mod.rs +++ b/server/texture-sync-server/src/persistency/mod.rs @@ -182,11 +182,47 @@ impl DataStore { self.textures.iter() } - pub fn garbage_collect(&mut self) -> io::Result<()> { - //unimplemented!() + pub fn extract_hash(filename: &std::ffi::OsStr) -> Option { + // directly return None for invalidly encoded file names + let str_name = filename.to_str()?; + let hash = Sha256::from_hex(str_name)?; - /// VERY TODO: - eprintln!("WARNING: We are sorry the GC isn't implemented yet :'( "); + // check back to ignore names with lowercase letters + if hash.as_hex_string() == str_name { + Some(hash) + } else { + None + } + } + + pub fn garbage_collect(&mut self) -> io::Result<()> { + let texture_dir = std::fs::read_dir(self.texture_base_path())?; + + let mut hashs_on_disk = HashSet::new(); + for result_direntry in texture_dir { + let texture_path = result_direntry?.path(); + let filename = match texture_path.file_name() { + Some(name) => name, + None => continue, + }; + match Self::extract_hash(filename) { + Some(hash) => { + hashs_on_disk.insert(hash); + } + None => (), // ignore other files + }; + } + + let mut unused_files = hashs_on_disk; + for texture in &self.textures { + unused_files.remove(&texture.texture_hash); + } + + // remove what is still contained in the HashSet + for entry in unused_files { + let path = self.texture_file_path(&entry); + std::fs::remove_file(path)?; + } Ok(()) } }