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)]
64#[derive(Default)]
65pub struct TemplatesConfig {
66 pub header: String,
68 pub body: String,
70}
71
72
73pub static TEMPLATE_ADDONS: LazyLock<RwLock<TemplatesConfig>> = LazyLock::new(RwLock::default);
74
75macro_rules! get_tmpl {
76 ($name:ident) => {
77 pub fn $name(&self) -> String {
79 let r = TEMPLATE_ADDONS.read().unwrap();
80 (*r).$name.to_string()
81 }
82 };
83}
84
85macro_rules! read_tmpl {
86 ($self:expr => $rel:ident->$name:ident) => {{
87 let v = &$self.$name;
88
89 if v.is_empty() {
90 String::new()
91 } else {
92 Self::read_template(PathBufD::new().extend(&[$rel, v]))
93 }
94 }};
95}
96
97impl TemplatesConfig {
98 pub fn read_template(path: PathBufD) -> String {
100 read_to_string(path).unwrap_or_default()
101 }
102
103 pub fn read_config(&self, relative: &str) {
105 let mut w = TEMPLATE_ADDONS.write().unwrap();
106 *w = TemplatesConfig {
107 header: read_tmpl!(&self => relative->header),
108 body: read_tmpl!(&self => relative->body),
109 }
110 }
111
112 get_tmpl!(header);
114 get_tmpl!(body);
115}
116
117#[derive(Clone, Serialize, Deserialize, Debug)]
119pub struct Config {
120 pub port: u16,
122 pub name: String,
124 pub description: String,
126 #[serde(default)]
128 pub static_dir: PathBufD,
129 #[serde(default)]
131 pub media_dir: PathBufD,
132 pub captcha: HCaptchaConfig,
134 pub real_ip_header: Option<String>,
136 #[serde(default)]
138 pub registration_enabled: bool,
139 #[serde(default)]
143 pub host: String,
144 pub snowflake_server_id: usize,
146 #[serde(default)]
148 pub blocked_hosts: Vec<String>,
149 #[serde(default)]
151 pub tiers: Tiers,
152 #[serde(default)]
154 pub alert: String,
155 #[serde(default)]
157 pub templates: TemplatesConfig,
158 #[serde(default = "default_plugin_verify")]
162 pub plugin_verify: bool,
163}
164
165fn default_plugin_verify() -> bool {
166 true
167}
168
169impl Default for Config {
170 fn default() -> Self {
171 Self {
172 port: 8080,
173 name: "Rainbeam".to_string(),
174 description: "Ask, share, socialize!".to_string(),
175 static_dir: PathBufD::new(),
176 media_dir: PathBufD::new(),
177 captcha: HCaptchaConfig::default(),
178 real_ip_header: Option::None,
179 registration_enabled: true,
180 host: String::new(),
181 snowflake_server_id: 1234567890,
182 blocked_hosts: Vec::new(),
183 tiers: Tiers::default(),
184 alert: String::new(),
185 templates: TemplatesConfig::default(),
186 plugin_verify: default_plugin_verify(),
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}