notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

user_account.rs (4444B)


      1 use enostr::{Keypair, KeypairUnowned};
      2 use tokenator::{ParseError, TokenParser, TokenSerializable};
      3 
      4 use crate::{
      5     wallet::{WalletSerializable, ZapWallet},
      6     AccountData, IsFollowing,
      7 };
      8 
      9 #[derive(Clone)]
     10 pub struct UserAccount {
     11     pub key: Keypair,
     12     pub wallet: Option<ZapWallet>,
     13     pub data: AccountData,
     14 }
     15 
     16 impl UserAccount {
     17     pub fn new(key: Keypair, data: AccountData) -> Self {
     18         Self {
     19             key,
     20             wallet: None,
     21             data,
     22         }
     23     }
     24 
     25     pub fn keypair(&self) -> KeypairUnowned<'_> {
     26         KeypairUnowned {
     27             pubkey: &self.key.pubkey,
     28             secret_key: self.key.secret_key.as_ref(),
     29         }
     30     }
     31 
     32     pub fn with_wallet(mut self, wallet: ZapWallet) -> Self {
     33         self.wallet = Some(wallet);
     34         self
     35     }
     36 
     37     pub fn is_following(&self, other_pubkey: &[u8; 32]) -> IsFollowing {
     38         self.data.contacts.is_following(other_pubkey)
     39     }
     40 }
     41 
     42 #[derive(Clone)]
     43 pub struct UserAccountSerializable {
     44     pub key: Keypair,
     45     pub wallet: Option<WalletSerializable>,
     46 }
     47 
     48 impl UserAccountSerializable {
     49     pub fn new(key: Keypair) -> Self {
     50         Self { key, wallet: None }
     51     }
     52 
     53     pub fn with_wallet(mut self, wallet: WalletSerializable) -> Self {
     54         self.wallet = Some(wallet);
     55         self
     56     }
     57 }
     58 
     59 impl From<&UserAccount> for UserAccountSerializable {
     60     fn from(value: &UserAccount) -> Self {
     61         Self {
     62             key: value.key.clone(),
     63             wallet: value.wallet.as_ref().map(|z| z.into()),
     64         }
     65     }
     66 }
     67 
     68 enum UserAccountRoute {
     69     Key(Keypair),
     70     Wallet(WalletSerializable),
     71 }
     72 
     73 impl TokenSerializable for UserAccountSerializable {
     74     fn parse_from_tokens<'a>(
     75         parser: &mut tokenator::TokenParser<'a>,
     76     ) -> Result<Self, tokenator::ParseError<'a>> {
     77         let mut m_key = None;
     78         let mut m_wallet = None;
     79 
     80         loop {
     81             let res = TokenParser::alt(
     82                 parser,
     83                 &[
     84                     |p| Ok(UserAccountRoute::Key(Keypair::parse_from_tokens(p)?)),
     85                     |p| {
     86                         Ok(UserAccountRoute::Wallet(
     87                             WalletSerializable::parse_from_tokens(p)?,
     88                         ))
     89                     },
     90                 ],
     91             );
     92 
     93             match res {
     94                 Ok(UserAccountRoute::Key(key)) => m_key = Some(key),
     95                 Ok(UserAccountRoute::Wallet(wallet)) => m_wallet = Some(wallet),
     96                 Err(ParseError::AltAllFailed) => break,
     97                 Err(_) => {}
     98             }
     99 
    100             if m_key.is_some() && m_wallet.is_some() {
    101                 break;
    102             }
    103         }
    104 
    105         let Some(key) = m_key else {
    106             return Err(ParseError::DecodeFailed);
    107         };
    108 
    109         let mut user_acc = UserAccountSerializable::new(key);
    110 
    111         if let Some(wallet) = m_wallet {
    112             user_acc = user_acc.with_wallet(wallet);
    113         };
    114 
    115         Ok(user_acc)
    116     }
    117 
    118     fn serialize_tokens(&self, writer: &mut tokenator::TokenWriter) {
    119         self.key.serialize_tokens(writer);
    120 
    121         let Some(wallet) = &self.wallet else {
    122             return;
    123         };
    124 
    125         wallet.serialize_tokens(writer);
    126     }
    127 }
    128 
    129 #[cfg(test)]
    130 mod tests {
    131     use enostr::FullKeypair;
    132     use tokenator::{TokenParser, TokenSerializable, TokenWriter};
    133 
    134     use crate::{user_account::UserAccountSerializable, wallet::WalletSerializable};
    135 
    136     const URI: &str = "nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c&lud16=nostr%40nostr.com";
    137 
    138     #[test]
    139     fn test_user_account_serialize_deserialize() {
    140         let kp = FullKeypair::generate();
    141         let acc = UserAccountSerializable::new(kp.to_keypair())
    142             .with_wallet(WalletSerializable::new(URI.to_owned()));
    143 
    144         let mut writer = TokenWriter::new("\t");
    145         acc.serialize_tokens(&mut writer);
    146 
    147         let serialized = writer.str();
    148 
    149         let data = &serialized.split("\t").collect::<Vec<&str>>();
    150         let mut parser = TokenParser::new(data);
    151         let m_new_acc = UserAccountSerializable::parse_from_tokens(&mut parser);
    152 
    153         assert!(m_new_acc.is_ok());
    154         let new_acc = m_new_acc.unwrap();
    155 
    156         assert_eq!(acc.key, new_acc.key);
    157 
    158         let Some(wallet) = new_acc.wallet else {
    159             panic!();
    160         };
    161 
    162         assert_eq!(wallet.uri, URI);
    163     }
    164 }