Skip to main content

audacity_sdk/
config.rs

1//! Client configuration — credential chain, builder, defaults.
2
3use std::time::Duration;
4
5const DEFAULT_BASE_URL: &str = "https://portal.audacityinvestments.com";
6const DEFAULT_TIMEOUT_SECS: u64 = 120;
7const DEFAULT_MAX_RETRIES: u32 = 2;
8
9/// Resolved SDK configuration.
10#[derive(Debug, Clone)]
11pub struct Config {
12    pub(crate) api_key: String,
13    pub(crate) base_url: String,
14    pub(crate) timeout: Duration,
15    pub(crate) max_retries: u32,
16}
17
18impl Config {
19    pub fn builder() -> ConfigBuilder {
20        ConfigBuilder::default()
21    }
22}
23
24/// Builder for [`Config`].
25#[derive(Default)]
26pub struct ConfigBuilder {
27    api_key: Option<String>,
28    base_url: Option<String>,
29    timeout: Option<Duration>,
30    max_retries: Option<u32>,
31}
32
33impl ConfigBuilder {
34    pub fn api_key(mut self, key: impl Into<String>) -> Self {
35        self.api_key = Some(key.into());
36        self
37    }
38
39    pub fn base_url(mut self, url: impl Into<String>) -> Self {
40        self.base_url = Some(url.into());
41        self
42    }
43
44    pub fn timeout(mut self, t: Duration) -> Self {
45        self.timeout = Some(t);
46        self
47    }
48
49    pub fn max_retries(mut self, n: u32) -> Self {
50        self.max_retries = Some(n);
51        self
52    }
53
54    /// Resolve the config, applying the credential chain.
55    /// Returns `Err(Error::MissingApiKey)` if no API key can be found.
56    pub fn build(self) -> Result<Config, crate::Error> {
57        let api_key = self
58            .api_key
59            .or_else(|| std::env::var("AUDACITY_API_KEY").ok())
60            .ok_or(crate::Error::MissingApiKey)?;
61
62        let base_url = self
63            .base_url
64            .or_else(|| std::env::var("AUDACITY_BASE_URL").ok())
65            .unwrap_or_else(|| DEFAULT_BASE_URL.to_owned());
66
67        // strip trailing slash for consistent URL construction
68        let base_url = base_url.trim_end_matches('/').to_owned();
69
70        Ok(Config {
71            api_key,
72            base_url,
73            timeout: self
74                .timeout
75                .unwrap_or(Duration::from_secs(DEFAULT_TIMEOUT_SECS)),
76            max_retries: self.max_retries.unwrap_or(DEFAULT_MAX_RETRIES),
77        })
78    }
79}