1use std::{io::prelude::*, path::PathBuf};
2
3use atuin_server_database::DbSettings;
4use config::{Config, Environment, File as ConfigFile, FileFormat};
5use eyre::{Result, eyre};
6use fs_err::{File, create_dir_all};
7use serde::{Deserialize, Serialize};
8
9static EXAMPLE_CONFIG: &str = include_str!("../server.toml");
10
11#[derive(Default, Clone, Debug, Deserialize, Serialize)]
12pub struct Mail {
13 #[serde(alias = "enable")]
14 pub enabled: bool,
15
16 #[serde(default)]
19 pub postmark: Postmark,
20
21 #[serde(default)]
22 pub verification: MailVerification,
23}
24
25#[derive(Default, Clone, Debug, Deserialize, Serialize)]
26pub struct Postmark {
27 #[serde(alias = "token")]
28 pub token: Option<String>,
29}
30
31#[derive(Default, Clone, Debug, Deserialize, Serialize)]
32pub struct MailVerification {
33 #[serde(alias = "enable")]
34 pub from: String,
35 pub subject: String,
36}
37
38#[derive(Clone, Debug, Deserialize, Serialize)]
39pub struct Metrics {
40 #[serde(alias = "enabled")]
41 pub enable: bool,
42 pub host: String,
43 pub port: u16,
44}
45
46impl Default for Metrics {
47 fn default() -> Self {
48 Self {
49 enable: false,
50 host: String::from("127.0.0.1"),
51 port: 9001,
52 }
53 }
54}
55
56#[derive(Clone, Debug, Deserialize, Serialize)]
57pub struct Settings {
58 pub host: String,
59 pub port: u16,
60 pub path: String,
61 pub open_registration: bool,
62 pub max_history_length: usize,
63 pub max_record_size: usize,
64 pub page_size: i64,
65 pub register_webhook_url: Option<String>,
66 pub register_webhook_username: String,
67 pub metrics: Metrics,
68 pub tls: Tls,
69 pub mail: Mail,
70
71 pub sync_v1_enabled: bool,
74
75 pub fake_version: Option<String>,
81
82 #[serde(flatten)]
83 pub db_settings: DbSettings,
84}
85
86impl Settings {
87 pub fn new() -> Result<Self> {
88 let mut config_file = if let Ok(p) = std::env::var("ATUIN_CONFIG_DIR") {
89 PathBuf::from(p)
90 } else {
91 let mut config_file = PathBuf::new();
92 let config_dir = atuin_common::utils::config_dir();
93 config_file.push(config_dir);
94 config_file
95 };
96
97 config_file.push("server.toml");
98
99 let mut config_builder = Config::builder()
101 .set_default("host", "127.0.0.1")?
102 .set_default("port", 8888)?
103 .set_default("open_registration", false)?
104 .set_default("max_history_length", 8192)?
105 .set_default("max_record_size", 1024 * 1024 * 1024)? .set_default("path", "")?
107 .set_default("register_webhook_username", "")?
108 .set_default("page_size", 1100)?
109 .set_default("metrics.enable", false)?
110 .set_default("metrics.host", "127.0.0.1")?
111 .set_default("metrics.port", 9001)?
112 .set_default("mail.enable", false)?
113 .set_default("tls.enable", false)?
114 .set_default("tls.cert_path", "")?
115 .set_default("tls.pkey_path", "")?
116 .set_default("sync_v1_enabled", true)?
117 .add_source(
118 Environment::with_prefix("atuin")
119 .prefix_separator("_")
120 .separator("__"),
121 );
122
123 config_builder = if config_file.exists() {
124 config_builder.add_source(ConfigFile::new(
125 config_file.to_str().unwrap(),
126 FileFormat::Toml,
127 ))
128 } else {
129 create_dir_all(config_file.parent().unwrap())?;
130 let mut file = File::create(config_file)?;
131 file.write_all(EXAMPLE_CONFIG.as_bytes())?;
132
133 config_builder
134 };
135
136 let config = config_builder.build()?;
137
138 config
139 .try_deserialize()
140 .map_err(|e| eyre!("failed to deserialize: {}", e))
141 }
142}
143
144pub fn example_config() -> &'static str {
145 EXAMPLE_CONFIG
146}
147
148#[derive(Clone, Debug, Default, Deserialize, Serialize)]
149pub struct Tls {
150 #[serde(alias = "enabled")]
151 pub enable: bool,
152
153 pub cert_path: PathBuf,
154 pub pkey_path: PathBuf,
155}