notedeck

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

user_account.rs (4423B)


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