]> OzVa Git service - ozva-cloud/commitdiff
feat: add logger
authorsigoden <sigoden@gmail.com>
Fri, 27 May 2022 01:01:16 +0000 (09:01 +0800)
committersigoden <sigoden@gmail.com>
Fri, 27 May 2022 01:21:17 +0000 (09:21 +0800)
Cargo.lock
Cargo.toml
README.md
src/args.rs
src/index.html
src/main.rs
src/server.rs

index e9dbd225137570818f14ba672d8e69cf0126879c..5a980b8aa68ee304bfe7d7e73196fd8cde3b32e3 100644 (file)
@@ -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"
index 3f763080a23677a36922ab2911b8c4323b076d3d..dd785e2832177c26010554aa556a3204a64d7f9c 100644 (file)
@@ -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
index 94d1f1789cfd59e8e93eaa30ec6c2c0d0e487db0..38f00f41d354389a2de54eb2152988a979cfcf08 100644 (file)
--- 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
 ```
index 4fdeba8f9b5200d8683676707d689b63dcdc0b59..8771c2616c779851c22a977532071c11bc4702d8 100644 (file)
@@ -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<String>,
+    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,
         })
     }
 
index f095e2cae37f0fd2d0476b39f4d3ca5132aee6ff..552beef0549ffbab400fa931ab0bfd33913dae4f 100644 (file)
@@ -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);
       }
         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 = `<strike>${this.file.name}</strike>`;
       }
     }
 
     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() {
index 5e5f17412988e3f11ea5fe15b913d5a96b08c6b7..208eb169ab88d493c0e7dbc586ffb01ca3d3fedf 100644 (file)
@@ -4,21 +4,36 @@ macro_rules! bail {
     }
 }
 
+#[macro_use]
+extern crate log;
+
 mod args;
 mod server;
 
 pub type BoxResult<T> = Result<T, Box<dyn std::error::Error>>;
 
+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<T>(err: Box<dyn std::error::Error>) -> T {
index 18e77877aedb32a516701bf1ecd550c8162e1cea..41b6d7642ab39d576cfa3f6f4d91078c59dd6e7b 100644 (file)
@@ -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<Self>, req: Request) -> Result<Response, hyper::Error> {
+    pub async fn call(self: Arc<Self>, req: Request) -> Result<Response, hyper::Error> {
+        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<Self>, req: Request) -> BoxResult<Response> {
         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<Response> {