1use 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#[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#[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 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 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}