1use std::time::Duration;
2
3use crate::sign::SignatureVersion;
4
5#[derive(Debug, Clone)]
10#[non_exhaustive]
11pub struct ClientConfig {
12 pub endpoint: String,
14
15 pub timeout: Duration,
17
18 pub max_concurrent_requests: usize,
20
21 pub connect_timeout: Duration,
23
24 pub pool_idle_timeout: Duration,
26
27 pub pool_max_idle_per_host: usize,
29
30 pub tcp_keepalive: Option<Duration>,
32
33 pub(crate) format: &'static str,
35
36 pub(crate) api_version: &'static str,
38
39 pub signature_version: SignatureVersion,
41}
42
43pub const DEFAULT_TIMEOUT_SECS: u64 = 30;
48
49pub const DEFAULT_MAX_CONCURRENT_REQUESTS: usize = 10;
54
55pub const DEFAULT_CONNECT_TIMEOUT_SECS: u64 = 10;
60
61pub const DEFAULT_POOL_IDLE_TIMEOUT_SECS: u64 = 90;
66
67pub const DEFAULT_POOL_MAX_IDLE_PER_HOST: usize = 10;
72
73pub const DEFAULT_TCP_KEEPALIVE_SECS: u64 = 60;
78
79pub const MIN_DURATION_SECONDS: u64 = 900;
84
85pub const MAX_DURATION_SECONDS: u64 = 3600;
90
91pub const MIN_ROLE_SESSION_NAME_LENGTH: usize = 1;
93
94pub const MAX_ROLE_SESSION_NAME_LENGTH: usize = 32;
96
97impl Default for ClientConfig {
98 fn default() -> Self {
99 Self {
100 endpoint: "https://sts.aliyuncs.com".to_string(),
101 timeout: Duration::from_secs(DEFAULT_TIMEOUT_SECS),
102 max_concurrent_requests: DEFAULT_MAX_CONCURRENT_REQUESTS,
103 connect_timeout: Duration::from_secs(DEFAULT_CONNECT_TIMEOUT_SECS),
104 pool_idle_timeout: Duration::from_secs(DEFAULT_POOL_IDLE_TIMEOUT_SECS),
105 pool_max_idle_per_host: DEFAULT_POOL_MAX_IDLE_PER_HOST,
106 tcp_keepalive: Some(Duration::from_secs(DEFAULT_TCP_KEEPALIVE_SECS)),
107 format: "JSON",
108 api_version: "2015-04-01",
109 signature_version: SignatureVersion::default(),
110 }
111 }
112}
113
114impl ClientConfig {
115 pub fn with_endpoint(mut self, endpoint: impl Into<String>) -> Self {
117 self.endpoint = endpoint.into();
118 self
119 }
120
121 pub fn with_timeout(mut self, timeout: Duration) -> Self {
135 self.timeout = timeout;
136 self
137 }
138
139 pub fn with_max_concurrent_requests(mut self, max: usize) -> Self {
159 assert!(max > 0, "max_concurrent_requests must be greater than 0");
160 self.max_concurrent_requests = max;
161 self
162 }
163
164 pub fn with_connect_timeout(mut self, timeout: Duration) -> Self {
166 self.connect_timeout = timeout;
167 self
168 }
169
170 pub fn with_pool_idle_timeout(mut self, timeout: Duration) -> Self {
172 self.pool_idle_timeout = timeout;
173 self
174 }
175
176 pub fn with_pool_max_idle_per_host(mut self, max: usize) -> Self {
178 self.pool_max_idle_per_host = max;
179 self
180 }
181
182 pub fn with_tcp_keepalive(mut self, duration: Option<Duration>) -> Self {
184 self.tcp_keepalive = duration;
185 self
186 }
187
188 pub fn with_signature_version(mut self, version: SignatureVersion) -> Self {
202 self.signature_version = version;
203 self
204 }
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
212 fn default_config() {
213 let config = ClientConfig::default();
214 assert_eq!(config.endpoint, "https://sts.aliyuncs.com");
215 assert_eq!(config.timeout, Duration::from_secs(DEFAULT_TIMEOUT_SECS));
216 assert_eq!(
217 config.max_concurrent_requests,
218 DEFAULT_MAX_CONCURRENT_REQUESTS
219 );
220 assert_eq!(
221 config.connect_timeout,
222 Duration::from_secs(DEFAULT_CONNECT_TIMEOUT_SECS)
223 );
224 assert_eq!(
225 config.pool_idle_timeout,
226 Duration::from_secs(DEFAULT_POOL_IDLE_TIMEOUT_SECS)
227 );
228 assert_eq!(
229 config.pool_max_idle_per_host,
230 DEFAULT_POOL_MAX_IDLE_PER_HOST
231 );
232 assert_eq!(
233 config.tcp_keepalive,
234 Some(Duration::from_secs(DEFAULT_TCP_KEEPALIVE_SECS))
235 );
236 assert_eq!(config.format, "JSON");
237 assert_eq!(config.api_version, "2015-04-01");
238 assert_eq!(config.signature_version, SignatureVersion::V1_0);
239 }
240
241 #[test]
242 fn custom_endpoint() {
243 let config =
244 ClientConfig::default().with_endpoint("https://sts-vpc.cn-hangzhou.aliyuncs.com");
245 assert_eq!(config.endpoint, "https://sts-vpc.cn-hangzhou.aliyuncs.com");
246 }
247
248 #[test]
249 fn custom_timeout() {
250 use std::time::Duration;
251 let config = ClientConfig::default().with_timeout(Duration::from_secs(60));
252 assert_eq!(config.timeout, Duration::from_secs(60));
253 }
254
255 #[test]
256 fn custom_max_concurrent_requests() {
257 let config = ClientConfig::default().with_max_concurrent_requests(5);
258 assert_eq!(config.max_concurrent_requests, 5);
259 }
260
261 #[test]
262 #[should_panic(expected = "max_concurrent_requests must be greater than 0")]
263 fn zero_max_concurrent_requests_panics() {
264 ClientConfig::default().with_max_concurrent_requests(0);
265 }
266
267 #[test]
268 fn custom_connect_timeout() {
269 let config = ClientConfig::default().with_connect_timeout(Duration::from_secs(5));
270 assert_eq!(config.connect_timeout, Duration::from_secs(5));
271 }
272
273 #[test]
274 fn custom_pool_idle_timeout() {
275 let config = ClientConfig::default().with_pool_idle_timeout(Duration::from_secs(120));
276 assert_eq!(config.pool_idle_timeout, Duration::from_secs(120));
277 }
278
279 #[test]
280 fn custom_pool_max_idle_per_host() {
281 let config = ClientConfig::default().with_pool_max_idle_per_host(20);
282 assert_eq!(config.pool_max_idle_per_host, 20);
283 }
284
285 #[test]
286 fn custom_tcp_keepalive() {
287 let config = ClientConfig::default().with_tcp_keepalive(Some(Duration::from_secs(30)));
288 assert_eq!(config.tcp_keepalive, Some(Duration::from_secs(30)));
289 }
290
291 #[test]
292 fn disable_tcp_keepalive() {
293 let config = ClientConfig::default().with_tcp_keepalive(None);
294 assert_eq!(config.tcp_keepalive, None);
295 }
296
297 #[test]
298 fn custom_signature_version_v1() {
299 let config = ClientConfig::default().with_signature_version(SignatureVersion::V1_0);
300 assert_eq!(config.signature_version, SignatureVersion::V1_0);
301 }
302
303 #[test]
304 fn custom_signature_version_v2() {
305 let config = ClientConfig::default().with_signature_version(SignatureVersion::V2_0);
306 assert_eq!(config.signature_version, SignatureVersion::V2_0);
307 }
308}