1use crate::{Error, Result};
2use std::{fs::File, io::Read, path::PathBuf};
3
4use serde::Deserialize;
5
6#[derive(Debug, Clone, Deserialize)]
8#[serde(default)]
9pub struct CoreSettings {
10 pub name: String,
11 pub secret_key: String,
12 pub language_code: String,
13 pub timezone: String,
14}
15
16impl Default for CoreSettings {
17 fn default() -> Self {
18 Self {
19 name: "DEFAULT_NAME".to_string(),
20 secret_key: "DEFAULT_SECRET_KEY".to_string(),
21 language_code: "en-us".to_string(),
22 timezone: "UTC".to_string(),
23 }
24 }
25}
26
27#[derive(Debug, Clone, Deserialize)]
29pub struct DatabaseSettings {
30 pub url: String,
31
32 #[serde(rename = "type")]
33 pub type_: String,
34}
35
36#[derive(Debug, Clone, Deserialize)]
40pub struct Settings {
41 #[serde(default)]
42 pub core: CoreSettings,
43 pub database: DatabaseSettings,
44}
45
46impl Settings {
47 pub fn builder() -> SettingsBuilder {
48 SettingsBuilder::new()
49 }
50}
51
52pub struct SettingsBuilder {
82 core: Option<CoreSettings>,
83 database: Option<DatabaseSettings>,
84 ron_path: Option<PathBuf>,
85}
86
87impl SettingsBuilder {
88 pub fn new() -> Self {
90 Self {
91 core: None,
92 database: None,
93 ron_path: None,
94 }
95 }
96
97 pub fn core(mut self, core: CoreSettings) -> Self {
99 self.core = Some(core);
100 self
101 }
102
103 pub fn database(mut self, database: DatabaseSettings) -> Self {
105 self.database = Some(database);
106 self
107 }
108
109 fn load_ron(mut self, path: PathBuf) -> Result<Self> {
110 let mut file = File::open(path).expect("Failed to open settings file");
112 let mut contents = String::new();
113 file.read_to_string(&mut contents)
114 .map_err(|_| Error::RonRead)?;
115
116 let settings: Settings = ron::from_str(&contents).expect("Failed to parse settings file");
118
119 self.core = Some(settings.core);
121 self.database = Some(settings.database);
122
123 Ok(self)
124 }
125
126 pub fn extend_ron<P: Into<PathBuf> + std::fmt::Debug>(mut self, path: P) -> Self {
128 self.ron_path = Some(path.into());
129
130 self
131 }
132
133 pub fn build(mut self) -> Result<Settings> {
135 if let Some(path) = self.ron_path.to_owned() {
136 self = self.load_ron(path)?;
137 }
138
139 let core = self.core.expect("Core settings are required");
140 let database = self.database.expect("Database settings are required");
141
142 if core.secret_key == "DEFAULT_SECRET_KEY" {
143 panic!("You must set a secret key");
144 }
145
146 Ok(Settings { core, database })
147 }
148}