feat: add logger

This commit is contained in:
sigoden 2022-05-27 09:01:16 +08:00
parent e6ea7e4f75
commit 63e6906393
7 changed files with 126 additions and 33 deletions

64
Cargo.lock generated
View file

@ -2,6 +2,17 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 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]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.1.0" version = "1.1.0"
@ -54,6 +65,17 @@ dependencies = [
"os_str_bytes", "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]] [[package]]
name = "duf" name = "duf"
version = "0.1.0" version = "0.1.0"
@ -62,9 +84,11 @@ dependencies = [
"clap", "clap",
"futures", "futures",
"hyper", "hyper",
"log",
"percent-encoding", "percent-encoding",
"serde", "serde",
"serde_json", "serde_json",
"simple_logger",
"tokio", "tokio",
"tokio-util", "tokio-util",
] ]
@ -301,6 +325,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "num_threads"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.12.0" version = "1.12.0"
@ -386,6 +419,19 @@ dependencies = [
"serde", "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]] [[package]]
name = "slab" name = "slab"
version = "0.4.6" version = "0.4.6"
@ -419,6 +465,24 @@ version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" 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]] [[package]]
name = "tokio" name = "tokio"
version = "1.18.2" version = "1.18.2"

View file

@ -20,7 +20,9 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
tokio-util = { version = "0.7", features = ["codec", "io-util"] } tokio-util = { version = "0.7", features = ["codec", "io-util"] }
futures = "0.3" futures = "0.3"
base64 = "0.13.0" base64 = "0.13"
log = "0.4"
simple_logger = "2.1.0"
[profile.release] [profile.release]
lto = true lto = true

View file

@ -10,8 +10,9 @@ Duf is a simple file server.
## Features ## Features
- Serve static files - Serve static files
- Upload/Delete files - Upload files
- Support basic auth - Delete files
- Basic authentication
- Easy to use with curl - Easy to use with curl
## Install ## Install
@ -44,7 +45,7 @@ Finally, run this command to see a list of all available option
## Curl ### Curl
Download a file Download a file
``` ```

View file

@ -40,6 +40,10 @@ fn app() -> clap::Command<'static> {
.help("Authenticate with user and pass") .help("Authenticate with user and pass")
.value_name("user: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!() clap::command!()
.about(ABOUT) .about(ABOUT)
.arg(arg_address) .arg(arg_address)
@ -47,6 +51,7 @@ fn app() -> clap::Command<'static> {
.arg(arg_path) .arg(arg_path)
.arg(arg_readonly) .arg(arg_readonly)
.arg(arg_auth) .arg(arg_auth)
.arg(arg_no_log)
} }
pub fn matches() -> ArgMatches { pub fn matches() -> ArgMatches {
@ -60,6 +65,7 @@ pub struct Args {
pub path: PathBuf, pub path: PathBuf,
pub readonly: bool, pub readonly: bool,
pub auth: Option<String>, pub auth: Option<String>,
pub log: bool,
} }
impl Args { impl Args {
@ -74,6 +80,7 @@ impl Args {
let path = Args::parse_path(path)?; let path = Args::parse_path(path)?;
let readonly = matches.is_present("readonly"); let readonly = matches.is_present("readonly");
let auth = matches.value_of("auth").map(|v| v.to_owned()); let auth = matches.value_of("auth").map(|v| v.to_owned());
let log = !matches.is_present("no-log");
Ok(Args { Ok(Args {
address, address,
@ -81,6 +88,7 @@ impl Args {
path, path,
readonly, readonly,
auth, auth,
log,
}) })
} }

View file

@ -59,8 +59,8 @@
const ajax = new XMLHttpRequest(); const ajax = new XMLHttpRequest();
ajax.upload.addEventListener("progress", e => this.progress(e), false); ajax.upload.addEventListener("progress", e => this.progress(e), false);
ajax.addEventListener("load", e => this.complete(e), false); ajax.addEventListener("load", e => this.complete(e), false);
ajax.addEventListener("error", e => this.error(e), false); ajax.addEventListener("error", e => this.fail(e), false);
ajax.addEventListener("abort", e => this.abort(e), false); ajax.addEventListener("abort", e => this.fail(e), false);
ajax.open("PUT", path); ajax.open("PUT", path);
ajax.send(file); ajax.send(file);
} }
@ -74,12 +74,8 @@
this.$elem.innerHTML = `${this.file.name}`; this.$elem.innerHTML = `${this.file.name}`;
} }
error(event) { fail(event) {
this.$elem.innerHTML = `${this.file.name} (x)`; this.$elem.innerHTML = `<strike>${this.file.name}</strike>`;
}
abort(event) {
this.$elem.innerHTML = `${this.file.name} (x)`;
} }
} }
@ -126,18 +122,15 @@
async function deletePath(index) { async function deletePath(index) {
const file = paths[index]; const file = paths[index];
if (!file) return; if (!file) return;
try {
const res = await fetch(encodeURI(file.path), { const ajax = new XMLHttpRequest();
method: "DELETE", ajax.open("DELETE", encodeURI(file.path));
}); ajax.addEventListener("readystatechange", function() {
if (res.status !== 200) { if(ajax.readyState === 4 && ajax.status === 200) {
const text = await res.text();
throw new Error(text);
}
document.getElementById(`addPath${index}`).remove(); document.getElementById(`addPath${index}`).remove();
} catch (err) {
alert(`Failed to delete ${file.name}, ${err.message}`);
} }
});
ajax.send();
} }
function addUploadControl() { function addUploadControl() {

View file

@ -4,21 +4,36 @@ macro_rules! bail {
} }
} }
#[macro_use]
extern crate log;
mod args; mod args;
mod server; mod server;
pub type BoxResult<T> = Result<T, Box<dyn std::error::Error>>; pub type BoxResult<T> = Result<T, Box<dyn std::error::Error>>;
use log::LevelFilter;
use crate::args::{matches, Args}; use crate::args::{matches, Args};
use crate::server::serve; use crate::server::serve;
#[tokio::main] #[tokio::main]
async fn main() { async fn main() {
Args::parse(matches()) run().await.unwrap_or_else(handle_err)
.map(serve) }
.unwrap_or_else(handle_err)
.await async fn run() -> BoxResult<()> {
.unwrap_or_else(handle_err); 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 { fn handle_err<T>(err: Box<dyn std::error::Error>) -> T {

View file

@ -37,7 +37,7 @@ pub async fn serve(args: Args) -> BoxResult<()> {
async { async {
Ok::<_, Infallible>(service_fn(move |req| { Ok::<_, Infallible>(service_fn(move |req| {
let inner = inner.clone(); let inner = inner.clone();
inner.handle(req) inner.call(req)
})) }))
} }
}); });
@ -59,7 +59,18 @@ impl InnerService {
Self { args } 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() { if !self.auth_guard(&req).unwrap_or_default() {
let mut res = status_code!(StatusCode::UNAUTHORIZED); let mut res = status_code!(StatusCode::UNAUTHORIZED);
res.headers_mut() res.headers_mut()
@ -67,7 +78,7 @@ impl InnerService {
return Ok(res); return Ok(res);
} }
let res = if req.method() == Method::GET { if req.method() == Method::GET {
self.handle_static(req).await self.handle_static(req).await
} else if req.method() == Method::PUT { } else if req.method() == Method::PUT {
if self.args.readonly { if self.args.readonly {
@ -78,8 +89,7 @@ impl InnerService {
self.handle_delete(req).await self.handle_delete(req).await
} else { } else {
return Ok(status_code!(StatusCode::NOT_FOUND)); 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> { async fn handle_static(&self, req: Request) -> BoxResult<Response> {