use chrono::{DateTime, Utc};
use clap::Parser;
use eyre::{Result, WrapErr};
use simulator_client::BacktestClient;
#[derive(Parser, Debug)]
pub struct UsageArgs {
#[arg(long)]
pub since: Option<String>,
#[arg(long)]
pub until: Option<String>,
#[arg(long)]
pub json: bool,
}
pub async fn usage(args: UsageArgs, url: String, api_key: String) -> Result<()> {
let since = args
.since
.as_deref()
.map(parse_datetime)
.transpose()
.wrap_err("invalid --since")?;
let until = args
.until
.as_deref()
.map(parse_datetime)
.transpose()
.wrap_err("invalid --until")?;
let client = BacktestClient::builder()
.url(format!("wss://{url}/backtest"))
.api_key(api_key)
.build();
let report = client.usage(since, until).await?;
if args.json {
println!("{}", serde_json::to_string_pretty(&report)?);
return Ok(());
}
println!("Usage Report");
println!(" API key: {}", report.api_key_name);
println!(
" Time range: {} to {}",
report.since.format("%Y-%m-%d %H:%M:%S UTC"),
report.until.format("%Y-%m-%d %H:%M:%S UTC"),
);
println!();
println!("Sessions");
println!(" Completed: {}", report.sessions.completed);
println!(" Incomplete: {}", report.sessions.failed);
println!();
println!("Compute");
println!(
" Slots executed: {}",
report.compute.executed_slot_count
);
let total_mins = report.compute.session_duration_ms / 60_000;
println!(
" Total session duration: {}h {}m",
total_mins / 60,
total_mins % 60,
);
Ok(())
}
fn parse_datetime(s: &str) -> Result<DateTime<Utc>> {
if let Ok(dt) = DateTime::parse_from_rfc3339(s) {
return Ok(dt.with_timezone(&Utc));
}
let date = chrono::NaiveDate::parse_from_str(s, "%Y-%m-%d")
.wrap_err_with(|| format!("cannot parse '{s}' as RFC 3339 or YYYY-MM-DD"))?;
Ok(date.and_hms_opt(0, 0, 0).unwrap().and_utc())
}