|
|
|
|
|
|
|
use crate::handler::paths::{file_path, FileType}; |
|
|
|
use crate::models::parser_models::{AggregatorConfig, RateLimiter, Style}; |
|
use log::LevelFilter; |
|
use mlua::Lua; |
|
use std::{collections::HashMap, fs, thread::available_parallelism}; |
|
|
|
|
|
#[derive(Clone)] |
|
pub struct Config { |
|
|
|
pub port: u16, |
|
|
|
pub binding_ip: String, |
|
|
|
pub style: Style, |
|
|
|
|
|
pub redis_url: String, |
|
|
|
pub aggregator: AggregatorConfig, |
|
|
|
pub logging: bool, |
|
|
|
pub debug: bool, |
|
|
|
pub upstream_search_engines: Vec<crate::models::engine_models::EngineHandler>, |
|
|
|
pub request_timeout: u8, |
|
|
|
pub threads: u8, |
|
|
|
pub rate_limiter: RateLimiter, |
|
|
|
|
|
pub safe_search: u8, |
|
} |
|
|
|
impl Config { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub fn parse(logging_initialized: bool) -> Result<Self, Box<dyn std::error::Error>> { |
|
let lua = Lua::new(); |
|
let globals = lua.globals(); |
|
|
|
lua.load(&fs::read_to_string(file_path(FileType::Config)?)?) |
|
.exec()?; |
|
|
|
let parsed_threads: u8 = globals.get::<_, u8>("threads")?; |
|
|
|
let debug: bool = globals.get::<_, bool>("debug")?; |
|
let logging: bool = globals.get::<_, bool>("logging")?; |
|
|
|
if !logging_initialized { |
|
set_logging_level(debug, logging); |
|
} |
|
|
|
let threads: u8 = if parsed_threads == 0 { |
|
let total_num_of_threads: usize = available_parallelism()?.get() / 2; |
|
log::error!( |
|
"Config Error: The value of `threads` option should be a non zero positive integer" |
|
); |
|
log::error!("Falling back to using {} threads", total_num_of_threads); |
|
total_num_of_threads as u8 |
|
} else { |
|
parsed_threads |
|
}; |
|
|
|
let rate_limiter = globals.get::<_, HashMap<String, u8>>("rate_limiter")?; |
|
|
|
let parsed_safe_search: u8 = globals.get::<_, u8>("safe_search")?; |
|
let safe_search: u8 = match parsed_safe_search { |
|
0..=4 => parsed_safe_search, |
|
_ => { |
|
log::error!("Config Error: The value of `safe_search` option should be a non zero positive integer from 0 to 4."); |
|
log::error!("Falling back to using the value `1` for the option"); |
|
1 |
|
} |
|
}; |
|
|
|
Ok(Config { |
|
port: globals.get::<_, u16>("port")?, |
|
binding_ip: globals.get::<_, String>("binding_ip")?, |
|
style: Style::new( |
|
globals.get::<_, String>("theme")?, |
|
globals.get::<_, String>("colorscheme")?, |
|
), |
|
redis_url: globals.get::<_, String>("redis_url")?, |
|
aggregator: AggregatorConfig { |
|
random_delay: globals.get::<_, bool>("production_use")?, |
|
}, |
|
logging, |
|
debug, |
|
upstream_search_engines: globals |
|
.get::<_, HashMap<String, bool>>("upstream_search_engines")? |
|
.into_iter() |
|
.filter_map(|(key, value)| value.then_some(key)) |
|
.filter_map(|engine| crate::models::engine_models::EngineHandler::new(&engine)) |
|
.collect(), |
|
request_timeout: globals.get::<_, u8>("request_timeout")?, |
|
threads, |
|
rate_limiter: RateLimiter { |
|
number_of_requests: rate_limiter["number_of_requests"], |
|
time_limit: rate_limiter["time_limit"], |
|
}, |
|
safe_search, |
|
}) |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn set_logging_level(debug: bool, logging: bool) { |
|
if let Ok(pkg_env_var) = std::env::var("PKG_ENV") { |
|
if pkg_env_var.to_lowercase() == "dev" { |
|
env_logger::Builder::new() |
|
.filter(None, LevelFilter::Trace) |
|
.init(); |
|
return; |
|
} |
|
} |
|
|
|
|
|
let log_level = match (debug, logging) { |
|
(true, true) => LevelFilter::Debug, |
|
(true, false) => LevelFilter::Debug, |
|
(false, true) => LevelFilter::Info, |
|
(false, false) => LevelFilter::Error, |
|
}; |
|
|
|
env_logger::Builder::new().filter(None, log_level).init(); |
|
} |
|
|