Skip to main content

flams/server/
settings.rs

1use clap::Parser;
2use core::panic;
3use flams_system::settings::{BuildQueueSettings, ServerSettings, SettingsSpec};
4use flams_utils::settings::GitlabSettings;
5use std::path::{Path, PathBuf};
6
7#[derive(Parser, Debug)]
8#[command(propagate_version = true, version, about, long_about = Some(
9"𝖥𝖫∀𝖬∫ - Flexiformal Annotation Management System\n\
10--------------------------------------------------------------------\n\
11See the \u{1b}]8;;https://github.com/UniFormal/MMT\u{1b}\\documentation\u{1b}]8;;\u{1b}\\ for details"
12))]
13struct Cli {
14    /// a comma-separated list of `MathHub` paths (if not given, the default paths are used
15    /// as determined by the MATHHUB system variable or ~/.mathhub/mathhub.path)
16    #[arg(short, long)]
17    pub(crate) mathhubs: Option<String>,
18
19    /// whether to enable debug logging
20    #[arg(short, long)]
21    pub(crate) debug: Option<bool>,
22
23    #[arg(short, long)]
24    /// The toml config file to use
25    pub(crate) config_file: Option<PathBuf>,
26
27    #[arg(short, long)]
28    /// The log directory to use
29    pub(crate) log_dir: Option<PathBuf>,
30
31    #[arg(long)]
32    /// The stack size in MB used for every thread
33    pub(crate) stack_size: Option<u8>,
34
35    #[arg(long)]
36    /// The directory used for temporary files
37    pub(crate) temp_dir: Option<PathBuf>,
38
39    #[arg(long)]
40    /// The directory used for embedding models for vector search
41    pub(crate) embedding_dir: Option<PathBuf>,
42
43    #[arg(short, long)]
44    /// The admin password to use for the server
45    pub(crate) admin_pwd: Option<String>,
46
47    /// Network port to use for the server
48    #[arg(long,value_parser = clap::value_parser!(u16).range(1..))]
49    pub(crate) port: Option<u16>,
50
51    /// Network address to use for the server
52    #[arg(long)]
53    pub(crate) ip: Option<String>,
54
55    #[arg(long)]
56    pub(crate) external_url: Option<String>,
57
58    #[arg(long)]
59    /// The database file to use for account management etc.
60    pub(crate) db: Option<PathBuf>,
61
62    #[arg(long)]
63    /// The directory to use for the rdf triple store.
64    pub(crate) rdf_database: Option<PathBuf>,
65
66    /// The number of threads to use for the buildqueue
67    #[arg(short, long)]
68    pub(crate) threads: Option<u8>,
69
70    /// enter lsp mode
71    #[arg(long)]
72    pub(crate) lsp: bool,
73
74    #[arg(long)]
75    pub(crate) gitlab_url: Option<String>,
76
77    #[arg(long)]
78    pub(crate) gitlab_token: Option<String>,
79    #[arg(long)]
80    pub(crate) gitlab_app_id: Option<String>,
81    #[arg(long)]
82    pub(crate) gitlab_app_secret: Option<String>,
83    #[arg(long)]
84    pub(crate) gitlab_redirect_url: Option<String>,
85}
86impl From<Cli> for (Option<PathBuf>, SettingsSpec) {
87    /// #### Panics
88    fn from(cli: Cli) -> Self {
89        let settings = SettingsSpec {
90            mathhubs: cli
91                .mathhubs
92                .map(|s| s.split(',').map(|s| PathBuf::from(s.trim())).collect())
93                .unwrap_or_default(),
94            debug: cli.debug,
95            stack_size: cli.stack_size,
96            database: cli.db.map(PathBuf::into_boxed_path),
97            rdf_database: cli.rdf_database.map(PathBuf::into_boxed_path),
98            log_dir: cli.log_dir.map(PathBuf::into_boxed_path),
99            temp_dir: cli.temp_dir.map(PathBuf::into_boxed_path),
100            embedding_dir: cli.embedding_dir.map(PathBuf::into_boxed_path),
101            server: ServerSettings {
102                port: cli.port.unwrap_or_default(),
103                ip: cli.ip.map(|s| s.parse().expect("Illegal ip")),
104                admin_pwd: cli.admin_pwd,
105                external_url: cli.external_url,
106            },
107            buildqueue: BuildQueueSettings {
108                num_threads: cli.threads,
109            },
110            gitlab: GitlabSettings {
111                url: cli.gitlab_url.map(|s| s.parse().expect("Illegal url")),
112                token: cli.gitlab_token.map(Into::into),
113                app_id: cli.gitlab_app_id.map(Into::into),
114                app_secret: cli.gitlab_app_secret.map(Into::into),
115                redirect_url: cli.gitlab_redirect_url.map(Into::into),
116            },
117            lsp: cli.lsp,
118        };
119        (cli.config_file, settings)
120    }
121}
122
123impl Cli {
124    #[must_use]
125    #[inline]
126    fn get() -> Self {
127        Self::parse()
128    }
129}
130
131#[must_use]
132#[allow(clippy::missing_panics_doc)]
133pub fn get_settings() -> SettingsSpec {
134    fn from_file(cfg_file: &Path) -> SettingsSpec {
135        let cfg = std::fs::read_to_string(cfg_file)
136            .unwrap_or_else(|e| panic!("Could not read config file {}: {e}", cfg_file.display()));
137        let cfg: SettingsSpec = toml::from_str(&cfg)
138            .unwrap_or_else(|e| panic!("Could not parse config file {}: {e}", cfg_file.display()));
139        cfg
140    }
141    let cli = Cli::get();
142    let (cfg, mut settings) = cli.into();
143    settings += SettingsSpec::from_envs();
144    if let Some(cfg_file) = cfg {
145        if cfg_file.exists() {
146            settings += from_file(&cfg_file);
147        } else {
148            panic!("Could not find config file {}", cfg_file.display());
149        }
150    } else if let Ok(path) = std::env::current_exe() {
151        if let Some(path) = path.parent() {
152            let path = path.join("settings.toml");
153            if path.exists() {
154                settings += from_file(&path);
155            }
156        }
157    }
158    settings
159}