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 #[serde(default = "default_plugin_verify")]
172 pub plugin_verify: bool,
173}
174
175fn default_plugin_verify() -> bool {
176 true
177}
178
179impl Default for Config {
180 fn default() -> Self {
181 Self {
182 port: 8080,
183 name: "Rainbeam".to_string(),
184 description: "Ask, share, socialize!".to_string(),
185 static_dir: PathBufD::new(),
186 media_dir: PathBufD::new(),
187 captcha: HCaptchaConfig::default(),
188 real_ip_header: Option::None,
189 registration_enabled: true,
190 host: String::new(),
191 snowflake_server_id: 1234567890,
192 blocked_hosts: Vec::new(),
193 tiers: Tiers::default(),
194 alert: String::new(),
195 templates: TemplatesConfig::default(),
196 plugin_verify: default_plugin_verify(),
197 }
198 }
199}
200
201impl Config {
202 pub fn read(contents: String) -> Self {
204 toml::from_str::<Self>(&contents).unwrap()
205 }
206
207 pub fn get_config() -> Self {
209 let path = PathBufD::current().extend(&[".config", "config.toml"]);
210
211 match fs::read(&path) {
212 Ok(c) => {
213 let c = Config::read(c);
214
215 c.templates
217 .read_config(path.as_path().parent().unwrap().to_str().unwrap());
218
219 c
221 }
222 Err(_) => {
223 Self::update_config(Self::default()).expect("failed to write default config");
224 Self::default()
225 }
226 }
227 }
228
229 pub fn update_config(contents: Self) -> Result<()> {
231 let c = fs::canonicalize(".").unwrap();
232 let here = c.to_str().unwrap();
233
234 fs::write(
235 format!("{here}/.config/config.toml"),
236 toml::to_string_pretty::<Self>(&contents).unwrap(),
237 )
238 }
239}