Skip to main content

ai_usagebar/
vendor.rs

1//! Shared vendor IDs and renderer/fetcher structs used by the widget and TUI.
2//!
3//! Snapshots remain a discriminated `VendorSnapshot` enum because the four
4//! vendors have genuinely different shapes — see `usage.rs`.
5
6use std::time::Duration;
7
8use clap::ValueEnum;
9
10use crate::usage::VendorSnapshot;
11use crate::widget::cli::Cli;
12
13/// Outer reqwest client timeout shared by widget and TUI entry points.
14/// Vendor fetchers still apply their own tighter per-request timeouts.
15pub const HTTP_CLIENT_TIMEOUT: Duration = Duration::from_secs(30);
16
17/// Stable enum used by `--vendor` and in config files.
18#[derive(
19    Debug, Clone, Copy, ValueEnum, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize,
20)]
21#[serde(rename_all = "lowercase")]
22pub enum VendorId {
23    Anthropic,
24    Openai,
25    Zai,
26    Openrouter,
27    Deepseek,
28}
29
30impl VendorId {
31    pub fn slug(self) -> &'static str {
32        match self {
33            VendorId::Anthropic => "anthropic",
34            VendorId::Openai => "openai",
35            VendorId::Zai => "zai",
36            VendorId::Openrouter => "openrouter",
37            VendorId::Deepseek => "deepseek",
38        }
39    }
40
41    pub fn all() -> &'static [VendorId] {
42        &[
43            VendorId::Anthropic,
44            VendorId::Openai,
45            VendorId::Zai,
46            VendorId::Openrouter,
47            VendorId::Deepseek,
48        ]
49    }
50}
51
52/// What a vendor returns from a successful fetch — snapshot + meta. Mirrors
53/// `anthropic::fetch::FetchOutcome` but vendor-agnostic.
54#[derive(Debug, Clone)]
55pub struct VendorOutcome {
56    pub snapshot: VendorSnapshot,
57    pub stale: bool,
58    pub last_error: Option<(u16, String)>,
59    pub cache_age: Option<std::time::Duration>,
60}
61
62/// Options forwarded to renderers from the CLI.
63#[derive(Debug, Clone)]
64pub struct RenderOpts {
65    pub format: Option<String>,
66    pub tooltip_format: Option<String>,
67    pub icon: Option<String>,
68    pub pace_tolerance: u32,
69    pub format_pace_color: bool,
70    pub tooltip_pace_pts: bool,
71}
72
73impl RenderOpts {
74    pub fn from_cli(cli: &Cli) -> Self {
75        Self {
76            format: cli.format.clone(),
77            tooltip_format: cli.tooltip_format.clone(),
78            icon: cli.icon.clone(),
79            pace_tolerance: cli.pace_tolerance,
80            format_pace_color: cli.format_pace_color,
81            tooltip_pace_pts: cli.tooltip_pace_pts,
82        }
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    #[test]
91    fn vendor_id_slug_round_trip() {
92        for id in VendorId::all() {
93            assert_eq!(
94                id.slug(),
95                serde_json::to_value(id).unwrap().as_str().unwrap()
96            );
97        }
98    }
99}