use clap::Parser;
use std::path::Path;
use tokio::runtime::Runtime;
use super::ServerContext;
use crate::config::Config;
use crate::error::{Error, ErrorKind};
use crate::log::init_log;
pub const DEFAULT_CONFIG: &str = "/etc/hebo/hebo.toml";
#[derive(Debug, Parser)]
#[command(name = "Hebo")]
#[command(author = "Xu Shaohua <shaohua@biofan.org>")]
#[command(version = "0.3.2")]
#[command(about = "High Performance MQTT Server", long_about = None)]
struct Arguments {
#[arg(short, long, value_name = "config_file")]
config: Option<String>,
#[arg(short, long)]
reload: bool,
#[arg(short, long)]
stop: bool,
#[arg(short, long)]
test: bool,
}
pub fn handle_cmdline() -> Result<(), Error> {
let args = Arguments::parse();
let config_file = if let Some(config_file) = args.config.as_deref() {
Some(config_file)
} else if Path::new(DEFAULT_CONFIG).exists() {
Some(DEFAULT_CONFIG)
} else {
None
};
let config = if let Some(config_file) = config_file {
let config_content = std::fs::read_to_string(config_file).map_err(|err| {
Error::from_string(
ErrorKind::ConfigError,
format!("Failed to read config file {config_file}, err: {err:?}"),
)
})?;
let config: Config = toml::from_str(&config_content).map_err(|err| {
Error::from_string(
ErrorKind::ConfigError,
format!("Invalid toml config file {config_file}, err: {err:?}"),
)
})?;
if args.test {
if let Err(err) = config.validate(false) {
eprintln!("Failed to validate config file!");
return Err(err);
}
println!("The configuration file {config_file} syntax is Ok");
return Ok(());
}
config
} else {
Config::default()
};
init_log(config.log())?;
let mut server = ServerContext::new(config);
if args.stop {
return server.send_stop_signal();
}
if args.reload {
return server.send_reload_signal();
}
let runtime = Runtime::new()?;
server.run_loop(&runtime)
}
#[allow(clippy::module_name_repetitions)]
pub fn run_server_with_config(config: Config) -> Result<(), Error> {
init_log(config.log())?;
let mut server = ServerContext::new(config);
let runtime = Runtime::new()?;
server.run_loop(&runtime)
}