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 }, 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}