1use std::{collections::HashMap, sync::Arc};
2
3pub struct SettingsSerializer {
4 pub database: Arc<crate::database::Database>,
5
6 prefix: compact_str::CompactString,
7 keys: Vec<compact_str::CompactString>,
8 values: Vec<compact_str::CompactString>,
9}
10
11impl SettingsSerializer {
12 pub(crate) fn new(
13 database: Arc<crate::database::Database>,
14 prefix: impl Into<compact_str::CompactString>,
15 ) -> Self {
16 Self {
17 database,
18 prefix: prefix.into(),
19 keys: Vec::new(),
20 values: Vec::new(),
21 }
22 }
23
24 pub(crate) fn key_prefix(&self, key: impl AsRef<str>) -> compact_str::CompactString {
25 compact_str::format_compact!("{}::{}", self.prefix, key.as_ref())
26 }
27
28 pub(crate) fn nest_prefix(&self, nested_prefix: &str) -> compact_str::CompactString {
29 compact_str::format_compact!(
30 "{}{}{}",
31 self.prefix,
32 if self.prefix.is_empty() { "" } else { "::" },
33 nested_prefix
34 )
35 }
36
37 pub fn write_raw_setting(
39 mut self,
40 key: impl AsRef<str>,
41 value: impl Into<compact_str::CompactString>,
42 ) -> Self {
43 self.keys.push(self.key_prefix(key));
44 self.values.push(value.into());
45
46 self
47 }
48
49 pub async fn write_raw_encrypted_setting(
51 mut self,
52 key: impl AsRef<str>,
53 value: impl Into<compact_str::CompactString>,
54 ) -> Result<Self, anyhow::Error> {
55 let encrypted_value = self.database.encrypt_base64(value.into()).await?;
56
57 self.keys.push(self.key_prefix(key));
58 self.values.push(encrypted_value);
59
60 Ok(self)
61 }
62
63 pub fn write_serde_setting(
65 mut self,
66 key: impl AsRef<str>,
67 value: &impl serde::Serialize,
68 ) -> Result<Self, serde_json::Error> {
69 let serialized = serde_json::to_string(value)?;
70 self.keys.push(self.key_prefix(key));
71 self.values
72 .push(compact_str::CompactString::from(serialized));
73
74 Ok(self)
75 }
76
77 pub async fn write_serde_encrypted_setting(
79 mut self,
80 key: impl AsRef<str>,
81 value: &impl serde::Serialize,
82 ) -> Result<Self, anyhow::Error> {
83 let serialized = serde_json::to_string(value)?;
84 let encrypted_value = self.database.encrypt_base64(serialized).await?;
85
86 self.keys.push(self.key_prefix(key));
87 self.values.push(encrypted_value);
88
89 Ok(self)
90 }
91
92 pub async fn nest(
94 mut self,
95 nested_prefix: &str,
96 settings: &impl SettingsSerializeExt,
97 ) -> Result<Self, anyhow::Error> {
98 let serializer = Self::new(self.database.clone(), self.nest_prefix(nested_prefix));
99
100 let nested_serializer = settings.serialize(serializer).await?;
101
102 self.keys.extend(nested_serializer.keys);
103 self.values.extend(nested_serializer.values);
104
105 Ok(self)
106 }
107
108 pub fn merge(mut self, other: SettingsSerializer) -> Self {
109 self.keys.extend(other.keys);
110 self.values.extend(other.values);
111
112 self
113 }
114
115 pub(crate) fn into_parts(
116 self,
117 ) -> (
118 Vec<compact_str::CompactString>,
119 Vec<compact_str::CompactString>,
120 ) {
121 (self.keys, self.values)
122 }
123}
124
125pub struct SettingsDeserializer<'a> {
126 pub database: Arc<crate::database::Database>,
127
128 pub(crate) prefix: compact_str::CompactString,
129 pub(crate) settings: &'a mut HashMap<compact_str::CompactString, compact_str::CompactString>,
130}
131
132impl<'a> SettingsDeserializer<'a> {
133 pub(crate) fn new(
134 database: Arc<crate::database::Database>,
135 prefix: impl Into<compact_str::CompactString>,
136 settings: &'a mut HashMap<compact_str::CompactString, compact_str::CompactString>,
137 ) -> Self {
138 Self {
139 database,
140 prefix: prefix.into(),
141 settings,
142 }
143 }
144
145 pub(crate) fn key_prefix(&self, key: impl AsRef<str>) -> compact_str::CompactString {
146 compact_str::format_compact!("{}::{}", self.prefix, key.as_ref())
147 }
148
149 pub(crate) fn nest_prefix(&self, nested_prefix: &str) -> compact_str::CompactString {
150 compact_str::format_compact!(
151 "{}{}{}",
152 self.prefix,
153 if self.prefix.is_empty() { "" } else { "::" },
154 nested_prefix
155 )
156 }
157
158 pub fn read_raw_setting(&self, key: impl AsRef<str>) -> Option<&compact_str::CompactString> {
160 self.settings.get(&self.key_prefix(key))
161 }
162
163 pub async fn read_raw_encrypted_setting(
165 &self,
166 key: impl AsRef<str>,
167 ) -> Result<Option<compact_str::CompactString>, anyhow::Error> {
168 match self.settings.get(&self.key_prefix(key)) {
169 Some(encrypted_value) => {
170 let decrypted = self.database.decrypt_base64(encrypted_value).await?;
171 Ok(Some(decrypted))
172 }
173 None => Ok(None),
174 }
175 }
176
177 pub fn take_raw_setting(&mut self, key: impl AsRef<str>) -> Option<compact_str::CompactString> {
179 self.settings.remove(&self.key_prefix(key))
180 }
181
182 pub fn read_serde_setting<T: serde::de::DeserializeOwned>(
184 &self,
185 key: impl AsRef<str>,
186 ) -> Result<T, serde_json::Error> {
187 let value = match self.settings.get(&self.key_prefix(key)) {
188 Some(v) => v,
189 None => return serde_json::from_value(serde_json::Value::Null),
190 };
191
192 serde_json::from_str(value)
193 }
194
195 pub async fn read_serde_encrypted_setting<T: serde::de::DeserializeOwned>(
197 &self,
198 key: impl AsRef<str>,
199 ) -> Result<Option<T>, anyhow::Error> {
200 match self.settings.get(&self.key_prefix(key)) {
201 Some(encrypted_value) => {
202 let decrypted = self.database.decrypt_base64(encrypted_value).await?;
203 let deserialized = serde_json::from_str(&decrypted)?;
204 Ok(Some(deserialized))
205 }
206 None => Ok(None),
207 }
208 }
209
210 pub async fn nest<T: 'static>(
212 &mut self,
213 nested_prefix: &str,
214 deserializer: &(dyn SettingsDeserializeExt + Send + Sync),
215 ) -> Result<T, anyhow::Error> {
216 let settings_deserializer = SettingsDeserializer::new(
217 self.database.clone(),
218 self.nest_prefix(nested_prefix),
219 self.settings,
220 );
221
222 let boxed = deserializer
223 .deserialize_boxed(settings_deserializer)
224 .await?;
225
226 match (boxed as Box<dyn std::any::Any + Send + Sync>).downcast::<T>() {
227 Ok(concrete_box) => Ok(*concrete_box),
228 Err(_) => Err(anyhow::anyhow!(
229 "Type mismatch: expected {}, but nested prefix {} returned a different type",
230 std::any::type_name::<T>(),
231 nested_prefix
232 )),
233 }
234 }
235}
236
237pub type ExtensionSettings = Box<dyn SettingsSerializeExt + Send + Sync + 'static>;
238pub type ExtensionSettingsDeserializer = Arc<dyn SettingsDeserializeExt + Send + Sync + 'static>;
239
240#[async_trait::async_trait]
241pub trait SettingsSerializeExt: std::any::Any + Send + Sync {
242 async fn serialize(
243 &self,
244 serializer: SettingsSerializer,
245 ) -> Result<SettingsSerializer, anyhow::Error>;
246}
247
248#[async_trait::async_trait]
249pub trait SettingsDeserializeExt {
250 async fn deserialize_boxed(
251 &self,
252 deserializer: SettingsDeserializer<'_>,
253 ) -> Result<ExtensionSettings, anyhow::Error>;
254}
255
256#[async_trait::async_trait]
257impl<T: SettingsSerializeExt + ?Sized + Send + Sync> SettingsSerializeExt for Box<T> {
258 async fn serialize(
259 &self,
260 serializer: SettingsSerializer,
261 ) -> Result<SettingsSerializer, anyhow::Error> {
262 (**self).serialize(serializer).await
263 }
264}
265
266#[async_trait::async_trait]
267impl<T: SettingsDeserializeExt + ?Sized + Send + Sync> SettingsDeserializeExt for Arc<T> {
268 async fn deserialize_boxed(
269 &self,
270 deserializer: SettingsDeserializer<'_>,
271 ) -> Result<ExtensionSettings, anyhow::Error> {
272 (**self).deserialize_boxed(deserializer).await
273 }
274}
275
276pub struct EmptySettings;
277
278#[async_trait::async_trait]
279impl SettingsSerializeExt for EmptySettings {
280 async fn serialize(
281 &self,
282 serializer: SettingsSerializer,
283 ) -> Result<SettingsSerializer, anyhow::Error> {
284 Ok(serializer)
285 }
286}
287
288#[async_trait::async_trait]
289impl SettingsDeserializeExt for EmptySettings {
290 async fn deserialize_boxed(
291 &self,
292 _deserializer: SettingsDeserializer<'_>,
293 ) -> Result<ExtensionSettings, anyhow::Error> {
294 Ok(Box::new(EmptySettings))
295 }
296}