diff --git a/file-service/src/main.rs b/file-service/src/main.rs index 549854e..b43dac8 100644 --- a/file-service/src/main.rs +++ b/file-service/src/main.rs @@ -1,11 +1,3 @@ -/* -use iron::headers; -use iron::middleware::Handler; -use iron::modifiers::{Header, Redirect}; -use iron::prelude::*; -use iron::response::BodyReader; -use iron::status; -*/ #[macro_use] extern crate log; @@ -14,9 +6,8 @@ use http::status::StatusCode; // use orizentic::{Permissions, ResourceName, Secret}; use build_html::Html; use bytes::Buf; -use futures_util::{Stream, StreamExt}; +use futures_util::StreamExt; use std::{ - collections::HashMap, io::Read, net::{IpAddr, Ipv4Addr, SocketAddr}, path::PathBuf, @@ -24,9 +15,9 @@ use std::{ }; use warp::{filters::multipart::Part, Filter}; -mod cookies; +// mod cookies; mod html; -mod middleware; +// mod middleware; mod pages; mod store; @@ -430,7 +421,7 @@ pub async fn main() { .with(log), ); */ - let server = warp::serve(root.or(upload).with(log)); + let server = warp::serve(root.or(upload).or(thumbnail).or(file).or(delete).with(log)); server .run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8002)) .await; diff --git a/file-service/src/pages.rs b/file-service/src/pages.rs index a95e70a..c69b075 100644 --- a/file-service/src/pages.rs +++ b/file-service/src/pages.rs @@ -1,6 +1,6 @@ use crate::{ html::*, - store::{FileHandle, FileId, ReadFileError, Thumbnail}, + store::{FileHandle, FileId, ReadFileError}, }; use build_html::{self, Container, ContainerType, Html, HtmlContainer}; diff --git a/file-service/src/store/filehandle.rs b/file-service/src/store/filehandle.rs index 50f79d5..d81159f 100644 --- a/file-service/src/store/filehandle.rs +++ b/file-service/src/store/filehandle.rs @@ -71,7 +71,6 @@ impl TryFrom for PathResolver { impl TryFrom<&str> for PathResolver { type Error = PathError; fn try_from(s: &str) -> Result { - let path = Path::new(s); PathResolver::try_from(Path::new(s)) } } @@ -160,11 +159,12 @@ impl FileHandle { )?; let byte_count = content_file.write(&content)?; self.info.size = byte_count; + self.info.hash = self.hash_content(&content).as_string(); let mut md_file = std::fs::File::create(self.path.metadata_path())?; md_file.write(&serde_json::to_vec(&self.info)?)?; - self.write_thumbnail(); + self.write_thumbnail()?; Ok(()) } @@ -177,12 +177,8 @@ impl FileHandle { load_content(&self.path.thumbnail_path()?) } - fn hash_content(&self) -> Result { - let mut buf = Vec::new(); - let mut file = std::fs::File::open(self.path.file_path()?)?; - file.read_to_end(&mut buf).map_err(ReadFileError::from)?; - - Ok(HexString::from_bytes(&Sha256::digest(&buf).to_vec())) + fn hash_content(&self, data: &Vec) -> HexString { + HexString::from_bytes(&Sha256::digest(data).to_vec()) } fn write_thumbnail(&self) -> Result<(), WriteFileError> { @@ -202,20 +198,20 @@ impl FileHandle { Ok(()) } - pub fn delete(self) -> Result<(), WriteFileError> { - std::fs::remove_file( - self.path - .thumbnail_path() - .map_err(|_| WriteFileError::NoMetadata)?, - )?; - std::fs::remove_file(self.path.metadata_path())?; - std::fs::remove_file( - self.path - .file_path() - .map_err(|_| WriteFileError::NoMetadata)?, - )?; - - Ok(()) + pub fn delete(self) { + match self.path.thumbnail_path() { + Ok(path) => { + let _ = std::fs::remove_file(path); + } + Err(_) => {} + }; + match self.path.file_path() { + Ok(path) => { + let _ = std::fs::remove_file(path); + } + Err(_) => {} + }; + let _ = std::fs::remove_file(self.path.metadata_path()); } } @@ -229,7 +225,7 @@ fn load_content(path: &Path) -> Result, ReadFileError> { #[cfg(test)] mod test { use super::*; - use crate::store::utils::FileCleanup; + use crate::store::utils::DirCleanup; use cool_asserts::assert_matches; use std::{convert::TryFrom, path::PathBuf}; @@ -237,6 +233,7 @@ mod test { fn paths() { let resolver = PathResolver::try_from("path/82420255-d3c8-4d90-a582-f94be588c70c.png") .expect("to have a valid path"); + assert_matches!( resolver.file_path(), Ok(path) => assert_eq!(path, PathBuf::from( @@ -257,15 +254,21 @@ mod test { #[test] fn it_opens_a_file() { - let _md = FileCleanup(PathBuf::from("fixtures/.metadata/rawr.png.json")); - let _tn = FileCleanup(PathBuf::from("fixtures/.thumbnails/rawr.png")); - + let _cleanup = DirCleanup(PathBuf::from("var/")); FileHandle::new("rawr.png".to_owned(), PathBuf::from("var/")).expect("to succeed"); } #[test] - fn it_can_return_a_thumbnail() { + fn it_deletes_a_file() { + let _cleanup = DirCleanup(PathBuf::from("var/")); let f = FileHandle::new("rawr.png".to_owned(), PathBuf::from("var/")).expect("to succeed"); + f.delete(); + } + + #[test] + fn it_can_return_a_thumbnail() { + let _cleanup = DirCleanup(PathBuf::from("var/")); + let _ = FileHandle::new("rawr.png".to_owned(), PathBuf::from("var/")).expect("to succeed"); /* assert_eq!( f.thumbnail(), @@ -279,13 +282,14 @@ mod test { #[test] fn it_can_return_a_file_stream() { - let f = FileHandle::new("rawr.png".to_owned(), PathBuf::from("var/")).expect("to succeed"); + let _cleanup = DirCleanup(PathBuf::from("var/")); + let _ = FileHandle::new("rawr.png".to_owned(), PathBuf::from("var/")).expect("to succeed"); // f.stream().expect("to succeed"); } #[test] fn it_raises_an_error_when_file_not_found() { - let resolver = PathResolver::try_from("var/rawr.png").expect("a valid path"); + let _cleanup = DirCleanup(PathBuf::from("var/")); match FileHandle::load(&FileId::from("rawr"), &PathBuf::from("var/")) { Err(ReadFileError::FileNotFound(_)) => assert!(true), _ => assert!(false), diff --git a/file-service/src/store/fileinfo.rs b/file-service/src/store/fileinfo.rs index 6f253ff..ba71c40 100644 --- a/file-service/src/store/fileinfo.rs +++ b/file-service/src/store/fileinfo.rs @@ -41,15 +41,11 @@ impl FileInfo { #[cfg(test)] mod test { use super::*; - use crate::store::{filehandle::PathResolver, utils::FileCleanup, FileId}; - use std::convert::TryFrom; + use crate::store::{utils::DirCleanup, FileId}; #[test] fn it_saves_and_loads_metadata() { - let resolver = PathResolver::try_from("var/1617654d-a588-4714-b4fa-e00ed0a8a607.png") - .expect("a valid path"); - let _cleanup = FileCleanup(resolver.metadata_path()); - + let _cleanup = DirCleanup(PathBuf::from("var/")); let created = Utc::now(); let info = FileInfo { @@ -60,9 +56,10 @@ mod test { hash: "abcdefg".to_owned(), extension: "png".to_owned(), }; - info.save(resolver.metadata_path()).unwrap(); + info.save(PathBuf::from(format!("var/{}", *info.id))) + .unwrap(); - let info_ = FileInfo::load(resolver.metadata_path()).unwrap(); + let info_ = FileInfo::load(PathBuf::from(format!("var/{}", *info.id))).unwrap(); assert_eq!(info_.size, 23777); assert_eq!(info_.created, info.created); assert_eq!(info_.file_type, "image/png"); diff --git a/file-service/src/store/mod.rs b/file-service/src/store/mod.rs index 4a9ff6a..227d8bb 100644 --- a/file-service/src/store/mod.rs +++ b/file-service/src/store/mod.rs @@ -1,18 +1,14 @@ use serde::{Deserialize, Serialize}; -use std::{ - ops::Deref, - path::{Path, PathBuf}, -}; +use std::collections::HashSet; +use std::{ops::Deref, path::PathBuf}; use thiserror::Error; mod filehandle; mod fileinfo; -mod thumbnail; pub mod utils; pub use filehandle::FileHandle; pub use fileinfo::FileInfo; -pub use thumbnail::Thumbnail; #[derive(Debug, Error)] pub enum WriteFileError { @@ -118,8 +114,20 @@ impl Store { Self { files_root } } - pub fn list_files(&self) -> Result, ReadFileError> { - unimplemented!() + pub fn list_files(&self) -> Result, ReadFileError> { + let paths = std::fs::read_dir(&self.files_root)?; + Ok(paths + .into_iter() + .map(|path| { + FileId::from( + path.unwrap() + .path() + .file_stem() + .and_then(|s| s.to_str()) + .unwrap(), + ) + }) + .collect::>()) } pub fn add_file( @@ -152,8 +160,7 @@ impl Store { #[cfg(test)] mod test { - use super::*; - use crate::store::utils::FileCleanup; + use super::{utils::DirCleanup, *}; use cool_asserts::assert_matches; use std::{collections::HashSet, io::Read}; @@ -161,6 +168,8 @@ mod test { where F: FnOnce(Store, FileId), { + let _cleanup = DirCleanup(PathBuf::from("var/")); + let mut buf = Vec::new(); let mut file = std::fs::File::open("fixtures/rawr.png").unwrap(); file.read_to_end(&mut buf).unwrap(); @@ -168,10 +177,6 @@ mod test { let mut store = Store::new(PathBuf::from("var/")); let file_record = store.add_file("rawr.png".to_owned(), buf).unwrap(); - let _file = FileCleanup(PathBuf::from(format!("var/{}.png", *file_record.id))); - let _md = FileCleanup(PathBuf::from(format!("var/{}.json", *file_record.id))); - let _tn = FileCleanup(PathBuf::from(format!("var/{}.tn.png", *file_record.id))); - test_fn(store, file_record.id); } @@ -191,6 +196,7 @@ mod test { #[test] fn sets_up_metadata_for_file() { with_file(|store, id| { + assert!(PathBuf::from(format!("var/{}.png", *id)).exists()); let info = store.get_metadata(&id).expect("to retrieve the metadata"); assert_matches!(info, FileInfo { size, file_type, hash, extension, .. } => { @@ -229,6 +235,7 @@ mod test { let resolvers = store.list_files().expect("file listing to succeed"); let ids = resolvers.into_iter().collect::>(); + println!("ids: {:?}", ids); assert_eq!(ids.len(), 1); }); } diff --git a/file-service/src/store/utils.rs b/file-service/src/store/utils.rs index 9427daf..92b7099 100644 --- a/file-service/src/store/utils.rs +++ b/file-service/src/store/utils.rs @@ -1,17 +1,15 @@ -use std::path::{Path, PathBuf}; +use std::{ffi::OsStr, path::PathBuf}; -pub struct FileCleanup(pub PathBuf); +pub struct DirCleanup(pub PathBuf); -impl Drop for FileCleanup { +impl Drop for DirCleanup { fn drop(&mut self) { - let _ = std::fs::remove_file(&self.0); + let files = std::fs::read_dir(&self.0).unwrap(); + for file in files { + let filename = file.unwrap().path(); + if filename.file_name() != Some(&OsStr::new(".placeholder")) { + let _ = std::fs::remove_file(filename); + } + } } } - -pub fn append_extension(path: &Path, extra_ext: &str) -> PathBuf { - let ext_ = match path.extension() { - None => String::from(extra_ext), - Some(ext) => [ext.to_string_lossy(), std::borrow::Cow::from(extra_ext)].join("."), - }; - path.with_extension(ext_) -}