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 }