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 }