1use crate::Error;
8use async_trait::async_trait;
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use sos_core::{AccountId, PublicIdentity};
12use std::{
13 collections::HashMap,
14 fmt,
15 ops::{Deref, DerefMut},
16 sync::Arc,
17};
18use tokio::sync::Mutex;
19
20pub type PreferenceStorageProvider<E> =
22 Box<dyn PreferencesStorage<Error = E> + Send + Sync + 'static>;
23
24#[async_trait]
26pub trait PreferenceManager {
27 type Error: std::error::Error
29 + std::fmt::Debug
30 + From<Error>
31 + Send
32 + 'static;
33
34 async fn load_global_preferences(&mut self) -> Result<(), Self::Error>;
36
37 async fn load_account_preferences(
39 &self,
40 accounts: &[PublicIdentity],
41 ) -> Result<(), Self::Error>;
42
43 fn global_preferences(&self) -> Arc<Mutex<Preferences<Self::Error>>>;
45
46 async fn account_preferences(
48 &self,
49 account_id: &AccountId,
50 ) -> Option<Arc<Mutex<Preferences<Self::Error>>>>;
51
52 async fn new_account(
57 &self,
58 account_id: &AccountId,
59 ) -> Result<(), Self::Error>;
60}
61
62#[async_trait]
64pub trait PreferencesStorage {
65 type Error: std::error::Error
67 + std::fmt::Debug
68 + From<Error>
69 + Send
70 + 'static;
71
72 async fn load_preferences(
74 &self,
75 account_id: Option<&AccountId>,
76 ) -> Result<PreferenceMap, Self::Error>;
77
78 async fn insert_preference(
80 &self,
81 account_id: Option<&AccountId>,
82 key: &str,
84 pref: &Preference,
85 ) -> Result<(), Self::Error>;
86
87 async fn remove_preference(
89 &self,
90 account_id: Option<&AccountId>,
91 key: &str,
93 ) -> Result<(), Self::Error>;
94
95 async fn clear_preferences(
97 &self,
98 account_id: Option<&AccountId>,
99 ) -> Result<(), Self::Error>;
101}
102
103pub struct CachedPreferences<E>
105where
106 E: std::error::Error + std::fmt::Debug + From<Error> + Send + 'static,
107{
108 provider: Arc<PreferenceStorageProvider<E>>,
109 globals: Arc<Mutex<Preferences<E>>>,
110 accounts: Mutex<HashMap<AccountId, Arc<Mutex<Preferences<E>>>>>,
111}
112
113#[async_trait]
114impl<E> PreferenceManager for CachedPreferences<E>
115where
116 E: std::error::Error + std::fmt::Debug + From<Error> + Send + 'static,
117{
118 type Error = E;
119
120 async fn load_global_preferences(&mut self) -> Result<(), E> {
122 let mut globals = self.globals.lock().await;
123 let map = globals.provider.load_preferences(None).await?;
124 globals.values = map;
125 Ok(())
126 }
127
128 async fn load_account_preferences(
130 &self,
131 accounts: &[PublicIdentity],
132 ) -> Result<(), E> {
133 for account in accounts {
134 self.new_account(account.account_id()).await?;
135 }
136 Ok(())
137 }
138
139 fn global_preferences(&self) -> Arc<Mutex<Preferences<E>>> {
141 self.globals.clone()
142 }
143
144 async fn account_preferences(
146 &self,
147 account_id: &AccountId,
148 ) -> Option<Arc<Mutex<Preferences<E>>>> {
149 let cache = self.accounts.lock().await;
150 cache.get(account_id).map(Arc::clone)
151 }
152
153 async fn new_account(&self, account_id: &AccountId) -> Result<(), E> {
158 let mut prefs =
159 Preferences::<E>::new(self.provider.clone(), Some(*account_id));
160 prefs.load().await?;
161
162 let mut cache = self.accounts.lock().await;
163 cache.insert(*account_id, Arc::new(Mutex::new(prefs)));
164 Ok(())
165 }
166}
167
168impl<E> CachedPreferences<E>
169where
170 E: std::error::Error + std::fmt::Debug + From<Error> + Send + 'static,
171{
172 pub fn new(provider: Arc<PreferenceStorageProvider<E>>) -> Self {
174 Self {
175 globals: Arc::new(Mutex::new(Preferences::<E>::new(
176 provider.clone(),
177 None,
178 ))),
179 accounts: Mutex::new(HashMap::new()),
180 provider,
181 }
182 }
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187#[serde(untagged)]
188pub enum Preference {
189 Bool(bool),
191 Number(f64),
193 String(String),
195 StringList(Vec<String>),
197 Json(Value),
199}
200
201impl fmt::Display for Preference {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 match self {
204 Self::Bool(val) => write!(f, "{}", val),
205 Self::Number(val) => write!(f, "{}", val),
206 Self::String(val) => write!(f, "{}", val),
207 Self::StringList(val) => {
208 write!(f, "[")?;
209 for (index, s) in val.iter().enumerate() {
210 write!(f, r#""{}""#, s)?;
211 if index < val.len() - 1 {
212 write!(f, ", ")?;
213 }
214 }
215 write!(f, "]")
216 }
217 Self::Json(val) => write!(f, "{:?}", serde_json::to_string(val)),
218 }
219 }
220}
221
222impl From<bool> for Preference {
223 fn from(value: bool) -> Self {
224 Self::Bool(value)
225 }
226}
227
228impl From<f64> for Preference {
229 fn from(value: f64) -> Self {
230 Self::Number(value)
231 }
232}
233
234impl From<i64> for Preference {
235 fn from(value: i64) -> Self {
236 Self::Number(value as f64)
237 }
238}
239
240impl From<String> for Preference {
241 fn from(value: String) -> Self {
242 Self::String(value)
243 }
244}
245
246impl From<Vec<String>> for Preference {
247 fn from(value: Vec<String>) -> Self {
248 Self::StringList(value)
249 }
250}
251
252impl From<Value> for Preference {
253 fn from(value: Value) -> Self {
254 Self::Json(value)
255 }
256}
257
258#[derive(Debug, Default, Clone, Serialize, Deserialize)]
260pub struct PreferenceMap(HashMap<String, Preference>);
261
262impl Deref for PreferenceMap {
263 type Target = HashMap<String, Preference>;
264
265 fn deref(&self) -> &Self::Target {
266 &self.0
267 }
268}
269
270impl DerefMut for PreferenceMap {
271 fn deref_mut(&mut self) -> &mut Self::Target {
272 &mut self.0
273 }
274}
275
276pub struct Preferences<E>
278where
279 E: std::error::Error + std::fmt::Debug + From<Error> + Send + 'static,
280{
281 account_id: Option<AccountId>,
283 values: PreferenceMap,
285 provider: Arc<PreferenceStorageProvider<E>>,
287}
288
289impl<E> Preferences<E>
290where
291 E: std::error::Error + std::fmt::Debug + From<Error> + Send + 'static,
292{
293 pub fn new(
295 provider: Arc<PreferenceStorageProvider<E>>,
296 account_id: Option<AccountId>,
297 ) -> Self {
298 Self {
299 account_id,
300 values: Default::default(),
301 provider,
302 }
303 }
304
305 pub async fn load(&mut self) -> Result<(), E> {
307 self.values = self
308 .provider
309 .load_preferences(self.account_id.as_ref())
310 .await?;
311 Ok(())
312 }
313
314 pub fn len(&self) -> usize {
316 self.values.0.len()
317 }
318
319 pub fn is_empty(&self) -> bool {
321 self.values.0.is_empty()
322 }
323
324 pub fn values(&self) -> &PreferenceMap {
326 &self.values
327 }
328
329 pub fn iter(&self) -> impl Iterator<Item = (&String, &Preference)> {
331 self.values.0.iter()
332 }
333
334 pub fn get_number(
336 &self,
337 key: impl AsRef<str>,
338 ) -> Result<Option<&Preference>, E> {
339 let result = self.values.0.get(key.as_ref());
340 if let Some(res) = result.as_ref() {
341 if matches!(res, Preference::Number(_)) {
342 Ok(result)
343 } else {
344 Err(Error::PreferenceTypeNumber(key.as_ref().to_owned())
345 .into())
346 }
347 } else {
348 Ok(None)
349 }
350 }
351
352 pub fn get_bool(
354 &self,
355 key: impl AsRef<str>,
356 ) -> Result<Option<&Preference>, E> {
357 let result = self.values.0.get(key.as_ref());
358 if let Some(res) = result.as_ref() {
359 if matches!(res, Preference::Bool(_)) {
360 Ok(result)
361 } else {
362 Err(Error::PreferenceTypeBool(key.as_ref().to_owned()).into())
363 }
364 } else {
365 Ok(None)
366 }
367 }
368
369 pub fn get_string(
371 &self,
372 key: impl AsRef<str>,
373 ) -> Result<Option<&Preference>, E> {
374 let result = self.values.0.get(key.as_ref());
375 if let Some(res) = result.as_ref() {
376 if matches!(res, Preference::String(_)) {
377 Ok(result)
378 } else {
379 Err(Error::PreferenceTypeString(key.as_ref().to_owned())
380 .into())
381 }
382 } else {
383 Ok(None)
384 }
385 }
386
387 pub fn get_string_list(
389 &self,
390 key: impl AsRef<str>,
391 ) -> Result<Option<&Preference>, E> {
392 let result = self.values.0.get(key.as_ref());
393 if let Some(res) = result.as_ref() {
394 if matches!(res, Preference::StringList(_)) {
395 Ok(result)
396 } else {
397 Err(Error::PreferenceTypeStringList(key.as_ref().to_owned())
398 .into())
399 }
400 } else {
401 Ok(None)
402 }
403 }
404
405 pub fn get_json_value(
407 &self,
408 key: impl AsRef<str>,
409 ) -> Result<Option<&Preference>, E> {
410 let result = self.values.0.get(key.as_ref());
411 if let Some(res) = result.as_ref() {
412 if matches!(res, Preference::Json(_)) {
413 Ok(result)
414 } else {
415 Err(Error::PreferenceTypeJsonValue(key.as_ref().to_owned())
416 .into())
417 }
418 } else {
419 Ok(None)
420 }
421 }
422
423 pub fn get_unchecked(&self, key: impl AsRef<str>) -> Option<&Preference> {
425 self.values.0.get(key.as_ref())
426 }
427
428 pub async fn insert(
432 &mut self,
433 key: String,
434 value: Preference,
435 ) -> Result<(), E> {
436 self.provider
437 .insert_preference(self.account_id.as_ref(), &key, &value)
438 .await?;
439 self.values.0.insert(key, value);
440 Ok(())
441 }
442
443 pub async fn remove(
445 &mut self,
446 key: impl AsRef<str>,
447 ) -> Result<Option<Preference>, E> {
448 let pref = self.values.0.remove(key.as_ref());
449 self.provider
450 .remove_preference(self.account_id.as_ref(), key.as_ref())
451 .await?;
452 Ok(pref)
453 }
454
455 pub async fn clear(&mut self) -> Result<(), E> {
457 self.values = Default::default();
458 self.provider
459 .clear_preferences(self.account_id.as_ref())
460 .await?;
461 Ok(())
462 }
463}