rainbeam_shared/
config.rs1use pathbufd::PathBufD;
3use serde::{Deserialize, Serialize};
4use std::fs::read_to_string;
5use std::io::Result;
6use std::sync::{LazyLock, RwLock};
7use crate::fs;
8
9#[derive(Clone, Serialize, Deserialize, Debug)]
10pub struct HCaptchaConfig {
11 pub site_key: String,
15 pub secret: String,
19}
20
21impl Default for HCaptchaConfig {
22 fn default() -> Self {
23 Self {
24 site_key: "10000000-ffff-ffff-ffff-000000000001".to_string(),
26 secret: "0x0000000000000000000000000000000000000000".to_string(),
27 }
28 }
29}
30
31#[derive(Clone, Serialize, Deserialize, Debug)]
33pub struct Tiers {
34 #[serde(default)]
42 pub double_limits: i32,
43 #[serde(default)]
45 pub avatar_crown: i32,
46 #[serde(default)]
48 pub profile_badge: i32,
49}
50
51impl Default for Tiers {
52 fn default() -> Self {
54 Self {
55 double_limits: 1,
56 avatar_crown: 1,
57 profile_badge: 1,
58 }
59 }
60}
61
62#[derive(Clone, Serialize, Deserialize, Debug)]
64pub struct TemplatesConfig {
65 pub header: String,
67 pub body: String,
69}
70
71impl Default for TemplatesConfig {
72 fn default() -> Self {
73 Self {
74 header: String::new(),
75 body: String::new(),
76 }
77 }
78}
79
80pub static TEMPLATE_ADDONS: LazyLock<RwLock<TemplatesConfig>> = LazyLock::new(|| RwLock::default());
81
82macro_rules! get_tmpl {
83 ($name:ident) => {
84 pub fn $name(&self) -> String {
86 let r = TEMPLATE_ADDONS.read().unwrap();
87 (*r).$name.to_string()
88 }
89 };
90}
91
92macro_rules! read_tmpl {
93 ($self:expr => $rel:ident->$name:ident) => {{
94 let v = &$self.$name;
95
96 if v.is_empty() {
97 String::new()
98 } else {
99 Self::read_template(PathBufD::new().extend(&[$rel, v]))
100 }
101 }};
102}
103
104impl TemplatesConfig {
105 pub fn read_template(path: PathBufD) -> String {
107 match read_to_string(path) {
108 Ok(s) => s,
109 Err(_) => String::new(),
110 }
111 }
112
113 pub fn read_config(&self, relative: &str) -> () {
115 let mut w = TEMPLATE_ADDONS.write().unwrap();
116 *w = TemplatesConfig {
117 header: read_tmpl!(&self => relative->header),
118 body: read_tmpl!(&self => relative->body),
119 }
120 }
121
122 get_tmpl!(header);
124 get_tmpl!(body);
125}
126
127#[derive(Clone, Serialize, Deserialize, Debug)]
129pub struct Config {
130 pub port: u16,
132 pub name: String,
134 pub description: String,
136 #[serde(default)]
138 pub static_dir: PathBufD,
139 #[serde(default)]
141 pub media_dir: PathBufD,
142 pub captcha: HCaptchaConfig,
144 pub real_ip_header: Option<String>,
146 #[serde(default)]
148 pub registration_enabled: bool,
149 #[serde(default)]
153 pub host: String,
154 pub snowflake_server_id: usize,
156 #[serde(default)]
158 pub blocked_hosts: Vec<String>,
159 #[serde(default)]
161 pub tiers: Tiers,
162 #[serde(default)]
164 pub alert: String,
165 #[serde(default)]
167 pub templates: TemplatesConfig,
168}
169
170impl Default for Config {
171 fn default() -> Self {
172 Self {
173 port: 8080,
174 name: "Rainbeam".to_string(),
175 description: "Ask, share, socialize!".to_string(),
176 static_dir: PathBufD::new(),
177 media_dir: PathBufD::new(),
178 captcha: HCaptchaConfig::default(),
179 real_ip_header: Option::None,
180 registration_enabled: true,
181 host: String::new(),
182 snowflake_server_id: 1234567890,
183 blocked_hosts: Vec::new(),
184 tiers: Tiers::default(),
185 alert: String::new(),
186 templates: TemplatesConfig::default(),
187 }
188 }
189}
190
191impl Config {
192 pub fn read(contents: String) -> Self {
194 toml::from_str::<Self>(&contents).unwrap()
195 }
196
197 pub fn get_config() -> Self {
199 let path = PathBufD::current().extend(&[".config", "config.toml"]);
200
201 match fs::read(&path) {
202 Ok(c) => {
203 let c = Config::read(c);
204
205 c.templates
207 .read_config(path.as_path().parent().unwrap().to_str().unwrap());
208
209 c
211 }
212 Err(_) => {
213 Self::update_config(Self::default()).expect("failed to write default config");
214 Self::default()
215 }
216 }
217 }
218
219 pub fn update_config(contents: Self) -> Result<()> {
221 let c = fs::canonicalize(".").unwrap();
222 let here = c.to_str().unwrap();
223
224 fs::write(
225 format!("{here}/.config/config.toml"),
226 toml::to_string_pretty::<Self>(&contents).unwrap(),
227 )
228 }
229}