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