usage_monitor_cli/
error.rs1use 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}