Skip to main content

outlit/
config.rs

1//! Client configuration.
2
3use std::time::Duration;
4
5/// Default API host.
6pub const DEFAULT_API_HOST: &str = "https://app.outlit.ai";
7
8/// Default flush interval.
9pub const DEFAULT_FLUSH_INTERVAL: Duration = Duration::from_secs(10);
10
11/// Default max batch size.
12pub const DEFAULT_MAX_BATCH_SIZE: usize = 100;
13
14/// Default request timeout.
15pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(10);
16
17/// Outlit client configuration.
18#[derive(Debug, Clone)]
19pub struct Config {
20    pub(crate) public_key: String,
21    pub(crate) api_host: String,
22    pub(crate) flush_interval: Duration,
23    pub(crate) max_batch_size: usize,
24    pub(crate) timeout: Duration,
25}
26
27impl Config {
28    /// Get the public key.
29    pub fn public_key(&self) -> &str {
30        &self.public_key
31    }
32
33    /// Get the API host.
34    pub fn api_host(&self) -> &str {
35        &self.api_host
36    }
37
38    /// Get the flush interval.
39    pub fn flush_interval(&self) -> Duration {
40        self.flush_interval
41    }
42
43    /// Get the max batch size.
44    pub fn max_batch_size(&self) -> usize {
45        self.max_batch_size
46    }
47
48    /// Get the request timeout.
49    pub fn timeout(&self) -> Duration {
50        self.timeout
51    }
52}
53
54/// Builder for Outlit client.
55#[derive(Debug)]
56pub struct OutlitBuilder {
57    public_key: String,
58    api_host: Option<String>,
59    flush_interval: Option<Duration>,
60    max_batch_size: Option<usize>,
61    timeout: Option<Duration>,
62}
63
64impl OutlitBuilder {
65    /// Create a new builder with the given public key.
66    pub fn new(public_key: impl Into<String>) -> Self {
67        Self {
68            public_key: public_key.into(),
69            api_host: None,
70            flush_interval: None,
71            max_batch_size: None,
72            timeout: None,
73        }
74    }
75
76    /// Set the API host.
77    pub fn api_host(mut self, host: impl Into<String>) -> Self {
78        self.api_host = Some(host.into());
79        self
80    }
81
82    /// Set the flush interval.
83    pub fn flush_interval(mut self, interval: Duration) -> Self {
84        self.flush_interval = Some(interval);
85        self
86    }
87
88    /// Set the max batch size.
89    pub fn max_batch_size(mut self, size: usize) -> Self {
90        self.max_batch_size = Some(size);
91        self
92    }
93
94    /// Set the request timeout.
95    pub fn timeout(mut self, timeout: Duration) -> Self {
96        self.timeout = Some(timeout);
97        self
98    }
99
100    /// Build the configuration.
101    pub(crate) fn build_config(self) -> Result<Config, crate::Error> {
102        if self.public_key.trim().is_empty() {
103            return Err(crate::Error::Config("public_key cannot be empty".into()));
104        }
105
106        if let Some(ref host) = self.api_host {
107            if host.trim().is_empty() {
108                return Err(crate::Error::Config("api_host cannot be empty".into()));
109            }
110        }
111
112        Ok(Config {
113            public_key: self.public_key,
114            api_host: self.api_host.unwrap_or_else(|| DEFAULT_API_HOST.into()),
115            flush_interval: self.flush_interval.unwrap_or(DEFAULT_FLUSH_INTERVAL),
116            max_batch_size: self.max_batch_size.unwrap_or(DEFAULT_MAX_BATCH_SIZE),
117            timeout: self.timeout.unwrap_or(DEFAULT_TIMEOUT),
118        })
119    }
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125
126    #[test]
127    fn test_builder_defaults() {
128        let config = OutlitBuilder::new("pk_test").build_config().unwrap();
129
130        assert_eq!(config.public_key(), "pk_test");
131        assert_eq!(config.api_host(), DEFAULT_API_HOST);
132        assert_eq!(config.flush_interval(), DEFAULT_FLUSH_INTERVAL);
133        assert_eq!(config.max_batch_size(), DEFAULT_MAX_BATCH_SIZE);
134        assert_eq!(config.timeout(), DEFAULT_TIMEOUT);
135    }
136
137    #[test]
138    fn test_builder_custom_values() {
139        let config = OutlitBuilder::new("pk_test")
140            .api_host("https://custom.example.com")
141            .flush_interval(Duration::from_secs(5))
142            .max_batch_size(50)
143            .timeout(Duration::from_secs(30))
144            .build_config()
145            .unwrap();
146
147        assert_eq!(config.api_host(), "https://custom.example.com");
148        assert_eq!(config.flush_interval(), Duration::from_secs(5));
149        assert_eq!(config.max_batch_size(), 50);
150        assert_eq!(config.timeout(), Duration::from_secs(30));
151    }
152
153    #[test]
154    fn test_builder_empty_public_key_fails() {
155        let result = OutlitBuilder::new("").build_config();
156        assert!(result.is_err());
157    }
158
159    #[test]
160    fn test_builder_whitespace_public_key_fails() {
161        let result = OutlitBuilder::new("   ").build_config();
162        assert!(result.is_err());
163    }
164
165    #[test]
166    fn test_builder_whitespace_api_host_fails() {
167        let result = OutlitBuilder::new("pk_test").api_host("   ").build_config();
168        assert!(result.is_err());
169    }
170
171    #[test]
172    fn test_builder_accepts_string_and_str() {
173        // &str
174        let _ = OutlitBuilder::new("pk_test");
175        // String
176        let _ = OutlitBuilder::new(String::from("pk_test"));
177        // Same for api_host
178        let _ = OutlitBuilder::new("pk_test").api_host("https://example.com");
179        let _ = OutlitBuilder::new("pk_test").api_host(String::from("https://example.com"));
180    }
181}