Skip to main content

headwaters_client/
config.rs

1//! Client configuration and its environment conventions.
2
3use std::time::Duration;
4
5use crate::Error;
6
7/// Environment variable holding the server base URL.
8pub const ENV_URL: &str = "HEADWATERS_URL";
9/// Environment variable holding a bearer token for the `authorization` header.
10pub const ENV_TOKEN: &str = "HEADWATERS_TOKEN";
11/// Environment variable holding the per-request timeout, in milliseconds.
12pub const ENV_TIMEOUT_MS: &str = "HEADWATERS_TIMEOUT_MS";
13
14/// Default per-request timeout when none is configured.
15pub const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30);
16
17/// How a [`HeadwatersClient`](crate::HeadwatersClient) reaches the server.
18///
19/// Build one with [`HeadwatersConfig::new`] (then the `with_*` setters) or
20/// [`HeadwatersConfig::from_env`].
21#[derive(Debug, Clone)]
22pub struct HeadwatersConfig {
23    pub(crate) base_url: String,
24    pub(crate) token: Option<String>,
25    pub(crate) timeout: Duration,
26}
27
28impl HeadwatersConfig {
29    /// Start from a base URL (e.g. `http://localhost:8091`), default timeout, no auth.
30    pub fn new(base_url: impl Into<String>) -> Self {
31        Self {
32            base_url: base_url.into(),
33            token: None,
34            timeout: DEFAULT_TIMEOUT,
35        }
36    }
37
38    /// Read configuration from the environment:
39    /// `HEADWATERS_URL` (required), `HEADWATERS_TOKEN` and `HEADWATERS_TIMEOUT_MS`
40    /// (optional). A non-numeric `HEADWATERS_TIMEOUT_MS` is ignored.
41    pub fn from_env() -> Result<Self, Error> {
42        let base_url = std::env::var(ENV_URL).map_err(|_| Error::MissingEnvVar(ENV_URL))?;
43        let mut config = Self::new(base_url);
44        if let Ok(token) = std::env::var(ENV_TOKEN) {
45            config.token = Some(token);
46        }
47        if let Some(ms) = std::env::var(ENV_TIMEOUT_MS)
48            .ok()
49            .and_then(|v| v.parse().ok())
50        {
51            config.timeout = Duration::from_millis(ms);
52        }
53        Ok(config)
54    }
55
56    /// Set a bearer token, sent as `authorization: Bearer <token>`.
57    #[must_use]
58    pub fn with_token(mut self, token: impl Into<String>) -> Self {
59        self.token = Some(token.into());
60        self
61    }
62
63    /// Set the per-request timeout.
64    #[must_use]
65    pub fn with_timeout(mut self, timeout: Duration) -> Self {
66        self.timeout = timeout;
67        self
68    }
69}