Skip to main content

flams_utils/
settings.rs

1use std::{
2    ops::{Add, AddAssign},
3    path::{Path, PathBuf},
4};
5
6#[derive(Debug, Default, Clone)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct SettingsSpec {
9    #[cfg_attr(feature = "serde", serde(default))]
10    pub mathhubs: Vec<PathBuf>,
11    #[cfg_attr(feature = "serde", serde(default))]
12    pub debug: Option<bool>,
13    #[cfg_attr(feature = "serde", serde(default))]
14    pub server: ServerSettings,
15    #[cfg_attr(feature = "serde", serde(default))]
16    pub log_dir: Option<Box<Path>>,
17    #[cfg_attr(feature = "serde", serde(default))]
18    pub temp_dir: Option<Box<Path>>,
19    #[cfg_attr(feature = "serde", serde(default))]
20    pub embedding_dir: Option<Box<Path>>,
21    #[cfg_attr(feature = "serde", serde(default))]
22    pub buildqueue: BuildQueueSettings,
23    #[cfg_attr(feature = "serde", serde(skip))]
24    pub lsp: bool,
25    #[cfg_attr(feature = "serde", serde(default))]
26    pub database: Option<Box<Path>>,
27    #[cfg_attr(feature = "serde", serde(default))]
28    pub rdf_database: Option<Box<Path>>,
29    #[cfg_attr(feature = "serde", serde(default))]
30    pub gitlab: GitlabSettings,
31    #[cfg_attr(feature = "serde", serde(default))]
32    pub stack_size: Option<u8>,
33}
34impl Add for SettingsSpec {
35    type Output = Self;
36    fn add(self, rhs: Self) -> Self::Output {
37        Self {
38            mathhubs: if self.mathhubs.is_empty() {
39                rhs.mathhubs
40            } else {
41                self.mathhubs
42            }, //self.mathhubs.into_iter().chain(rhs.mathhubs.into_iter()).collect(),
43            debug: self.debug.or(rhs.debug),
44            server: self.server + rhs.server,
45            log_dir: self.log_dir.or(rhs.log_dir),
46            temp_dir: self.temp_dir.or(rhs.temp_dir),
47            database: self.database.or(rhs.database),
48            rdf_database: self.rdf_database.or(rhs.rdf_database),
49            embedding_dir: self.embedding_dir.or(rhs.embedding_dir),
50            stack_size: self.stack_size.or(rhs.stack_size),
51            buildqueue: self.buildqueue + rhs.buildqueue,
52            gitlab: self.gitlab + rhs.gitlab,
53            lsp: self.lsp || rhs.lsp,
54        }
55    }
56}
57impl AddAssign for SettingsSpec {
58    fn add_assign(&mut self, rhs: Self) {
59        if self.mathhubs.is_empty() {
60            self.mathhubs = rhs.mathhubs;
61        }
62        self.debug = self.debug.or(rhs.debug);
63        self.lsp = self.lsp || rhs.lsp;
64        self.server += rhs.server;
65        if self.log_dir.is_none() {
66            self.log_dir = rhs.log_dir;
67        }
68        if self.stack_size.is_none() {
69            self.stack_size = rhs.stack_size;
70        }
71        if self.temp_dir.is_none() {
72            self.temp_dir = rhs.temp_dir;
73        }
74        if self.embedding_dir.is_none() {
75            self.embedding_dir = rhs.embedding_dir;
76        }
77        if self.database.is_none() {
78            self.database = rhs.database;
79        }
80        if self.rdf_database.is_none() {
81            self.rdf_database = rhs.rdf_database;
82        }
83        self.gitlab += rhs.gitlab;
84        self.buildqueue += rhs.buildqueue;
85    }
86}
87
88impl SettingsSpec {
89    #[allow(clippy::missing_panics_doc)]
90    #[must_use]
91    pub fn from_envs() -> Self {
92        Self {
93            mathhubs: Vec::new(),
94            debug: std::env::var("FLAMS_DEBUG")
95                .ok()
96                .and_then(|s| s.parse().ok()),
97            log_dir: std::env::var("FLAMS_LOG_DIR")
98                .ok()
99                .map(|s| PathBuf::from(s).into_boxed_path()),
100            temp_dir: std::env::var("FLAMS_TEMP_DIR")
101                .ok()
102                .map(|s| PathBuf::from(s).into_boxed_path()),
103            embedding_dir: std::env::var("FLAMS_EMBEDDING_DIR")
104                .ok()
105                .map(|s| PathBuf::from(s).into_boxed_path()),
106            database: std::env::var("FLAMS_DATABASE")
107                .ok()
108                .map(|s| PathBuf::from(s).into_boxed_path()),
109            rdf_database: std::env::var("FLAMS_RDF_DATABASE")
110                .ok()
111                .map(|s| PathBuf::from(s).into_boxed_path()),
112            stack_size: std::env::var("FLAMS_STACK_SIZE").ok().map(|s| {
113                s.parse().expect(
114                    "Could not parse stack size parameter (environment variable FLAMS_STACK_SIZE)",
115                )
116            }),
117            server: ServerSettings {
118                port: std::env::var("FLAMS_PORT")
119                    .ok()
120                    .and_then(|s| s.parse().ok())
121                    .unwrap_or_default(),
122                ip: std::env::var("FLAMS_IP").ok().map(|s| {
123                    s.parse()
124                        .expect("Could not parse IP address (environment variable FLAMS_IP)")
125                }),
126                external_url: std::env::var("FLAMS_EXTERNAL_URL").ok(),
127                admin_pwd: std::env::var("FLAMS_ADMIN_PWD").ok(),
128            },
129            buildqueue: BuildQueueSettings {
130                num_threads: std::env::var("FLAMS_NUM_THREADS")
131                    .ok()
132                    .and_then(|s| s.parse().ok()),
133            },
134            gitlab: GitlabSettings {
135                url: std::env::var("FLAMS_GITLAB_URL").ok().map(|s| {
136                    s.parse()
137                        .expect("Could not parse URL (environment variable FLAMS_GITLAB_URL)")
138                }),
139                token: std::env::var("FLAMS_GITLAB_TOKEN").ok().map(Into::into),
140                app_id: std::env::var("FLAMS_GITLAB_APP_ID").ok().map(Into::into),
141                app_secret: std::env::var("FLAMS_GITLAB_APP_SECRET")
142                    .ok()
143                    .map(Into::into),
144                redirect_url: std::env::var("FLAMS_GITLAB_REDIRECT_URL")
145                    .ok()
146                    .map(Into::into),
147            },
148            lsp: false,
149        }
150    }
151}
152
153#[derive(Debug, Default, Clone)]
154#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
155pub struct ServerSettings {
156    #[cfg_attr(feature = "serde", serde(default))]
157    pub port: u16,
158    #[cfg_attr(feature = "serde", serde(default))]
159    pub ip: Option<std::net::IpAddr>,
160    #[cfg_attr(feature = "serde", serde(default))]
161    pub admin_pwd: Option<String>,
162    #[cfg_attr(feature = "serde", serde(default))]
163    pub external_url: Option<String>,
164}
165impl Add for ServerSettings {
166    type Output = Self;
167    fn add(self, rhs: Self) -> Self::Output {
168        Self {
169            port: if self.port == 0 { rhs.port } else { self.port },
170            ip: self.ip.or(rhs.ip),
171            admin_pwd: self.admin_pwd.or(rhs.admin_pwd),
172            external_url: self.external_url.or(rhs.external_url),
173        }
174    }
175}
176impl AddAssign for ServerSettings {
177    fn add_assign(&mut self, rhs: Self) {
178        if self.port == 0 {
179            self.port = rhs.port;
180        }
181        if self.ip.is_none() {
182            self.ip = rhs.ip;
183        }
184        if self.admin_pwd.is_none() {
185            self.admin_pwd = rhs.admin_pwd;
186        }
187        if self.external_url.is_none() {
188            self.external_url = rhs.external_url;
189        }
190    }
191}
192
193#[derive(Debug, Default, Clone)]
194#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
195pub struct BuildQueueSettings {
196    #[cfg_attr(feature = "serde", serde(default))]
197    pub num_threads: Option<u8>,
198}
199impl Add for BuildQueueSettings {
200    type Output = Self;
201    fn add(self, rhs: Self) -> Self::Output {
202        Self {
203            num_threads: self.num_threads.or(rhs.num_threads),
204        }
205    }
206}
207impl AddAssign for BuildQueueSettings {
208    fn add_assign(&mut self, rhs: Self) {
209        if self.num_threads.is_none() {
210            self.num_threads = rhs.num_threads;
211        }
212    }
213}
214
215#[derive(Debug, Default, Clone)]
216#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
217pub struct GitlabSettings {
218    #[cfg_attr(feature = "serde", serde(default))]
219    pub url: Option<url::Url>,
220    #[cfg_attr(feature = "serde", serde(default))]
221    pub token: Option<Box<str>>,
222    #[cfg_attr(feature = "serde", serde(default))]
223    pub app_id: Option<Box<str>>,
224    #[cfg_attr(feature = "serde", serde(default))]
225    pub app_secret: Option<Box<str>>,
226    #[cfg_attr(feature = "serde", serde(default))]
227    pub redirect_url: Option<Box<str>>,
228}
229
230impl Add for GitlabSettings {
231    type Output = Self;
232    fn add(self, rhs: Self) -> Self::Output {
233        Self {
234            url: self.url.or(rhs.url),
235            token: self.token.or(rhs.token),
236            app_id: self.app_id.or(rhs.app_id),
237            app_secret: self.app_secret.or(rhs.app_secret),
238            redirect_url: self.redirect_url.or(rhs.redirect_url),
239        }
240    }
241}
242impl AddAssign for GitlabSettings {
243    fn add_assign(&mut self, rhs: Self) {
244        if self.url.is_none() {
245            self.url = rhs.url;
246        }
247        if self.token.is_none() {
248            self.token = rhs.token;
249        }
250        if self.app_id.is_none() {
251            self.app_id = rhs.app_id;
252        }
253        if self.app_secret.is_none() {
254            self.app_secret = rhs.app_secret;
255        }
256        if self.redirect_url.is_none() {
257            self.redirect_url = rhs.redirect_url;
258        }
259    }
260}