nullnet_libdatastore/
config.rs

1use crate::store_service_client::StoreServiceClient;
2use nullnet_liberror::{Error, ErrorHandler, Location, location};
3use tonic::transport::{Channel, ClientTlsConfig};
4
5/// Configuration structure for the datastore.
6///
7/// This struct encapsulates the configuration details required to connect to the datastore,
8/// including the host address, port, and whether TLS is enabled.
9#[derive(Debug, Clone)]
10pub struct DatastoreConfig {
11    /// Hostname or IP address of the datastore.
12    pub host: String,
13    /// Port number used to connect to the datastore.
14    pub port: u16,
15    /// Whether TLS is enabled for the datastore connection.
16    pub tls: bool,
17}
18
19impl DatastoreConfig {
20    /// Creates a new `DatastoreConfig` instance by reading values from environment variables.
21    ///
22    /// If the environment variables are not set or cannot be parsed, default values are used:
23    /// - `DATASTORE_HOST` defaults to `"127.0.0.1"`.
24    /// - `DATASTORE_PORT` defaults to `6000`.
25    /// - `DATASTORE_TLS` defaults to `false`.
26    ///
27    /// # Returns
28    /// A `DatastoreConfig` instance with values derived from the environment or defaults.
29    #[must_use]
30    pub fn from_env() -> Self {
31        Self {
32            host: read_host_value_from_env(String::from("127.0.0.1")),
33            port: read_port_value_from_env(6000),
34            tls: real_tls_value_from_env(false),
35        }
36    }
37
38    /// Creates a new `DatastoreConfig` instance with the provided values.
39    ///
40    /// # Arguments
41    /// * `host` - A `String` representing the hostname or IP address of the datastore.
42    /// * `port` - A `u16` representing the port number for connecting to the datastore.
43    /// * `tls` - A `bool` indicating whether to use TLS for the connection (`true` for TLS, `false` otherwise).
44    ///
45    /// # Returns
46    /// A `DatastoreConfig` instance initialized with the specified host, port, and TLS settings.
47    #[must_use]
48    pub fn new(host: String, port: u16, tls: bool) -> Self {
49        Self { host, port, tls }
50    }
51
52    /// Establishes a connection to the datastore service.
53    ///
54    /// # Returns
55    /// * `Ok(StoreServiceClient<Channel>)` - The client for interacting with the datastore service.
56    /// * `Err(Error)` - If the connection fails.
57    pub(crate) async fn connect(&self) -> Result<StoreServiceClient<Channel>, Error> {
58        let protocol = if self.tls { "https" } else { "http" };
59        let host = self.host.as_str();
60        let port = self.port;
61
62        let mut endpoint = Channel::from_shared(format!("{protocol}://{host}:{port}"))
63            .handle_err(location!())?
64            .connect_timeout(std::time::Duration::from_secs(10));
65
66        if self.tls {
67            endpoint = endpoint
68                .tls_config(ClientTlsConfig::new().with_native_roots())
69                .handle_err(location!())?;
70        }
71
72        let channel: Channel = endpoint.connect().await.handle_err(location!())?;
73
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}