amaters_sdk_rust/
config.rs1use std::path::PathBuf;
4use std::time::Duration;
5
6#[derive(Debug, Clone)]
8pub struct ClientConfig {
9 pub server_addr: String,
11
12 pub connect_timeout: Duration,
14
15 pub request_timeout: Duration,
17
18 pub keep_alive: bool,
20
21 pub keep_alive_interval: Duration,
23
24 pub keep_alive_timeout: Duration,
26
27 pub max_connections: usize,
29
30 pub idle_timeout: Duration,
32
33 pub tls_enabled: bool,
35
36 pub tls_config: Option<TlsConfig>,
38
39 pub retry_config: RetryConfig,
41}
42
43impl Default for ClientConfig {
44 fn default() -> Self {
45 Self {
46 server_addr: "http://localhost:50051".to_string(),
47 connect_timeout: Duration::from_secs(10),
48 request_timeout: Duration::from_secs(30),
49 keep_alive: true,
50 keep_alive_interval: Duration::from_secs(60),
51 keep_alive_timeout: Duration::from_secs(20),
52 max_connections: 10,
53 idle_timeout: Duration::from_secs(300),
54 tls_enabled: false,
55 tls_config: None,
56 retry_config: RetryConfig::default(),
57 }
58 }
59}
60
61impl ClientConfig {
62 pub fn new(server_addr: impl Into<String>) -> Self {
64 Self {
65 server_addr: server_addr.into(),
66 ..Default::default()
67 }
68 }
69
70 pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
72 self.connect_timeout = timeout;
73 self
74 }
75
76 pub fn with_request_timeout(mut self, timeout: Duration) -> Self {
78 self.request_timeout = timeout;
79 self
80 }
81
82 pub fn with_max_connections(mut self, max: usize) -> Self {
84 self.max_connections = max;
85 self
86 }
87
88 pub fn with_tls(mut self, tls_config: TlsConfig) -> Self {
90 self.tls_enabled = true;
91 self.tls_config = Some(tls_config);
92 self
93 }
94
95 pub fn with_retry_config(mut self, retry_config: RetryConfig) -> Self {
97 self.retry_config = retry_config;
98 self
99 }
100
101 pub fn without_keep_alive(mut self) -> Self {
103 self.keep_alive = false;
104 self
105 }
106}
107
108#[derive(Debug, Clone, Default)]
110pub struct TlsConfig {
111 pub ca_cert_path: Option<PathBuf>,
113
114 pub client_cert_path: Option<PathBuf>,
116
117 pub client_key_path: Option<PathBuf>,
119
120 pub domain_name: Option<String>,
122
123 pub accept_invalid_certs: bool,
125}
126
127impl TlsConfig {
128 pub fn new() -> Self {
130 Self::default()
131 }
132
133 pub fn with_ca_cert(mut self, path: impl Into<PathBuf>) -> Self {
135 self.ca_cert_path = Some(path.into());
136 self
137 }
138
139 pub fn with_client_cert(
141 mut self,
142 cert_path: impl Into<PathBuf>,
143 key_path: impl Into<PathBuf>,
144 ) -> Self {
145 self.client_cert_path = Some(cert_path.into());
146 self.client_key_path = Some(key_path.into());
147 self
148 }
149
150 pub fn with_domain_name(mut self, domain: impl Into<String>) -> Self {
152 self.domain_name = Some(domain.into());
153 self
154 }
155
156 pub fn accept_invalid_certs(mut self) -> Self {
158 self.accept_invalid_certs = true;
159 self
160 }
161}
162
163#[derive(Debug, Clone)]
165pub struct RetryConfig {
166 pub max_retries: usize,
168
169 pub initial_backoff: Duration,
171
172 pub max_backoff: Duration,
174
175 pub backoff_multiplier: f64,
177
178 pub jitter: bool,
180}
181
182impl Default for RetryConfig {
183 fn default() -> Self {
184 Self {
185 max_retries: 3,
186 initial_backoff: Duration::from_millis(100),
187 max_backoff: Duration::from_secs(30),
188 backoff_multiplier: 2.0,
189 jitter: true,
190 }
191 }
192}
193
194impl RetryConfig {
195 pub fn new() -> Self {
197 Self::default()
198 }
199
200 pub fn with_max_retries(mut self, max: usize) -> Self {
202 self.max_retries = max;
203 self
204 }
205
206 pub fn with_initial_backoff(mut self, backoff: Duration) -> Self {
208 self.initial_backoff = backoff;
209 self
210 }
211
212 pub fn no_retry() -> Self {
214 Self {
215 max_retries: 0,
216 ..Default::default()
217 }
218 }
219
220 pub fn backoff_duration(&self, attempt: usize) -> Duration {
222 if attempt == 0 {
223 return Duration::from_secs(0);
224 }
225
226 let base = self.initial_backoff.as_millis() as f64
227 * self.backoff_multiplier.powi((attempt - 1) as i32);
228 let backoff = Duration::from_millis(base.min(self.max_backoff.as_millis() as f64) as u64);
229
230 if self.jitter {
231 let jitter_factor = 0.5 + (attempt % 10) as f64 / 10.0; Duration::from_millis((backoff.as_millis() as f64 * jitter_factor) as u64)
234 } else {
235 backoff
236 }
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn test_default_config() {
246 let config = ClientConfig::default();
247 assert_eq!(config.server_addr, "http://localhost:50051");
248 assert_eq!(config.max_connections, 10);
249 assert!(config.keep_alive);
250 }
251
252 #[test]
253 fn test_config_builder() {
254 let config = ClientConfig::new("http://example.com:50051")
255 .with_connect_timeout(Duration::from_secs(5))
256 .with_max_connections(20)
257 .without_keep_alive();
258
259 assert_eq!(config.server_addr, "http://example.com:50051");
260 assert_eq!(config.connect_timeout, Duration::from_secs(5));
261 assert_eq!(config.max_connections, 20);
262 assert!(!config.keep_alive);
263 }
264
265 #[test]
266 fn test_tls_config() {
267 let tls = TlsConfig::new()
268 .with_ca_cert("/path/to/ca.pem")
269 .with_domain_name("example.com");
270
271 assert!(tls.ca_cert_path.is_some());
272 assert_eq!(tls.domain_name, Some("example.com".to_string()));
273 }
274
275 #[test]
276 fn test_retry_config() {
277 let retry = RetryConfig::default();
278 assert_eq!(retry.max_retries, 3);
279
280 let backoff1 = retry.backoff_duration(1);
281 let backoff2 = retry.backoff_duration(2);
282 assert!(backoff2 > backoff1);
283 }
284
285 #[test]
286 fn test_no_retry() {
287 let retry = RetryConfig::no_retry();
288 assert_eq!(retry.max_retries, 0);
289 }
290}