|
| 1 | +use anyhow::Result; |
| 2 | +use clap::{Parser, Subcommand}; |
| 3 | +use serde::Deserialize; |
| 4 | + |
| 5 | +use super::executable::ExecutableCommand; |
| 6 | +use crate::config::CliConfig; |
| 7 | + |
| 8 | +/// Manage your registry account and view usage. |
| 9 | +#[derive(Parser, Debug, Clone)] |
| 10 | +pub struct AccountCommand { |
| 11 | + #[clap(subcommand)] |
| 12 | + pub subcommand: AccountSubcommand, |
| 13 | +} |
| 14 | + |
| 15 | +#[derive(Subcommand, Debug, Clone)] |
| 16 | +pub enum AccountSubcommand { |
| 17 | + /// Show account status and rate limits |
| 18 | + Status { |
| 19 | + /// Registry URL to query |
| 20 | + #[arg(long, default_value = "https://registry.auths.dev")] |
| 21 | + registry_url: String, |
| 22 | + }, |
| 23 | + /// Show API usage history |
| 24 | + Usage { |
| 25 | + /// Registry URL to query |
| 26 | + #[arg(long, default_value = "https://registry.auths.dev")] |
| 27 | + registry_url: String, |
| 28 | + /// Number of days to show |
| 29 | + #[arg(long, default_value = "7")] |
| 30 | + days: u32, |
| 31 | + }, |
| 32 | +} |
| 33 | + |
| 34 | +#[derive(Debug, Deserialize)] |
| 35 | +struct AccountStatusResponse { |
| 36 | + did: String, |
| 37 | + tier: String, |
| 38 | + daily_limit: i32, |
| 39 | + daily_used: i32, |
| 40 | + expires_at: Option<String>, |
| 41 | +} |
| 42 | + |
| 43 | +#[derive(Debug, Deserialize)] |
| 44 | +struct UsageEntry { |
| 45 | + date: String, |
| 46 | + request_count: i32, |
| 47 | +} |
| 48 | + |
| 49 | +fn handle_status(registry_url: &str) -> Result<()> { |
| 50 | + let url = registry_url.trim_end_matches('/'); |
| 51 | + |
| 52 | + println!("Fetching account status..."); |
| 53 | + |
| 54 | + let client = reqwest::blocking::Client::new(); |
| 55 | + let resp = client |
| 56 | + .get(format!("{url}/v1/account/status")) |
| 57 | + .send() |
| 58 | + .map_err(|e| anyhow::anyhow!("Failed to fetch account status: {e}"))?; |
| 59 | + |
| 60 | + if !resp.status().is_success() { |
| 61 | + return Err(anyhow::anyhow!("Registry returned {}", resp.status())); |
| 62 | + } |
| 63 | + |
| 64 | + let status: AccountStatusResponse = resp |
| 65 | + .json() |
| 66 | + .map_err(|e| anyhow::anyhow!("Failed to parse response: {e}"))?; |
| 67 | + |
| 68 | + println!("\nAccount Status:"); |
| 69 | + println!(" DID: {}", status.did); |
| 70 | + println!(" Tier: {}", status.tier); |
| 71 | + println!(" Daily Limit: {}", status.daily_limit); |
| 72 | + println!(" Daily Used: {}", status.daily_used); |
| 73 | + if let Some(expires) = status.expires_at { |
| 74 | + println!(" Expires: {expires}"); |
| 75 | + } |
| 76 | + |
| 77 | + Ok(()) |
| 78 | +} |
| 79 | + |
| 80 | +fn handle_usage(registry_url: &str, days: u32) -> Result<()> { |
| 81 | + let url = registry_url.trim_end_matches('/'); |
| 82 | + |
| 83 | + println!("Fetching usage history ({days} days)..."); |
| 84 | + |
| 85 | + let client = reqwest::blocking::Client::new(); |
| 86 | + let resp = client |
| 87 | + .get(format!("{url}/v1/account/usage?days={days}")) |
| 88 | + .send() |
| 89 | + .map_err(|e| anyhow::anyhow!("Failed to fetch usage: {e}"))?; |
| 90 | + |
| 91 | + if !resp.status().is_success() { |
| 92 | + return Err(anyhow::anyhow!("Registry returned {}", resp.status())); |
| 93 | + } |
| 94 | + |
| 95 | + let entries: Vec<UsageEntry> = resp |
| 96 | + .json() |
| 97 | + .map_err(|e| anyhow::anyhow!("Failed to parse response: {e}"))?; |
| 98 | + |
| 99 | + if entries.is_empty() { |
| 100 | + println!("\nNo usage data found."); |
| 101 | + return Ok(()); |
| 102 | + } |
| 103 | + |
| 104 | + println!("\nUsage History:"); |
| 105 | + for entry in &entries { |
| 106 | + println!(" {} -- {} requests", entry.date, entry.request_count); |
| 107 | + } |
| 108 | + |
| 109 | + Ok(()) |
| 110 | +} |
| 111 | + |
| 112 | +impl ExecutableCommand for AccountCommand { |
| 113 | + fn execute(&self, _ctx: &CliConfig) -> Result<()> { |
| 114 | + match &self.subcommand { |
| 115 | + AccountSubcommand::Status { registry_url } => handle_status(registry_url), |
| 116 | + AccountSubcommand::Usage { registry_url, days } => handle_usage(registry_url, *days), |
| 117 | + } |
| 118 | + } |
| 119 | +} |
0 commit comments