use std::path::Path;
use log::*;
use simple_logger::SimpleLogger;
use shvrpc::util::parse_log_verbosity;
use clap::{Parser};
use shvbroker::{brokerimpl::BrokerImpl, config::{AccessConfig, BrokerConfig, SharedBrokerConfig}, sql::{self}};
#[derive(Parser, Debug)]
struct CliOpts {
#[arg(long)]
version: bool,
#[arg(short, long)]
config: Option<String>,
#[arg(long)]
print_config: bool,
#[arg(short, long)]
data_directory: Option<String>,
#[arg(short = 'b', long)]
use_access_db: bool,
#[arg(long)]
no_use_access_db: bool,
#[arg(long)]
tunneling: bool,
#[arg(long)]
no_tunneling: bool,
#[arg(long = "shv2")]
shv2_compatibility: bool,
#[arg(long = "no-shv2")]
no_shv2_compatibility: bool,
#[arg(short = 'v', long = "verbose")]
verbose: Option<String>,
}
pub(crate) fn main() -> shvrpc::Result<()> {
const SMOL_THREADS: &str = "SMOL_THREADS";
if std::env::var(SMOL_THREADS).is_err_and(|e| matches!(e, std::env::VarError::NotPresent))
&& let Ok(num_threads) = std::thread::available_parallelism() {
unsafe {
std::env::set_var(SMOL_THREADS, num_threads.to_string());
}
}
let cli_opts = CliOpts::parse();
if cli_opts.version {
println!("{}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
let mut logger = SimpleLogger::new().with_level(LevelFilter::Info);
if let Some(module_names) = cli_opts.verbose {
for (module, level) in parse_log_verbosity(&module_names, module_path!()) {
if let Some(module) = module {
logger = logger.with_module_level(module, level);
} else {
logger = logger.with_level(level);
}
}
}
logger.init().unwrap();
info!("=====================================================");
info!("{} ver. {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
info!("=====================================================");
let mut config = if let Some(config_file) = &cli_opts.config {
info!("Loading config file {config_file}");
match BrokerConfig::from_file(config_file) {
Ok(config) => {config}
Err(err) => {
return Err(err);
}
}
} else {
info!("Using default config");
BrokerConfig::default()
};
if cli_opts.data_directory.is_some() {
config.data_directory = cli_opts.data_directory;
}
config.shv2_compatibility |= cli_opts.shv2_compatibility;
config.shv2_compatibility &= !cli_opts.no_shv2_compatibility;
config.tunnelling.enabled |= cli_opts.tunneling;
config.tunnelling.enabled &= !cli_opts.no_tunneling;
config.use_access_db |= cli_opts.use_access_db;
config.use_access_db &= !cli_opts.no_use_access_db;
if config.shv2_compatibility {
info!("Running in SHV2 compatibility mode");
}
let (access, sql_connection) = if config.use_access_db {
let data_dir = config.data_directory.clone().unwrap_or("/tmp/shvbroker/data".to_owned());
info!("Data directory: {}", data_dir);
let sql_config_file = Path::new(&data_dir).join("shvbroker.sqlite");
let (sql_connection, access_config) = smol::block_on( sql::migrate_sqlite_connection(&sql_config_file, &config.access))?;
(access_config, Some(sql_connection))
} else {
(config.access.clone(), None)
};
if cli_opts.print_config {
print_config(&config, &access)?;
return Ok(());
}
info!("-----------------------------------------------------");
let broker_impl = BrokerImpl::new(SharedBrokerConfig::new(config), access, sql_connection);
smol::block_on(shvbroker::brokerimpl::run_broker(broker_impl))
}
fn print_config(config: &BrokerConfig, access: &AccessConfig) -> shvrpc::Result<()> {
let mut config = config.clone();
config.access = access.clone();
println!("{}", &serde_yaml::to_string(&config)?);
Ok(())
}