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