Import and update the file service application and orizentic #72
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
html::*,
|
||||
store::{FileHandle, FileId, ReadFileError, Thumbnail},
|
||||
store::{FileHandle, FileId, ReadFileError},
|
||||
};
|
||||
use build_html::{self, Container, ContainerType, Html, HtmlContainer};
|
||||
|
||||
|
|
|
@ -71,7 +71,6 @@ impl TryFrom<String> for PathResolver {
|
|||
impl TryFrom<&str> for PathResolver {
|
||||
type Error = PathError;
|
||||
fn try_from(s: &str) -> Result<Self, Self::Error> {
|
||||
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<HexString, ReadFileError> {
|
||||
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<u8>) -> 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<Vec<u8>, 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),
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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<Vec<FileId>, ReadFileError> {
|
||||
unimplemented!()
|
||||
pub fn list_files(&self) -> Result<HashSet<FileId>, 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::<HashSet<FileId>>())
|
||||
}
|
||||
|
||||
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::<HashSet<FileId>>();
|
||||
|
||||
println!("ids: {:?}", ids);
|
||||
assert_eq!(ids.len(), 1);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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_)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue