koios_sdk/client/
config.rs

1// src/client/config.rs
2
3use crate::network::Network;
4use governor::Quota;
5use std::time::Duration;
6
7/// Authentication configuration for the client
8#[derive(Debug, Clone)]
9pub struct AuthConfig {
10    /// JWT Bearer token
11    pub token: String,
12    /// Optional expiry time for the token
13    pub expiry: Option<chrono::DateTime<chrono::Utc>>,
14}
15
16impl AuthConfig {
17    /// Create a new auth configuration with just a token
18    pub fn new(token: String) -> Self {
19        Self {
20            token,
21            expiry: None,
22        }
23    }
24
25    /// Create a new auth configuration with token and expiry
26    pub fn with_expiry(token: String, expiry: chrono::DateTime<chrono::Utc>) -> Self {
27        Self {
28            token,
29            expiry: Some(expiry),
30        }
31    }
32
33    /// Check if the token is still valid
34    pub fn is_valid(&self) -> bool {
35        match self.expiry {
36            Some(expiry) => chrono::Utc::now() < expiry,
37            None => true,
38        }
39    }
40}
41
42/// Configuration options for the Koios client
43#[derive(Debug, Clone)]
44pub struct Config {
45    /// Network to connect to
46    pub network: Network,
47    /// Optional custom base URL (overrides network URL)
48    pub custom_url: Option<String>,
49    /// Authentication configuration (if required)
50    pub auth: Option<AuthConfig>,
51    /// Request timeout
52    pub timeout: Duration,
53    /// Rate limiting quota
54    pub rate_limit: Quota,
55}
56
57impl Config {
58    /// Create a new configuration with custom settings
59    pub fn new(
60        network: Network,
61        custom_url: Option<String>,
62        auth: Option<AuthConfig>,
63        timeout: Duration,
64        rate_limit: Quota,
65    ) -> Self {
66        Self {
67            network,
68            custom_url,
69            auth,
70            timeout,
71            rate_limit,
72        }
73    }
74
75    /// Get the base URL to use
76    pub fn base_url(&self) -> String {
77        self.custom_url
78            .clone()
79            .unwrap_or_else(|| self.network.base_url().to_string())
80    }
81
82    /// Add authentication to the configuration
83    pub fn with_auth(mut self, token: String) -> Self {
84        self.auth = Some(AuthConfig::new(token));
85        self
86    }
87
88    /// Add authentication with expiry to the configuration
89    pub fn with_auth_expiry(
90        mut self,
91        token: String,
92        expiry: chrono::DateTime<chrono::Utc>,
93    ) -> Self {
94        self.auth = Some(AuthConfig::with_expiry(token, expiry));
95        self
96    }
97
98    /// Set request timeout
99    pub fn with_timeout(mut self, timeout: Duration) -> Self {
100        self.timeout = timeout;
101        self
102    }
103
104    /// Set rate limit quota
105    pub fn with_rate_limit(mut self, rate_limit: Quota) -> Self {
106        self.rate_limit = rate_limit;
107        self
108    }
109}
110
111impl Default for Config {
112    fn default() -> Self {
113        Self {
114            network: Network::default(),
115            custom_url: None,
116            auth: None,
117            timeout: Duration::from_secs(30),
118            rate_limit: Quota::per_second(100u32.try_into().unwrap()),
119        }
120    }
121}
122
123#[cfg(test)]
124mod tests {
125    use super::*;
126    use chrono::Utc;
127    use std::time::Duration;
128
129    #[test]
130    fn test_default_config() {
131        let config = Config::default();
132        assert_eq!(config.network, Network::Mainnet);
133        assert!(config.custom_url.is_none());
134        assert!(config.auth.is_none());
135        assert_eq!(config.timeout, Duration::from_secs(30));
136    }
137
138    #[test]
139    fn test_config_builder_pattern() {
140        let config = Config::default()
141            .with_auth("test-token".to_string())
142            .with_timeout(Duration::from_secs(60))
143            .with_rate_limit(Quota::per_second(50u32.try_into().unwrap()));
144
145        assert!(config.auth.is_some());
146        assert_eq!(config.timeout, Duration::from_secs(60));
147    }
148
149    #[test]
150    fn test_auth_config_validation() {
151        // Test without expiry
152        let auth = AuthConfig::new("test-token".to_string());
153        assert!(auth.is_valid());
154
155        // Test with future expiry
156        let future = Utc::now() + chrono::Duration::hours(1);
157        let auth = AuthConfig::with_expiry("test-token".to_string(), future);
158        assert!(auth.is_valid());
159
160        // Test with past expiry
161        let past = Utc::now() - chrono::Duration::hours(1);
162        let auth = AuthConfig::with_expiry("test-token".to_string(), past);
163        assert!(!auth.is_valid());
164    }
165
166    #[test]
167    fn test_config_base_url() {
168        // Test default network URL
169        let config = Config::default();
170        assert_eq!(config.base_url(), Network::Mainnet.base_url());
171
172        // Test custom URL
173        let custom_url = "https://custom.api.com".to_string();
174        let config = Config::new(
175            Network::Mainnet,
176            Some(custom_url.clone()),
177            None,
178            Duration::from_secs(30),
179            Quota::per_second(100u32.try_into().unwrap()),
180        );
181        assert_eq!(config.base_url(), custom_url);
182
183        // Test network URL
184        let config = Config::new(
185            Network::Preprod,
186            None,
187            None,
188            Duration::from_secs(30),
189            Quota::per_second(100u32.try_into().unwrap()),
190        );
191        assert_eq!(config.base_url(), Network::Preprod.base_url());
192    }
193
194    #[test]
195    fn test_config_with_auth_expiry() {
196        let expiry = Utc::now() + chrono::Duration::hours(1);
197        let config = Config::default().with_auth_expiry("test-token".to_string(), expiry);
198
199        assert!(config.auth.is_some());
200        let auth = config.auth.unwrap();
201        assert_eq!(auth.token, "test-token");
202        assert!(auth.expiry.is_some());
203        assert!(auth.is_valid());
204    }
205}