nullnet_libdatastore/
config.rs

1use nullnet_liberror::{Error, ErrorHandler, Location, location};
2use tonic::transport::{Channel, ClientTlsConfig};
3
4/// Configuration structure for the datastore.
5///
6/// This struct encapsulates the configuration details required to connect to the datastore,
7/// including the host address, port, and whether TLS is enabled.
8#[derive(Debug, Clone)]
9pub struct DatastoreConfig {
10    /// Hostname or IP address of the datastore.
11    pub host: String,
12    /// Port number used to connect to the datastore.
13    pub port: u16,
14    /// Whether TLS is enabled for the datastore connection.
15    pub tls: bool,
16}
17
18impl DatastoreConfig {
19    /// Creates a new `DatastoreConfig` instance by reading values from environment variables.
20    ///
21    /// If the environment variables are not set or cannot be parsed, default values are used:
22    /// - `DATASTORE_HOST` defaults to `"127.0.0.1"`.
23    /// - `DATASTORE_PORT` defaults to `6000`.
24    /// - `DATASTORE_TLS` defaults to `false`.
25    ///
26    /// # Returns
27    /// A `DatastoreConfig` instance with values derived from the environment or defaults.
28    #[must_use]
29    pub fn from_env() -> Self {
30        Self {
31            host: read_host_value_from_env(String::from("127.0.0.1")),
32            port: read_port_value_from_env(6000),
33            tls: real_tls_value_from_env(false),
34        }
35    }
36
37    /// Creates a new `DatastoreConfig` instance with the provided values.
38    ///
39    /// # Arguments
40    /// * `host` - A `String` representing the hostname or IP address of the datastore.
41    /// * `port` - A `u16` representing the port number for connecting to the datastore.
42    /// * `tls` - A `bool` indicating whether to use TLS for the connection (`true` for TLS, `false` otherwise).
43    ///
44    /// # Returns
45    /// A `DatastoreConfig` instance initialized with the specified host, port, and TLS settings.
46    #[must_use]
47    pub fn new(host: String, port: u16, tls: bool) -> Self {
48        Self { host, port, tls }
49    }
50
51    /// Establishes a connection to the datastore service.
52    ///
53    /// # Returns
54    /// * `Ok(Channel)` - Opened channel.
55    /// * `Err(Error)` - If the connection fails.
56    pub(crate) async fn connect(&self) -> Result<Channel, Error> {
57        let protocol = if self.tls { "https" } else { "http" };
58        let host = self.host.as_str();
59        let port = self.port;
60
61        let mut endpoint = Channel::from_shared(format!("{protocol}://{host}:{port}"))
62            .handle_err(location!())?
63            .connect_timeout(std::time::Duration::from_secs(10));
64
65        if self.tls {
66            endpoint = endpoint
67                .tls_config(ClientTlsConfig::new().with_native_roots())
68                .handle_err(location!())?;
69        }
70
71        let channel = endpoint.connect().await.handle_err(location!())?;
72
73        Ok(channel)
74        // Ok(StoreServiceClient::new(channel).max_decoding_message_size(50 * 1024 * 1024))
75    }
76}
77
78/// Reads the `DATASTORE_HOST` environment variable.
79///
80/// If the variable is not set or an error occurs, the specified default value is returned.
81///
82/// # Parameters
83/// - `default`: Default hostname to use if the environment variable is not set.
84///
85/// # Returns
86/// The value of `DATASTORE_HOST` or the default value if the variable is not set.
87fn read_host_value_from_env(default: String) -> String {
88    std::env::var("DATASTORE_HOST").unwrap_or_else(|err| {
89        log::warn!("Failed to read 'DATASTORE_HOST' env var: {err}. Using default value ...");
90        default
91    })
92}
93
94/// Reads the `DATASTORE_PORT` environment variable and parses it as a `u16`.
95///
96/// If the variable is not set, cannot be parsed, or an error occurs, the specified default value is used.
97///
98/// # Parameters
99/// - `default`: Default port to use if the environment variable is not set or invalid.
100///
101/// # Returns
102/// The value of `DATASTORE_PORT` parsed as a `u16` or the default value if the variable is not set or invalid.
103fn read_port_value_from_env(default: u16) -> u16 {
104    match std::env::var("DATASTORE_PORT") {
105        Ok(value) => value.parse::<u16>().unwrap_or_else(|err| {
106            log::warn!(
107                "Failed to parse 'DATASTORE_PORT' ({value}) as u16: {err}. Using default value ..."
108            );
109            default
110        }),
111        Err(err) => {
112            log::warn!("Failed to read 'DATASTORE_PORT' env var: {err}. Using default value ...");
113            default
114        }
115    }
116}
117
118/// Reads the `DATASTORE_TLS` environment variable and interprets it as a boolean.
119///
120/// If the variable is set to `"true"` (case insensitive), it returns `true`. For any other value or
121/// if the variable is not set, the specified default value is used.
122///
123/// # Parameters
124/// - `default`: Default value to use if the environment variable is not set.
125///
126/// # Returns
127/// `true` if the environment variable is set to `"true"`, otherwise the default value.
128fn real_tls_value_from_env(default: bool) -> bool {
129    match std::env::var("DATASTORE_TLS") {
130        Ok(value) => value.to_lowercase() == "true",
131        Err(err) => {
132            log::warn!("Failed to read 'DATASTORE_TLS' env var: {err}. Using default value ...");
133            default
134        }
135    }
136}