worterbuch_client/
config.rs

1/*
2 *  Worterbuch client config module
3 *
4 *  Copyright (C) 2024 Michael Bachmann
5 *
6 *  This program is free software: you can redistribute it and/or modify
7 *  it under the terms of the GNU Affero General Public License as published by
8 *  the Free Software Foundation, either version 3 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU Affero General Public License for more details.
15 *
16 *  You should have received a copy of the GNU Affero General Public License
17 *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#[cfg(target_family = "unix")]
21use std::path::PathBuf;
22use std::{
23    env,
24    net::{Ipv4Addr, SocketAddr, SocketAddrV4, ToSocketAddrs},
25    ops::Deref,
26    time::Duration,
27};
28use tracing::{debug, error, instrument};
29
30#[derive(Debug, Clone, PartialEq)]
31pub struct Config {
32    pub proto: String,
33    pub servers: Box<[SocketAddr]>,
34    pub send_timeout: Option<Duration>,
35    pub connection_timeout: Duration,
36    pub auth_token: Option<String>,
37    pub use_backpressure: bool,
38    pub channel_buffer_size: usize,
39    #[cfg(target_family = "unix")]
40    pub socket_path: Option<PathBuf>,
41}
42
43impl Config {
44    pub fn load_env(&mut self) {
45        if let Ok(val) = env::var("WORTERBUCH_PROTO") {
46            self.proto = val;
47        }
48
49        if let Ok(val) = env::var("WORTERBUCH_SERVERS") {
50            self.servers = val
51                .split(',')
52                .map(str::trim)
53                .filter_map(|s| s.to_socket_addrs().ok())
54                .flatten()
55                .collect();
56        } else if let Ok(val) = env::var("WORTERBUCH_HOST_ADDRESS") {
57            let default_port = match self.proto.to_lowercase().deref() {
58                "ws" | "wss" | "http" | "https" => 8080,
59                _ => 8081,
60            };
61            let port = if let Ok(val) = env::var("WORTERBUCH_PORT") {
62                if let Ok(port) = val.parse() {
63                    port
64                } else {
65                    default_port
66                }
67            } else {
68                default_port
69            };
70            if let Ok(addr) = format!("{val}:{port}").to_socket_addrs() {
71                self.servers = addr.collect();
72            }
73        }
74
75        if let Ok(val) = env::var("WORTERBUCH_SEND_TIMEOUT") {
76            if let Ok(secs) = val.parse() {
77                self.send_timeout = Some(Duration::from_secs(secs));
78            } else {
79                error!("invalid timeout: {val}");
80            }
81        }
82
83        if let Ok(val) = env::var("WORTERBUCH_CONNECTION_TIMEOUT") {
84            if let Ok(secs) = val.parse() {
85                self.connection_timeout = Duration::from_secs(secs);
86            } else {
87                error!("invalid timeout: {val}");
88            }
89        }
90
91        if let Ok(val) = env::var("WORTERBUCH_AUTH_TOKEN") {
92            self.auth_token = Some(val);
93        }
94
95        if let Ok(val) = env::var("WORTERBUCH_CHANNEL_BUFFER_SIZE") {
96            if let Ok(size) = val.parse() {
97                self.channel_buffer_size = size;
98            } else {
99                error!("invalid buffer size: {val}");
100            }
101        }
102
103        if let Ok(val) = env::var("WORTERBUCH_USE_BACKPRESSURE") {
104            let val = val.to_lowercase() == "true";
105            self.use_backpressure = val;
106        }
107
108        #[cfg(target_family = "unix")]
109        {
110            if let Ok(val) = env::var("WORTERBUCH_UNIX_SOCKET_PATH") {
111                self.socket_path = Some(PathBuf::from(val));
112            }
113        }
114    }
115}
116
117impl Default for Config {
118    fn default() -> Self {
119        let proto = "tcp".to_owned();
120        let servers = vec![SocketAddr::V4(SocketAddrV4::new(
121            Ipv4Addr::new(127, 0, 0, 1),
122            8081,
123        ))]
124        .into();
125        let send_timeout = None;
126        let connection_timeout = Duration::from_secs(5);
127        let channel_buffer_size = 1;
128        let use_backpressure = true;
129        #[cfg(target_family = "unix")]
130        let socket_path = Some("/tmp/worterbuch.socket".into());
131
132        Config {
133            proto,
134            servers,
135            send_timeout,
136            connection_timeout,
137            auth_token: None,
138            channel_buffer_size,
139            use_backpressure,
140            #[cfg(target_family = "unix")]
141            socket_path,
142        }
143    }
144}
145
146impl Config {
147    #[instrument]
148    pub fn new() -> Self {
149        debug!("Creating default config");
150        let mut config = Config::default();
151        debug!("Loading environment variables");
152        config.load_env();
153        config
154    }
155
156    #[instrument]
157    pub fn with_servers(proto: String, servers: Box<[SocketAddr]>) -> Self {
158        let mut config = Config::new();
159        config.proto = proto;
160        config.servers = servers;
161        config
162    }
163}