lb_rs/service/
keychain.rs

1use std::collections::HashMap;
2use std::sync::{Arc, RwLock};
3
4use crate::Lb;
5use crate::model::account::Account;
6use crate::model::crypto::AESKey;
7use crate::model::errors::{LbErrKind, LbResult};
8use libsecp256k1::PublicKey;
9use tokio::sync::OnceCell;
10use uuid::Uuid;
11
12pub type KeyCache = Arc<RwLock<HashMap<Uuid, AESKey>>>;
13
14#[derive(Default, Clone)]
15pub struct Keychain {
16    key_cache: KeyCache,
17    account: Arc<OnceCell<Account>>,
18    public_key: Arc<OnceCell<PublicKey>>,
19}
20
21impl From<Option<&Account>> for Keychain {
22    fn from(value: Option<&Account>) -> Self {
23        match value {
24            Some(account) => {
25                let account = account.clone();
26                let pk = account.public_key();
27                let key_cache = Default::default();
28
29                Self {
30                    account: Arc::new(OnceCell::from(account)),
31                    public_key: Arc::new(OnceCell::from(pk)),
32                    key_cache,
33                }
34            }
35            None => Self::default(),
36        }
37    }
38}
39
40impl Lb {
41    pub fn get_account(&self) -> LbResult<&Account> {
42        self.keychain.get_account()
43    }
44}
45
46impl Keychain {
47    pub fn get_account(&self) -> LbResult<&Account> {
48        self.account
49            .get()
50            .ok_or_else(|| LbErrKind::AccountNonexistent.into())
51    }
52
53    pub fn get_pk(&self) -> LbResult<PublicKey> {
54        self.public_key
55            .get()
56            .copied()
57            .ok_or_else(|| LbErrKind::AccountNonexistent.into())
58    }
59
60    #[doc(hidden)]
61    pub async fn cache_account(&self, account: Account) -> LbResult<()> {
62        let pk = account.public_key();
63        self.account
64            .set(account)
65            .map_err(|_| LbErrKind::AccountExists)?;
66        self.public_key
67            .set(pk)
68            .map_err(|_| LbErrKind::AccountExists)?;
69
70        Ok(())
71    }
72
73    pub fn contains_aes_key(&self, id: &Uuid) -> LbResult<bool> {
74        Ok(self.key_cache.read()?.contains_key(id))
75    }
76
77    pub fn insert_aes_key(&self, id: Uuid, key: AESKey) -> LbResult<()> {
78        self.key_cache.write()?.insert(id, key);
79        Ok(())
80    }
81
82    pub fn get_aes_key(&self, id: &Uuid) -> LbResult<Option<AESKey>> {
83        Ok(self.key_cache.read()?.get(id).copied())
84    }
85}