use clap::{Arg, ArgAction, Command};
fn build_version_info() -> String {
let mut s = String::new();
s.push_str("quant1x - Rust edition\n");
s.push_str("--------------------------------------------------------------------------------\n");
s.push_str(&format!(" Version : {}\n", env!("CARGO_PKG_VERSION")));
s.push_str(&format!(" Author : {}\n", env!("CARGO_PKG_AUTHORS")));
s.push_str("--------------------------------------------------------------------------------\n");
s
}
fn main() {
let program_name = std::env::current_exe()
.ok()
.and_then(|p| p.file_name().map(|n| n.to_string_lossy().to_string()))
.unwrap_or_else(|| String::from("quant1x"));
let program_version = build_version_info();
let service_sub = Command::new("service")
.about("Manage the service.")
.arg(Arg::new("action").value_parser(["install","uninstall","start","stop","status","run"]).required(true))
.arg(Arg::new("pipe").long("pipe").action(ArgAction::SetTrue))
.arg(Arg::new("elevated-out").long("elevated-out").num_args(1))
.arg(Arg::new("elevated-pipe").long("elevated-pipe").num_args(1));
let update_sub = Command::new("update")
.about("Update cached data (base / features)")
.arg(Arg::new("calendar").long("calendar").action(ArgAction::SetTrue).help("Only update calendar cache"))
.arg(Arg::new("servers").long("servers").action(ArgAction::SetTrue).help("Only detect and update level1 servers cache"))
.arg(Arg::new("all").long("all").action(ArgAction::SetTrue).help("Update everything (default)"))
.arg(Arg::new("base").long("base").num_args(1..).value_name("KEY").help("Update base data keys (e.g. xdxr)").value_parser(clap::builder::NonEmptyStringValueParser::new()))
.arg(Arg::new("features").long("features").num_args(1..).value_name("KEY").help("Update feature datasets (derived data)").value_parser(clap::builder::NonEmptyStringValueParser::new()));
let program_name_static: &'static str = Box::leak(program_name.into_boxed_str());
let program_version_static: &'static str = Box::leak(program_version.into_boxed_str());
let mut app = Command::new(program_name_static)
.long_about(program_version_static)
.arg(Arg::new("verbose").long("verbose").action(ArgAction::SetTrue).help("显示日志信息到终端"))
.arg(Arg::new("debug").long("debug").action(ArgAction::SetTrue).help("打开日志的调试模式"))
.subcommand_required(false)
.subcommand(service_sub)
.subcommand(update_sub);
let matches = app.clone().get_matches();
let verbose = matches.get_flag("verbose");
let debug = matches.get_flag("debug");
if let Err(e) = call_runtime_global_init() {
log::error!("runtime::global_init failed: {}", e);
}
if let Err(e) = call_datasets_init() {
log::error!("datasets::init failed: {}", e);
}
let _ = call_logger_set(verbose, debug);
let _ = call_engine_init();
if let Some((name, subm)) = matches.subcommand() {
if name == "service" {
let action = subm.get_one::<String>("action").map(|s| s.as_str()).unwrap_or("");
let pipe = subm.get_flag("pipe");
let elevated_out = subm.get_one::<String>("elevated-out").map(|s| s.to_string());
let elevated_pipe = subm.get_one::<String>("elevated-pipe").map(|s| s.to_string());
let code = call_engine_daemon(action, pipe, elevated_out.as_deref(), elevated_pipe.as_deref());
std::process::exit(code);
}
}
if let Some((name, subm)) = matches.subcommand() {
if name != "service" {
match lib_bridge::try_run_subcommand(name, subm) {
Ok(true) => {
return;
}
Ok(false) => {
log::error!("Error: Command '{}' not implemented in Rust library.\n", name);
app.print_help().ok();
std::process::exit(1);
}
Err(err) => {
log::error!("Error running subcommand '{}': {}", name, err);
std::process::exit(1);
}
}
}
}
log::error!("Error: No command provided.");
app.print_help().ok();
std::process::exit(1);
}
fn call_runtime_global_init() -> Result<(), String> {
quant1x::global_init();
Ok(())
}
fn call_datasets_init() -> Result<(), String> {
quant1x::datasets_init();
Ok(())
}
fn call_logger_set(verbose: bool, debug: bool) -> Result<(), String> {
quant1x::logger_set(verbose, debug);
Ok(())
}
fn call_engine_init() -> Result<(), String> {
quant1x::engine_init();
Ok(())
}
fn call_engine_daemon(action: &str, pipe: bool, elevated_out: Option<&str>, elevated_pipe: Option<&str>) -> i32 {
quant1x::engine_daemon(action, pipe, elevated_out, elevated_pipe)
}
mod lib_bridge {
use clap::ArgMatches;
use std::error::Error;
pub fn try_run_subcommand(name: &str, matches: &ArgMatches) -> Result<bool, Box<dyn Error>> {
quant1x::try_run_subcommand(name, matches)
}
}