use clap::{CommandFactory, Parser, Subcommand, parser::ValueSource};
use macmon::{App, Sampler, debug};
use std::error::Error;
use std::sync::{Arc, Mutex};
use std::thread;
mod serve;
#[derive(Debug, Subcommand)]
enum Commands {
#[command(alias = "raw")]
Pipe {
#[arg(short, long, default_value_t = 0)]
samples: u32,
#[arg(long, default_value_t = false)]
soc_info: bool,
},
Serve {
#[arg(short, long, default_value_t = 9090)]
port: u16,
#[arg(long, default_value_t = false)]
install: bool,
#[arg(long, default_value_t = false)]
uninstall: bool,
},
Debug,
}
#[derive(Debug, Parser)]
#[command(version, verbatim_doc_comment)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
#[arg(short, long, global = true, default_value_t = 1000)]
interval: u32,
}
fn main() -> Result<(), Box<dyn Error>> {
let args = Cli::parse();
match &args.command {
Some(Commands::Pipe { samples, soc_info }) => {
let mut sampler = Sampler::new()?;
let mut counter = 0u32;
let soc_info_val = if *soc_info { Some(sampler.get_soc_info().clone()) } else { None };
loop {
let doc = sampler.get_metrics(args.interval.max(100))?;
let mut doc = serde_json::to_value(&doc)?;
if let Some(ref soc) = soc_info_val {
doc["soc"] = serde_json::to_value(soc)?;
}
doc["timestamp"] = serde_json::to_value(chrono::Utc::now().to_rfc3339())?;
let doc = serde_json::to_string(&doc)?;
println!("{}", doc);
counter += 1;
if *samples > 0 && counter >= *samples {
break;
}
}
}
Some(Commands::Serve { port, install, uninstall }) => {
if *install || *uninstall {
serve::launchd(*port, *install)?;
return Ok(());
}
let mut sampler = Sampler::new()?;
let soc = Arc::new(sampler.get_soc_info().clone());
let shared: serve::SharedMetrics = Arc::new(Mutex::new(None));
let shared_http = Arc::clone(&shared);
let soc_http = Arc::clone(&soc);
let port = *port;
thread::spawn(move || {
if let Err(e) = serve::run(port, shared_http, soc_http) {
eprintln!("server error: {e}");
}
});
loop {
match sampler.get_metrics(args.interval.max(100)) {
Ok(m) => *shared.lock().unwrap() = Some(m),
Err(e) => eprintln!("sampling error: {e}"),
}
}
}
Some(Commands::Debug) => debug::print_debug()?,
_ => {
let mut app = App::new()?;
let matches = Cli::command().get_matches();
let msec = match matches.value_source("interval") {
Some(ValueSource::CommandLine) => Some(args.interval),
_ => None,
};
app.run_loop(msec)?;
}
}
Ok(())
}