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