barreleye_common/
settings.rs1use config::{Config, Environment, File};
2use directories::BaseDirs;
3use eyre::Result;
4use serde::Deserialize;
5use std::{env::var, fs, fs::OpenOptions, path::PathBuf};
6use url::Url;
7
8use crate::{
9 cache::Driver as CacheDriver, db::Driver as DatabaseDriver, errors::AppError, quit, utils,
10 warehouse::Driver as WarehouseDriver,
11};
12
13pub static DEFAULT_SETTINGS_FILENAME: &str = "barreleye.toml";
14pub static DEFAULT_SETTINGS_CONTENT: &str = r#"
15sdn_refresh_rate = 3600 # in seconds
16primary_ping = 2 # in seconds
17primary_promotion = 20 # in seconds
18
19[server]
20ip_v4 = "0.0.0.0"
21ip_v6 = "::"
22port = 22775
23
24[cache]
25driver = "rocksdb"
26
27[db]
28driver = "sqlite" # or "postgres" or "mysql"
29min_connections = 5
30max_connections = 100
31connect_timeout = 8
32idle_timeout = 8
33max_lifetime = 8
34
35[warehouse]
36driver = "clickhouse"
37
38[dsn]
39rocksdb = "rocksdb://barreleye_cache"
40sqlite = "sqlite://barreleye_database?mode=rwc"
41postgres = "" # eg: "postgres://USERNAME[:PASSWORD]@localhost:5432/database"
42mysql = "" # eg: "mysql://USERNAME[:PASSWORD]@localhost:3306/database"
43clickhouse = "" # eg: "http://USERNAME[:PASSWORD]@localhost:8123/database"
44"#;
45
46#[derive(Debug, Deserialize)]
47pub struct Settings {
48 pub sdn_refresh_rate: u64,
49 pub primary_ping: u64,
50 pub primary_promotion: u64,
51 pub server: Server,
52 pub cache: Cache,
53 pub db: Db,
54 pub warehouse: Warehouse,
55 pub dsn: Dsn,
56}
57
58#[derive(Debug, Deserialize)]
59pub struct Server {
60 pub ip_v4: String,
61 pub ip_v6: String,
62 pub port: u16,
63}
64
65#[derive(Debug, Deserialize)]
66pub struct Cache {
67 pub driver: CacheDriver,
68}
69
70#[derive(Debug, Deserialize)]
71pub struct Db {
72 pub driver: DatabaseDriver,
73 pub min_connections: u32,
74 pub max_connections: u32,
75 pub connect_timeout: u64,
76 pub idle_timeout: u64,
77 pub max_lifetime: u64,
78}
79
80#[derive(Debug, Deserialize)]
81pub struct Warehouse {
82 pub driver: WarehouseDriver,
83}
84
85#[derive(Debug, Deserialize)]
86pub struct Dsn {
87 pub rocksdb: String,
88 pub sqlite: String,
89 pub postgres: String,
90 pub mysql: String,
91 pub clickhouse: String,
92}
93
94impl Settings {
95 pub fn new(config_path: Option<String>) -> Result<Self> {
96 let config_path = {
98 let mut ret = None;
99
100 if let Some(filename) = config_path {
102 let try_filename = PathBuf::from(filename.clone());
103 if try_filename.exists() {
104 ret = Some(try_filename);
105 } else {
106 quit(AppError::MissingConfigFile { filename });
107 }
108 } else {
109 let mut paths = vec![];
111 if let Ok(manifest_dir) = var("CARGO_MANIFEST_DIR") {
112 paths.push(PathBuf::from(manifest_dir).join(DEFAULT_SETTINGS_FILENAME))
113 }
114 paths.push(std::env::current_exe()?.join(DEFAULT_SETTINGS_FILENAME));
115 if let Some(base_dir) = BaseDirs::new() {
116 paths.push(
117 PathBuf::from(base_dir.config_dir())
118 .join("barreleye")
119 .join(DEFAULT_SETTINGS_FILENAME),
120 );
121 }
122
123 for path in paths.clone().into_iter() {
125 if path.exists() {
126 ret = Some(path);
127 break;
128 }
129 }
130
131 if ret.is_none() {
133 for path in paths.into_iter() {
134 if OpenOptions::new()
135 .write(true)
136 .create_new(true)
137 .open(path.clone())
138 .is_ok()
139 {
140 fs::write(path.clone(), DEFAULT_SETTINGS_CONTENT.trim())?;
141
142 ret = Some(path);
143 break;
144 }
145 }
146 }
147
148 if ret.is_none() {
150 quit(AppError::DefaultConfigFile);
151 }
152 }
153
154 ret.unwrap()
155 };
156
157 let s = Config::builder()
159 .add_source(File::from(config_path).required(false))
160 .add_source(Environment::with_prefix("BARRELEYE"));
161
162 let settings: Settings = s.build()?.try_deserialize()?;
164
165 if settings.cache.driver == CacheDriver::RocksDB &&
167 utils::get_db_path(&settings.dsn.rocksdb).is_empty()
168 {
169 quit(AppError::InvalidSetting {
170 key: "dsn.rocksdb".to_string(),
171 value: settings.dsn.rocksdb.clone(),
172 });
173 }
174
175 if settings.warehouse.driver == WarehouseDriver::Clickhouse &&
177 Url::parse(&settings.dsn.clickhouse).is_err()
178 {
179 quit(AppError::InvalidSetting {
180 key: "dsn.clickhouse".to_string(),
181 value: settings.dsn.clickhouse.clone(),
182 });
183 }
184
185 let db_url = match settings.db.driver {
187 DatabaseDriver::SQLite => settings.dsn.sqlite.clone(),
188 DatabaseDriver::PostgreSQL => settings.dsn.postgres.clone(),
189 DatabaseDriver::MySQL => settings.dsn.mysql.clone(),
190 };
191 if Url::parse(&db_url).is_err() {
192 quit(AppError::InvalidSetting {
193 key: format!("dsn.{}", settings.db.driver),
194 value: db_url,
195 });
196 }
197
198 if settings.primary_promotion < settings.primary_ping * 3 {
200 quit(AppError::InvalidPrimaryConfigs);
201 }
202
203 Ok(settings)
204 }
205}