Skip to main content

usage_monitor_cli/
error.rs

1use thiserror::Error;
2
3fn rate_limited_message(provider: &str, retry_after: &Option<u64>) -> String {
4    match retry_after {
5        Some(secs) if *secs > 0 => format!("Rate limited by '{}', retry after {}s", provider, secs),
6        _ => format!("Rate limited by '{}', try again in a few minutes", provider),
7    }
8}
9
10#[derive(Error, Debug, Clone, PartialEq)]
11pub enum SpendPanelError {
12    #[error("Provider '{0}' not found")]
13    ProviderNotFound(String),
14
15    #[error("Authentication failed for '{0}': {1}")]
16    AuthFailed(String, String),
17
18    #[error("HTTP request failed: {0}")]
19    NetworkError(String),
20
21    #[error("{}", rate_limited_message(.0, .1))]
22    RateLimited(String, Option<u64>),
23
24    #[error("Failed to parse response from '{0}': {1}")]
25    ParseError(String, String),
26
27    #[error("Configuration error: {0}")]
28    ConfigError(String),
29
30    #[error("Provider '{0}' returned error: {1}")]
31    ProviderError(String, String),
32
33    #[error("Timeout fetching '{0}'")]
34    Timeout(String),
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn test_rate_limited_message_with_seconds() {
43        let e = SpendPanelError::RateLimited("claude".into(), Some(120));
44        assert_eq!(e.to_string(), "Rate limited by 'claude', retry after 120s");
45    }
46
47    #[test]
48    fn test_rate_limited_message_zero_seconds() {
49        let e = SpendPanelError::RateLimited("claude".into(), Some(0));
50        assert_eq!(
51            e.to_string(),
52            "Rate limited by 'claude', try again in a few minutes"
53        );
54    }
55
56    #[test]
57    fn test_rate_limited_message_no_seconds() {
58        let e = SpendPanelError::RateLimited("codex".into(), None);
59        assert_eq!(
60            e.to_string(),
61            "Rate limited by 'codex', try again in a few minutes"
62        );
63    }
64}