#![feature(proc_macro_hygiene, decl_macro)] #[macro_use] extern crate rocket; #[macro_use] extern crate lazy_static; use std::path::{PathBuf, Path}; use std::env; use std::fs; use std::ffi::OsStr; use std::collections::HashMap; use rocket::response::{NamedFile, Redirect}; use rocket::http::ContentType; use rocket_contrib::templates::Template; use rocket_upload::MultipartDatas; use serde::{Serialize, Deserialize}; #[derive(Serialize)] struct DirPath { is_file: bool, path: String, name: String, } #[derive(FromForm, Deserialize)] struct LoginInfo { key: String, } lazy_static! { static ref DIR: PathBuf = Path::new(env::var("FASTCLOUD_DIR").unwrap_or_else(|_| String::from("")).as_str()).to_path_buf(); static ref ADMIN_KEY: PathBuf = Path::new(env::var("FASTCLOUD_ADMIN_KEY").unwrap_or_else(|_| String::from("")).as_str()).to_path_buf(); static ref USER_KEY: PathBuf = Path::new(env::var("FASTCLOUD_USER_KEY").unwrap_or_else(|_| String::from("")).as_str()).to_path_buf(); } #[get("/serve")] fn get_root() -> Template { let path = DIR.as_path().to_str().unwrap_or(""); Template::render("dir", directory_structure(path.to_string())) } #[get("/serve/")] fn get_dir_entry(path: PathBuf) -> Template { let dir = DIR.as_path().join(path); let path = dir.to_str().unwrap_or(""); Template::render("dir", directory_structure(path.to_string())) } #[post("/dir/")] fn create_dir(path: PathBuf) { let dir = DIR.as_path().join(path); fs::create_dir_all(dir).unwrap(); } #[post("/del/")] fn delete(path: PathBuf) -> Redirect { let dir = DIR.as_path().join(path.clone()); if dir.is_file() { fs::remove_file(dir).unwrap(); } else { fs::remove_dir_all(dir).unwrap(); } let npath = path.parent().unwrap().to_path_buf(); Redirect::to(uri!(get_dir_entry: npath)) } fn directory_structure(path: String) -> HashMap<&'static str, HashMap> { let dir = Path::new(path.as_str()); let paths = fs::read_dir(dir).unwrap() .map(|x| x.unwrap().path().into_os_string().into_string().unwrap()) .enumerate() .map(|x| (x.0 as i32, DirPath { is_file: Path::new(&x.1).is_file(), path: Path::new(&x.1).strip_prefix(DIR.clone().into_os_string().into_string().unwrap()).unwrap().to_str().unwrap().to_string(), name: Path::new(&x.1).file_name().unwrap().to_str().unwrap().to_string(), })) .collect::>(); let mut context: HashMap<&str, HashMap> = HashMap::new(); let parent = DirPath { is_file: false, path: dir.strip_prefix(DIR.clone().into_os_string().into_string().unwrap()).unwrap().parent().unwrap_or_else(|| Path::new("")).to_str().unwrap().to_string(), name: dir.parent().unwrap().file_name().unwrap_or_else(|| OsStr::new("")).to_str().unwrap().to_string(), }; let current = DirPath { is_file: false, path: dir.strip_prefix(DIR.clone().into_os_string().into_string().unwrap()).unwrap_or_else(|_| Path::new("")).to_str().unwrap().to_string(), name: dir.file_name().unwrap_or_else(|| OsStr::new("")).to_str().unwrap().to_string(), }; let mut pt = HashMap::new(); pt.insert(0, parent); context.insert("parent", pt); let mut pt = HashMap::new(); pt.insert(0, current); context.insert("current", pt); context.insert("ctx", paths); context } #[get("/file/")] fn file_get(path: PathBuf) -> Option { let dir = DIR.as_path().join(path); rocket::response::NamedFile::open(dir.as_path()).ok() } #[post("/upload/", data = "")] fn upload_file(path: PathBuf, _content_type: &ContentType, data:MultipartDatas) -> Redirect { let dir = DIR.as_path().join(path.clone()); for f in data.files { if !Path::new(&format!("{}/{}", dir.to_str().unwrap(), f.filename)).exists() { f.persist(&dir); } for i in 0.. { if !Path::new(&format!("{}/{}.{}", dir.to_str().unwrap(), f.filename, i)).exists() { f.persist(&dir); break } } } Redirect::to(uri!(get_dir_entry: path)) } // TODO: move files // TODO: rename files // TODO: rewrite frontend fn main() { rocket::ignite() .attach(Template::fairing()) .mount("/", routes![get_root, get_dir_entry, create_dir, file_get, upload_file, delete]).launch(); }