diff --git a/src/main.rs b/src/main.rs index 85a3430..698425d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,28 +3,34 @@ mod web; fn main() -> std::io::Result<()> { let app = clap::App::new(clap::crate_name!()) - .author(clap::crate_authors!("\n")) - .version(clap::crate_version!()) - .about(clap::crate_description!()) - .arg(clap::Arg::with_name("chdir") - .short("w") - .long("chdir") - .value_name("DIRECTORY") - .help("directory to serve") - .default_value(".") - .takes_value(true)) - .arg(clap::Arg::with_name("addr") - .short("b") - .long("bind") - .value_name("ADDRESS") - .help("bind address") - .default_value("0.0.0.0") - .takes_value(true)) - .arg(clap::Arg::with_name("port") - .value_name("PORT") - .help("Specify alternate port") - .default_value("8000") - .index(1)); + .author(clap::crate_authors!("\n")) + .version(clap::crate_version!()) + .about(clap::crate_description!()) + .arg( + clap::Arg::with_name("chdir") + .short("w") + .long("chdir") + .value_name("DIRECTORY") + .help("directory to serve") + .default_value(".") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("addr") + .short("b") + .long("bind") + .value_name("ADDRESS") + .help("bind address") + .default_value("0.0.0.0") + .takes_value(true), + ) + .arg( + clap::Arg::with_name("port") + .value_name("PORT") + .help("Specify alternate port") + .default_value("8000") + .index(1), + ); let matches = app.get_matches(); let chdir = matches.value_of("chdir").unwrap(); // these shouldn't panic ever, since all have default_value @@ -32,7 +38,10 @@ fn main() -> std::io::Result<()> { let port = matches.value_of("port").unwrap(); let bind_addr = format!("{}:{}", addr, port); - std::env::set_var("RUST_LOG", std::env::var("RUST_LOG").unwrap_or("info".to_string())); + std::env::set_var( + "RUST_LOG", + std::env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()), + ); env_logger::init(); let root = std::path::PathBuf::from(chdir).canonicalize()?; diff --git a/src/threaded_archiver.rs b/src/threaded_archiver.rs index 7c7c2d9..38755fa 100644 --- a/src/threaded_archiver.rs +++ b/src/threaded_archiver.rs @@ -1,12 +1,11 @@ +use bytes; use futures; use futures::Sink; -use bytes; use tar; -use std::thread; -use std::path::PathBuf; use std::io; - +use std::path::PathBuf; +use std::thread; /* * TODO: @@ -17,7 +16,6 @@ type Stream = futures::sync::mpsc::Receiver; type Sender = futures::sync::mpsc::Sender; type BlockingSender = futures::sink::Wait; - pub fn stream_tar_in_thread(path: PathBuf) -> Stream { let (writer, stream) = StreamWriter::new(64); @@ -27,32 +25,34 @@ pub fn stream_tar_in_thread(path: PathBuf) -> Stream { a.mode(tar::HeaderMode::Deterministic); a.append_dir_all(last_path_component, &path) .unwrap_or_else(|e| println!("{}", e)); - a.finish() - .unwrap_or_else(|e| println!("{}", e)); + a.finish().unwrap_or_else(|e| println!("{}", e)); }); stream } struct StreamWriter { - tx: BlockingSender + tx: BlockingSender, } impl StreamWriter { fn new(size: usize) -> (Self, Stream) { let (tx, rx) = futures::sync::mpsc::channel(size); let tx = tx.wait(); - (StreamWriter{tx:tx}, rx) + (StreamWriter { tx }, rx) } } impl io::Write for StreamWriter { fn write(&mut self, buf: &[u8]) -> io::Result { - self.tx.send(bytes::Bytes::from(buf)) + self.tx + .send(bytes::Bytes::from(buf)) .map(|_| buf.len()) .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) } fn flush(&mut self) -> io::Result<()> { - self.tx.flush().map_err(|e| io::Error::new(io::ErrorKind::Other, e)) + self.tx + .flush() + .map_err(|e| io::Error::new(io::ErrorKind::Other, e)) } } diff --git a/src/web.rs b/src/web.rs index f0f72b3..8a6169a 100644 --- a/src/web.rs +++ b/src/web.rs @@ -1,6 +1,6 @@ -use actix_web::{App, middleware, error, HttpServer, HttpRequest, HttpResponse, Responder, web}; -use actix_web::dev::ServiceResponse; use actix_files as fs; +use actix_web::dev::ServiceResponse; +use actix_web::{error, middleware, web, App, HttpRequest, HttpResponse, HttpServer, Responder}; use futures::Stream; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use v_htmlescape::escape as escape_html_entity; @@ -10,7 +10,6 @@ use crate::threaded_archiver; use std::fmt::Write; use std::path::PathBuf; - pub fn run(bind_addr: &str, root: &PathBuf) -> std::io::Result<()> { let root = root.clone(); HttpServer::new(move || { @@ -32,49 +31,88 @@ pub fn run(bind_addr: &str, root: &PathBuf) -> std::io::Result<()> { .run() } - -fn handle_directory<'a, 'b>( - dir: &'a fs::Directory, - req: &'b HttpRequest, +fn handle_directory( + dir: &fs::Directory, + req: &HttpRequest, ) -> Result { - let rd = std::fs::read_dir(&dir.path)?; fn optimistic_is_dir(entry: &std::fs::DirEntry) -> bool { // consider it non directory if metadata reading fails, better than an unwrap() panic - entry.metadata().map(|m| m.file_type().is_dir()).unwrap_or(false) + entry + .metadata() + .map(|m| m.file_type().is_dir()) + .unwrap_or(false) } - let mut paths : Vec<_> = rd.filter_map(|entry| if dir.is_visible(&entry) { entry.ok() } else {None}).collect(); + let mut paths: Vec<_> = rd + .filter_map(|entry| { + if dir.is_visible(&entry) { + entry.ok() + } else { + None + } + }) + .collect(); paths.sort_by_key(|entry| (!optimistic_is_dir(entry), entry.file_name())); - let tar_url = req.path().trim_end_matches('/'); // this is already encoded let mut body = String::new(); writeln!(body, "

Index of {}

", req.path()).unwrap(); // FIXME: decode from url, escape for html - writeln!(body, r#"[.tar of whole directory]"#, tar_url).unwrap(); + writeln!( + body, + r#"[.tar of whole directory]"#, + tar_url + ) + .unwrap(); writeln!(body, "").unwrap(); - writeln!(body, "").unwrap(); + writeln!( + body, + "" + ) + .unwrap(); for entry in paths { let meta = entry.metadata()?; - let file_url = utf8_percent_encode(&entry.file_name().to_string_lossy(), NON_ALPHANUMERIC).to_string(); + let file_url = + utf8_percent_encode(&entry.file_name().to_string_lossy(), NON_ALPHANUMERIC).to_string(); let file_name = escape_html_entity(&entry.file_name().to_string_lossy()).to_string(); let size = meta.len(); write!(body, "").unwrap(); if meta.file_type().is_dir() { - writeln!(body, r#""#, file_url, file_name).unwrap(); - write!(body, r#" "#, file_url).unwrap(); + writeln!( + body, + r#""#, + file_url, file_name + ) + .unwrap(); + write!( + body, + r#" "#, + file_url + ) + .unwrap(); } else { - writeln!(body, r#""#, file_url, file_name).unwrap(); + writeln!( + body, + r#""#, + file_url, file_name + ) + .unwrap(); write!(body, " ", size).unwrap(); } writeln!(body, "").unwrap(); } writeln!(body, "
📁 ../Size
📁 ../Size
📂 {}/[.tar]📂 {}/[.tar]🗎 {}🗎 {}{}
").unwrap(); - writeln!(body, r#""#, - env!("CARGO_PKG_HOMEPAGE"), env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")).unwrap(); + writeln!( + body, + r#""#, + env!("CARGO_PKG_HOMEPAGE"), + env!("CARGO_PKG_NAME"), + env!("CARGO_PKG_VERSION") + ) + .unwrap(); let mut html = String::new(); writeln!(html, "").unwrap(); @@ -85,7 +123,9 @@ fn handle_directory<'a, 'b>( writeln!(html, "\n{}", body).unwrap(); writeln!(html, "").unwrap(); - let resp = HttpResponse::Ok().content_type("text/html; charset=utf-8").body(html); + let resp = HttpResponse::Ok() + .content_type("text/html; charset=utf-8") + .body(html); Ok(ServiceResponse::new(req.clone(), resp)) }