diff --git a/Cargo.lock b/Cargo.lock index 484511b..9dda97c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -872,26 +872,6 @@ dependencies = [ "syn 2.0.71", ] -[[package]] -name = "tsr" -version = "0.1.8" -dependencies = [ - "async-mutex", - "chrono", - "clap", - "ipnet", - "lazy_static", - "log", - "log4rs", - "lru", - "mime", - "mime_guess", - "serde", - "serde_yml", - "tokio", - "urlencoding", -] - [[package]] name = "typemap-ors" version = "1.0.0" @@ -1198,3 +1178,23 @@ dependencies = [ "quote", "syn 2.0.71", ] + +[[package]] +name = "zest" +version = "0.1.8" +dependencies = [ + "async-mutex", + "chrono", + "clap", + "ipnet", + "lazy_static", + "log", + "log4rs", + "lru", + "mime", + "mime_guess", + "serde", + "serde_yml", + "tokio", + "urlencoding", +] diff --git a/Cargo.toml b/Cargo.toml index 6f9ff67..f5276c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "tsr" +name = "zest" version = "0.1.8" edition = "2021" diff --git a/README.md b/README.md index 027ee7e..721221c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## Rusted HTTP Server [![Rust](https://github.com/kfatyuip/tsr/actions/workflows/rust.yml/badge.svg)](https://github.com/kfatyuip/tsr/actions/workflows/rust.yml) +## Rusted HTTP Server [![Rust](https://github.com/kfatyuip/zest/actions/workflows/rust.yml/badge.svg)](https://github.com/kfatyuip/zest/actions/workflows/rust.yml) **Features** @@ -37,8 +37,8 @@ locations: # optional index: index.html logging: # optional - access_log: /var/log/tsr/access.log - error_log: /var/log/tsr/error.log + access_log: /var/log/zest/access.log + error_log: /var/log/zest/error.log ``` **Benchmark (wrk)** diff --git a/src/config.rs b/src/config.rs index 5f6cfc5..350ad94 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use clap::{command, Parser}; use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use serde_yml::Value; @@ -49,7 +50,7 @@ impl Default for Config { Config { bind: BindConfig { addr: "0.0.0.0".to_owned(), - listen: 80, + listen: 8080, }, server: ServerConfig { info: "Powered by Rust".to_owned(), @@ -65,16 +66,40 @@ impl Default for Config { } } +#[derive(Parser)] +#[command(version, about, long_about = None)] +pub struct Args { + #[arg(short, long, default_value = None, help = "set config file path")] + pub config: Option, + + #[arg(short, long, default_value = None, help = "set the root directory")] + pub root: Option, + + #[arg(short, long, default_value = None, help = "set the listening port")] + pub port: Option, +} + lazy_static! { pub static ref CONFIG_PATH: Mutex = Mutex::new("".to_owned()); pub static ref CONFIG: Config = init_config(); + pub static ref ARGS: Args = Args::parse(); } fn init_config() -> Config { let config_path = CONFIG_PATH.lock().unwrap(); let default_config = Config::default(); - match fs::read_to_string(config_path.to_owned()) { + let mut config = match fs::read_to_string(config_path.to_owned()) { Ok(conf) => serde_yml::from_str(&conf).unwrap_or(default_config), _ => default_config, + }; + + if let Some(root) = &ARGS.root { + config.server.root = root.to_path_buf(); + } + + if let Some(port) = &ARGS.port { + config.bind.listen = *port; } + + config } diff --git a/src/main.rs b/src/main.rs index dc54f9d..f1f93f2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,9 @@ -use tsr::{ - config::{CONFIG, CONFIG_PATH}, +use zest::{ + config::{Config, ARGS, CONFIG, CONFIG_PATH}, route::{location_index, mime_match, root_relative, status_page}, }; use chrono::{DateTime, Utc}; -use clap::Parser; use mime::Mime; use std::{ collections::HashMap, env::set_current_dir, error::Error, io, ops::Deref, path::Path, sync::Arc, @@ -37,7 +36,7 @@ use tokio::{ const DATE_FORMAT: &str = "%a, %d %b %Y %H:%M:%S GMT"; #[cfg(feature = "log")] -const LOG_FORMAT: &str = "[{d(%Y-%m-%dT%H:%M:%SZ)} {h({l})} tsr] {m}\n"; +const LOG_FORMAT: &str = "[{d(%Y-%m-%dT%H:%M:%SZ)} {h({l})} zest] {m}\n"; #[cfg(feature = "lru_cache")] lazy_static! { @@ -99,7 +98,11 @@ where _headers_buffer: HashMap::new(), }; - let server_info = format!("TSR/{} ({})", env!("CARGO_PKG_VERSION"), config.server.info); + let server_info = format!( + "Zest/{} ({})", + env!("CARGO_PKG_VERSION"), + config.server.info + ); response.send_header("Server", server_info.clone()); response.send_header("Date", Utc::now().format(DATE_FORMAT)); @@ -211,112 +214,100 @@ where Ok((response.status_code, req)) } -#[derive(Parser)] -#[command(version, about, long_about = None)] -struct Args { - #[arg(short, long, default_value = None, help = "set config file path")] - config: Option, +#[inline] +fn init_logger(config: Config) { + use log4rs::{ + append::{console::ConsoleAppender, file::FileAppender}, + config::{Appender, Logger, Root}, + encode::pattern::PatternEncoder, + Config, + }; + + let mut builder = Config::builder(); + + let stdout = ConsoleAppender::builder() + .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) + .target(log4rs::append::console::Target::Stdout) + .build(); + + let stderr = ConsoleAppender::builder() + .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) + .target(log4rs::append::console::Target::Stderr) + .build(); + + if let Some(logging) = &config.logging { + builder = if let Some(access_log) = &logging.access_log { + let access_log_path = Path::new(&access_log); + std::fs::File::create(access_log_path).unwrap(); + builder.appender( + Appender::builder().build( + "logfile_access", + Box::new( + FileAppender::builder() + .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) + .build(access_log_path) + .unwrap(), + ), + ), + ) + } else { + builder.appender(Appender::builder().build("logfile_access", Box::new(stdout))) + }; - #[arg(short, long, default_value = None, help = "set the listening port")] - port: Option, + builder = if let Some(error_log) = &logging.error_log { + let error_log_path = Path::new(&error_log); + std::fs::File::create(error_log_path).unwrap(); + builder.appender( + Appender::builder().build( + "logfile_error", + Box::new( + FileAppender::builder() + .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) + .build(error_log_path) + .unwrap(), + ), + ), + ) + } else { + builder.appender(Appender::builder().build("logfile_error", Box::new(stderr))) + } + } else { + builder = builder + .appender(Appender::builder().build("logfile_access", Box::new(stdout))) + .appender(Appender::builder().build("logfile_error", Box::new(stderr))); + } + + let config = builder + .logger( + Logger::builder() + .appender("logfile_access") + .additive(false) + .build("access", log::LevelFilter::Info), + ) + .logger( + Logger::builder() + .appender("logfile_error") + .additive(false) + .build("error", log::LevelFilter::Error), + ) + .build(Root::builder().build(log::LevelFilter::Off)) + .unwrap(); + + log4rs::init_config(config).unwrap(); } #[tokio::main] async fn main() -> Result<(), Box> { - let arg = Args::parse(); - *CONFIG_PATH.lock()? = arg.config.unwrap_or(String::new()); + *CONFIG_PATH.lock()? = ARGS.config.clone().unwrap_or_default(); let config = CONFIG.deref(); set_current_dir(config.clone().server.root)?; #[cfg(feature = "log")] - { - use log4rs::{ - append::{console::ConsoleAppender, file::FileAppender}, - config::{Appender, Logger, Root}, - encode::pattern::PatternEncoder, - Config, - }; - - let mut builder = Config::builder(); - - let stdout = ConsoleAppender::builder() - .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) - .target(log4rs::append::console::Target::Stdout) - .build(); - - let stderr = ConsoleAppender::builder() - .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) - .target(log4rs::append::console::Target::Stderr) - .build(); - - if let Some(logging) = &config.logging { - builder = if let Some(access_log) = &logging.access_log { - let access_log_path = Path::new(&access_log); - std::fs::File::create(access_log_path).unwrap(); - builder.appender( - Appender::builder().build( - "logfile_access", - Box::new( - FileAppender::builder() - .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) - .build(access_log_path) - .unwrap(), - ), - ), - ) - } else { - builder.appender(Appender::builder().build("logfile_access", Box::new(stdout))) - }; - - builder = if let Some(error_log) = &logging.error_log { - let error_log_path = Path::new(&error_log); - std::fs::File::create(error_log_path).unwrap(); - builder.appender( - Appender::builder().build( - "logfile_error", - Box::new( - FileAppender::builder() - .encoder(Box::new(PatternEncoder::new(LOG_FORMAT))) - .build(error_log_path) - .unwrap(), - ), - ), - ) - } else { - builder.appender(Appender::builder().build("logfile_error", Box::new(stderr))) - } - } else { - builder = builder - .appender(Appender::builder().build("logfile_access", Box::new(stdout))) - .appender(Appender::builder().build("logfile_error", Box::new(stderr))); - } - - let config = builder - .logger( - Logger::builder() - .appender("logfile_access") - .additive(false) - .build("access", log::LevelFilter::Info), - ) - .logger( - Logger::builder() - .appender("logfile_error") - .additive(false) - .build("error", log::LevelFilter::Error), - ) - .build(Root::builder().build(log::LevelFilter::Off)) - .unwrap(); - - log4rs::init_config(config).unwrap(); - } + init_logger(config.clone()); - let listener = TcpListener::bind(format!( - "{}:{}", - config.bind.addr, - arg.port.unwrap_or(config.bind.listen) - )) - .await?; + let listener = + TcpListener::bind(format!("{}:{}", config.bind.addr, config.bind.listen)).await?; let mut _allowlist: Option> = config.clone().allowlist; let mut _blocklist: Option> = config.clone().blocklist;