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}