#![allow(clippy::type_complexity)]
#![deny(clippy::unwrap_used)]
#![deny(clippy::expect_used)]
use clap::{Args, Parser, Subcommand};
use monocle::utils::OutputFormat;
use monocle::*;
use tracing::Level;
mod commands;
use commands::as2rel::As2relArgs;
use commands::config::ConfigArgs;
use commands::country::CountryArgs;
use commands::inspect::InspectArgs;
use commands::ip::IpArgs;
use commands::parse::ParseArgs;
use commands::pfx2as::Pfx2asArgs;
use commands::rib::RibArgs;
use commands::rpki::RpkiCommands;
use commands::search::SearchArgs;
use commands::time::TimeArgs;
#[derive(Parser)]
#[clap(author, version, about, long_about = None)]
#[clap(propagate_version = true)]
struct Cli {
#[clap(short, long)]
config: Option<String>,
#[clap(long, global = true)]
debug: bool,
#[clap(long, global = true, value_name = "FORMAT")]
format: Option<OutputFormat>,
#[clap(long, global = true)]
json: bool,
#[clap(long, global = true)]
no_update: bool,
#[clap(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Parse(ParseArgs),
Search(SearchArgs),
Rib(RibArgs),
Server(ServerArgs),
Inspect(InspectArgs),
Country(CountryArgs),
Time(TimeArgs),
Rpki {
#[clap(subcommand)]
commands: RpkiCommands,
},
Ip(IpArgs),
As2rel(As2relArgs),
Pfx2as(Pfx2asArgs),
Config(ConfigArgs),
}
#[derive(Args, Debug, Clone)]
struct ServerArgs {
#[clap(long)]
address: Option<String>,
#[clap(long)]
port: Option<u16>,
#[clap(long)]
max_search_batch_size: Option<usize>,
#[clap(long)]
max_search_results: Option<u64>,
#[clap(long)]
concurrency: Option<usize>,
#[clap(long)]
search_timeout_secs: Option<u64>,
#[clap(long)]
max_concurrent_searches: Option<usize>,
#[clap(long)]
auth_enabled: Option<bool>,
#[clap(long)]
auth_token: Option<String>,
}
fn main() {
#[cfg(unix)]
{
unsafe {
libc::signal(libc::SIGPIPE, libc::SIG_DFL);
}
}
dotenvy::dotenv().ok();
let cli = Cli::parse();
let config = match MonocleConfig::new(&cli.config) {
Ok(c) => c,
Err(e) => {
eprintln!("Failed to load configuration: {}", e);
std::process::exit(1);
}
};
if cli.debug {
tracing_subscriber::fmt()
.with_max_level(Level::INFO)
.init();
}
let output_format = if let Some(fmt) = cli.format {
fmt
} else if cli.json {
OutputFormat::JsonPretty
} else {
OutputFormat::Table
};
let streaming_output_format = if let Some(fmt) = cli.format {
fmt
} else if cli.json {
OutputFormat::JsonPretty
} else {
OutputFormat::Psv
};
match cli.command {
Commands::Parse(args) => commands::parse::run(args, streaming_output_format),
Commands::Search(args) => commands::search::run(&config, args, streaming_output_format),
Commands::Rib(args) => {
commands::rib::run(&config, args, streaming_output_format, cli.no_update)
}
Commands::Server(args) => {
#[cfg(feature = "cli")]
{
let mut server_config = config.clone();
if let Some(addr) = args.address {
server_config.server_address = addr;
}
if let Some(port) = args.port {
server_config.server_port = port;
}
if let Some(v) = args.max_search_batch_size {
server_config.server_max_search_batch_size = v;
}
if let Some(v) = args.max_search_results {
server_config.server_max_search_results = v;
}
if let Some(v) = args.concurrency {
server_config.search_concurrency = v;
}
if let Some(v) = args.search_timeout_secs {
server_config.server_search_timeout_secs = v;
}
if let Some(v) = args.max_concurrent_searches {
server_config.server_max_concurrent_searches = v;
}
if let Some(v) = args.auth_enabled {
server_config.server_auth_enabled = v;
}
if let Some(v) = args.auth_token {
server_config.server_auth_token = v;
}
let rt = match tokio::runtime::Runtime::new() {
Ok(rt) => rt,
Err(e) => {
eprintln!("Failed to create tokio runtime for server: {e}");
std::process::exit(1);
}
};
if let Err(e) = rt.block_on(monocle::server::start_server(server_config)) {
eprintln!("Server failed: {e}");
std::process::exit(1);
}
}
#[cfg(not(feature = "cli"))]
{
let _ = args;
eprintln!("ERROR: server subcommand requires building with --features cli");
std::process::exit(2);
}
}
Commands::Inspect(args) => {
commands::inspect::run(&config, args, output_format, cli.no_update)
}
Commands::Time(args) => commands::time::run(args, output_format),
Commands::Country(args) => commands::country::run(args, output_format),
Commands::Rpki { commands } => {
commands::rpki::run(commands, output_format, &config, cli.no_update)
}
Commands::Ip(args) => commands::ip::run(args, output_format),
Commands::As2rel(args) => {
commands::as2rel::run(&config, args, output_format, cli.no_update)
}
Commands::Pfx2as(args) => {
commands::pfx2as::run(&config, args, output_format, cli.no_update)
}
Commands::Config(args) => commands::config::run(&config, args, output_format),
}
}