#[macro_use] extern crate log; use handlers::{file, handle_auth, handle_upload, thumbnail}; use http::status::StatusCode; // use mustache::{compile_path, Template}; // use orizentic::{Permissions, ResourceName, Secret}; use bytes::Buf; use futures_util::StreamExt; use std::{ collections::HashSet, convert::Infallible, io::Read, net::{IpAddr, Ipv4Addr, SocketAddr}, path::PathBuf, sync::Arc, }; use tokio::sync::RwLock; use warp::{filters::multipart::Part, Filter, Rejection}; mod handlers; mod html; mod pages; pub use file_service::{ AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store, Username, WriteFileError, }; pub use handlers::handle_index; /* async fn authenticate_user(app: App, auth_token: String) -> Result { match app.auth_session(SessionToken::from(auth_token)).await { Ok(username) => Ok(username), Err(_) => Err(warp::reject::not_found()), } } */ /* */ /* async fn collect_content( mut part: Part, ) -> Result<(Option, Option, Vec), String> { let mut content: Vec = Vec::new(); while let Some(Ok(data)) = part.data().await { let mut reader = data.reader(); reader.read_to_end(&mut content).unwrap(); } Ok(( part.content_type().map(|s| s.to_owned()), part.filename().map(|s| s.to_owned()), content, )) } */ /* async fn collect_multipart( mut stream: warp::filters::multipart::FormData, ) -> Result, Option, Vec)>, warp::Error> { let mut content: Vec<(Option, Option, Vec)> = Vec::new(); while let Some(part) = stream.next().await { match part { Ok(part) => content.push(collect_content(part).await.unwrap()), Err(err) => return Err(err), } } Ok(content) } */ /* async fn handle_upload( form: warp::filters::multipart::FormData, app: App, ) -> warp::http::Result> { let files = collect_multipart(form).await; match files { Ok(files) => { for (_, filename, content) in files { match filename { Some(filename) => { app.add_file(filename, content).unwrap(); } None => { return warp::http::Response::builder() .status(StatusCode::BAD_REQUEST) .body("".to_owned()) } } } } Err(_err) => { return warp::http::Response::builder() .status(StatusCode::BAD_REQUEST) .body("".to_owned()) } } // println!("file length: {:?}", files.map(|f| f.len())); warp::http::Response::builder() .header("location", "/") .status(StatusCode::SEE_OTHER) .body("".to_owned()) } */ #[derive(Clone)] pub struct App { authdb: Arc>, store: Arc>, } impl App { pub fn new(authdb: AuthDB, store: Store) -> Self { Self { authdb: Arc::new(RwLock::new(authdb)), store: Arc::new(RwLock::new(store)), } } pub async fn auth_token(&self, token: AuthToken) -> Result, AuthError> { self.authdb.read().await.auth_token(token).await } pub async fn auth_session(&self, token: SessionToken) -> Result, AuthError> { self.authdb.read().await.auth_session(token).await } pub async fn list_files(&self) -> Result, ReadFileError> { self.store.read().await.list_files() } pub async fn get_file(&self, id: &FileId) -> Result { self.store.read().await.get_file(id) } pub async fn add_file( &self, filename: String, content: Vec, ) -> Result { self.store.write().await.add_file(filename, content) } } fn with_app(app: App) -> impl Filter + Clone { warp::any().map(move || app.clone()) } fn maybe_with_session() -> impl Filter,), Error = Rejection> + Copy { warp::any() .and(warp::header::optional::("cookie")) .map(|cookies| { println!("cookies retrieved: {:?}", cookies); None }) } fn with_session() -> impl Filter + Copy { warp::any() .and(warp::header::("cookie")) .map(|token: String| SessionToken::from(token)) } #[tokio::main] pub async fn main() { pretty_env_logger::init(); let authdb = AuthDB::new(PathBuf::from(":memory:")).await.unwrap(); let store = Store::new(PathBuf::from(&std::env::var("FILE_SHARE_DIR").unwrap())); let app = App::new(authdb, store); /* let with_app = { let app = app.clone(); warp::any().map(move || app.clone()) }; */ let log = warp::log("file_service"); let root = warp::path!() .and(warp::get()) .and(with_app(app.clone())) .and(maybe_with_session()) .then(handle_index); let auth = warp::path!("auth") .and(warp::post()) .and(with_app(app.clone())) .and(warp::filters::body::form()) .then(handle_auth); let upload_handler = warp::path!("upload") .and(warp::post()) .and(with_app(app.clone())) .and(with_session()) .then(handle_upload); let thumbnail = warp::path!(String / "tn") .and(warp::get()) .and(warp::header::optional::("if-none-match")) .and(with_app(app.clone())) .then(move |id, old_etags, app: App| thumbnail(app, id, old_etags)); let file = warp::path!(String) .and(warp::get()) .and(warp::header::optional::("if-none-match")) .and(with_app(app.clone())) .then(move |id, old_etags, app: App| file(app, id, old_etags)); let server = warp::serve( root.or(auth).with(log), /* root.or(auth) .or(thumbnail) .or(file) .or(upload_handler) .with(log), */ ); server .run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8002)) .await; }