feat: add logger
This commit is contained in:
parent
e6ea7e4f75
commit
63e6906393
7 changed files with 126 additions and 33 deletions
64
Cargo.lock
generated
64
Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
```
|
```
|
||||||
|
|
|
@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
25
src/main.rs
25
src/main.rs
|
@ -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 {
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue