From 63e69063939f821b41069781673230684d1678e9 Mon Sep 17 00:00:00 2001 From: sigoden Date: Fri, 27 May 2022 09:01:16 +0800 Subject: [PATCH] feat: add logger --- Cargo.lock | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 +++- README.md | 7 +++--- src/args.rs | 8 +++++++ src/index.html | 31 ++++++++++-------------- src/main.rs | 25 ++++++++++++++++---- src/server.rs | 20 ++++++++++++---- 7 files changed, 126 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9dbd22..5a980b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -54,6 +65,17 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + [[package]] name = "duf" version = "0.1.0" @@ -62,9 +84,11 @@ dependencies = [ "clap", "futures", "hyper", + "log", "percent-encoding", "serde", "serde_json", + "simple_logger", "tokio", "tokio-util", ] @@ -301,6 +325,15 @@ dependencies = [ "libc", ] +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + [[package]] name = "once_cell" version = "1.12.0" @@ -386,6 +419,19 @@ dependencies = [ "serde", ] +[[package]] +name = "simple_logger" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75a9723083573ace81ad0cdfc50b858aa3c366c48636edb4109d73122a0c0ea" +dependencies = [ + "atty", + "colored", + "log", + "time", + "winapi", +] + [[package]] name = "slab" version = "0.4.6" @@ -419,6 +465,24 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + [[package]] name = "tokio" version = "1.18.2" diff --git a/Cargo.toml b/Cargo.toml index 3f76308..dd785e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,9 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tokio-util = { version = "0.7", features = ["codec", "io-util"] } futures = "0.3" -base64 = "0.13.0" +base64 = "0.13" +log = "0.4" +simple_logger = "2.1.0" [profile.release] lto = true diff --git a/README.md b/README.md index 94d1f17..38f00f4 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,9 @@ Duf is a simple file server. ## Features - Serve static files -- Upload/Delete files -- Support basic auth +- Upload files +- Delete files +- Basic authentication - Easy to use with curl ## Install @@ -44,7 +45,7 @@ Finally, run this command to see a list of all available option -## Curl +### Curl Download a file ``` diff --git a/src/args.rs b/src/args.rs index 4fdeba8..8771c26 100644 --- a/src/args.rs +++ b/src/args.rs @@ -40,6 +40,10 @@ fn app() -> clap::Command<'static> { .help("Authenticate with user and pass") .value_name("user:pass"); + let arg_no_log = Arg::new("no-log") + .long("--no-log") + .help("Don't log any request/response information."); + clap::command!() .about(ABOUT) .arg(arg_address) @@ -47,6 +51,7 @@ fn app() -> clap::Command<'static> { .arg(arg_path) .arg(arg_readonly) .arg(arg_auth) + .arg(arg_no_log) } pub fn matches() -> ArgMatches { @@ -60,6 +65,7 @@ pub struct Args { pub path: PathBuf, pub readonly: bool, pub auth: Option, + pub log: bool, } impl Args { @@ -74,6 +80,7 @@ impl Args { let path = Args::parse_path(path)?; let readonly = matches.is_present("readonly"); let auth = matches.value_of("auth").map(|v| v.to_owned()); + let log = !matches.is_present("no-log"); Ok(Args { address, @@ -81,6 +88,7 @@ impl Args { path, readonly, auth, + log, }) } diff --git a/src/index.html b/src/index.html index f095e2c..552beef 100644 --- a/src/index.html +++ b/src/index.html @@ -59,8 +59,8 @@ const ajax = new XMLHttpRequest(); ajax.upload.addEventListener("progress", e => this.progress(e), false); ajax.addEventListener("load", e => this.complete(e), false); - ajax.addEventListener("error", e => this.error(e), false); - ajax.addEventListener("abort", e => this.abort(e), false); + ajax.addEventListener("error", e => this.fail(e), false); + ajax.addEventListener("abort", e => this.fail(e), false); ajax.open("PUT", path); ajax.send(file); } @@ -74,12 +74,8 @@ this.$elem.innerHTML = `${this.file.name}`; } - error(event) { - this.$elem.innerHTML = `${this.file.name} (x)`; - } - - abort(event) { - this.$elem.innerHTML = `${this.file.name} (x)`; + fail(event) { + this.$elem.innerHTML = `${this.file.name}`; } } @@ -126,18 +122,15 @@ async function deletePath(index) { const file = paths[index]; if (!file) return; - try { - const res = await fetch(encodeURI(file.path), { - method: "DELETE", - }); - if (res.status !== 200) { - const text = await res.text(); - throw new Error(text); + + const ajax = new XMLHttpRequest(); + ajax.open("DELETE", encodeURI(file.path)); + ajax.addEventListener("readystatechange", function() { + if(ajax.readyState === 4 && ajax.status === 200) { + document.getElementById(`addPath${index}`).remove(); } - document.getElementById(`addPath${index}`).remove(); - } catch (err) { - alert(`Failed to delete ${file.name}, ${err.message}`); - } + }); + ajax.send(); } function addUploadControl() { diff --git a/src/main.rs b/src/main.rs index 5e5f174..208eb16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,21 +4,36 @@ macro_rules! bail { } } +#[macro_use] +extern crate log; + mod args; mod server; pub type BoxResult = Result>; +use log::LevelFilter; + use crate::args::{matches, Args}; use crate::server::serve; #[tokio::main] async fn main() { - Args::parse(matches()) - .map(serve) - .unwrap_or_else(handle_err) - .await - .unwrap_or_else(handle_err); + run().await.unwrap_or_else(handle_err) +} + +async fn run() -> BoxResult<()> { + let args = Args::parse(matches())?; + + let level = if args.log { + LevelFilter::Info + } else { + LevelFilter::Error + }; + simple_logger::SimpleLogger::default() + .with_level(level) + .init()?; + serve(args).await } fn handle_err(err: Box) -> T { diff --git a/src/server.rs b/src/server.rs index 18e7787..41b6d76 100644 --- a/src/server.rs +++ b/src/server.rs @@ -37,7 +37,7 @@ pub async fn serve(args: Args) -> BoxResult<()> { async { Ok::<_, Infallible>(service_fn(move |req| { let inner = inner.clone(); - inner.handle(req) + inner.call(req) })) } }); @@ -59,7 +59,18 @@ impl InnerService { Self { args } } - pub async fn handle(self: Arc, req: Request) -> Result { + pub async fn call(self: Arc, req: Request) -> Result { + let method = req.method().clone(); + let uri = req.uri().clone(); + let res = self + .handle(req) + .await + .unwrap_or_else(|_| status_code!(StatusCode::INTERNAL_SERVER_ERROR)); + info!(r#""{} {}" - {}"#, method, uri, res.status()); + Ok(res) + } + + pub async fn handle(self: Arc, req: Request) -> BoxResult { if !self.auth_guard(&req).unwrap_or_default() { let mut res = status_code!(StatusCode::UNAUTHORIZED); res.headers_mut() @@ -67,7 +78,7 @@ impl InnerService { return Ok(res); } - let res = if req.method() == Method::GET { + if req.method() == Method::GET { self.handle_static(req).await } else if req.method() == Method::PUT { if self.args.readonly { @@ -78,8 +89,7 @@ impl InnerService { self.handle_delete(req).await } else { return Ok(status_code!(StatusCode::NOT_FOUND)); - }; - Ok(res.unwrap_or_else(|_| status_code!(StatusCode::INTERNAL_SERVER_ERROR))) + } } async fn handle_static(&self, req: Request) -> BoxResult {