move (de)serialization of wallets & accounts to own structs
for easy cloning Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
@@ -3,6 +3,7 @@ use tracing::{debug, error, info};
|
||||
use crate::account::cache::AccountCache;
|
||||
use crate::account::mute::AccountMutedData;
|
||||
use crate::account::relay::{AccountRelayData, RelayDefaults};
|
||||
use crate::user_account::UserAccountSerializable;
|
||||
use crate::{AccountStorage, MuteFun, RelaySpec, SingleUnkIdAction, UserAccount};
|
||||
use enostr::{ClientMessage, FilledKeypair, Keypair, Pubkey, RelayPool};
|
||||
use nostrdb::{Ndb, Note, Transaction};
|
||||
@@ -32,7 +33,8 @@ impl Accounts {
|
||||
match keystore.get_accounts() {
|
||||
Ok(accounts) => {
|
||||
for account in accounts {
|
||||
cache.add(account);
|
||||
// TODO(kernelkind): this will get processed in a later commit
|
||||
let _ = add_account_from_storage(&mut cache, account);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -94,7 +96,7 @@ impl Accounts {
|
||||
};
|
||||
|
||||
if let Some(key_store) = &self.key_store {
|
||||
if let Err(e) = key_store.write_account(acc.get_acc()) {
|
||||
if let Err(e) = key_store.write_account(&acc.get_acc().into()) {
|
||||
tracing::error!("Could not add key for {:?}: {e}", kp.pubkey);
|
||||
}
|
||||
}
|
||||
@@ -118,7 +120,7 @@ impl Accounts {
|
||||
return false;
|
||||
};
|
||||
|
||||
if let Err(err) = key_store.write_account(cur_acc) {
|
||||
if let Err(err) = key_store.write_account(&cur_acc.into()) {
|
||||
tracing::error!("Could not add account {:?} to storage: {err}", cur_acc.key);
|
||||
return false;
|
||||
}
|
||||
@@ -450,6 +452,40 @@ impl<'a> AccType<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_account_from_storage(
|
||||
cache: &mut AccountCache,
|
||||
user_account_serializable: UserAccountSerializable,
|
||||
) -> SingleUnkIdAction {
|
||||
let Some(acc) = get_acc_from_storage(user_account_serializable) else {
|
||||
return SingleUnkIdAction::NoAction;
|
||||
};
|
||||
|
||||
let pk = acc.key.pubkey;
|
||||
cache.add(acc);
|
||||
|
||||
SingleUnkIdAction::pubkey(pk)
|
||||
}
|
||||
|
||||
fn get_acc_from_storage(user_account_serializable: UserAccountSerializable) -> Option<UserAccount> {
|
||||
let keypair = user_account_serializable.key;
|
||||
|
||||
let mut wallet = None;
|
||||
if let Some(wallet_s) = user_account_serializable.wallet {
|
||||
let m_wallet: Result<crate::ZapWallet, crate::Error> = wallet_s.into();
|
||||
match m_wallet {
|
||||
Ok(w) => wallet = Some(w),
|
||||
Err(e) => {
|
||||
tracing::error!("Problem creating wallet from disk: {e}");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Some(UserAccount {
|
||||
key: keypair,
|
||||
wallet,
|
||||
})
|
||||
}
|
||||
|
||||
enum RelayAction {
|
||||
Add,
|
||||
Remove,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{Result, UserAccount};
|
||||
use crate::{user_account::UserAccountSerializable, Result};
|
||||
use enostr::{Keypair, Pubkey, SerializableKeypair};
|
||||
use tokenator::{TokenParser, TokenSerializable, TokenWriter};
|
||||
|
||||
@@ -21,7 +21,7 @@ impl AccountStorage {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_account(&self, account: &UserAccount) -> Result<()> {
|
||||
pub fn write_account(&self, account: &UserAccountSerializable) -> Result<()> {
|
||||
let mut writer = TokenWriter::new("\t");
|
||||
account.serialize_tokens(&mut writer);
|
||||
write_file(
|
||||
@@ -31,7 +31,7 @@ impl AccountStorage {
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_accounts(&self) -> Result<Vec<UserAccount>> {
|
||||
pub fn get_accounts(&self) -> Result<Vec<UserAccountSerializable>> {
|
||||
let keys = self
|
||||
.accounts_directory
|
||||
.get_files()?
|
||||
@@ -79,16 +79,18 @@ impl AccountStorage {
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_storage(serialized: &str) -> Result<UserAccount> {
|
||||
fn deserialize_storage(serialized: &str) -> Result<UserAccountSerializable> {
|
||||
let data = serialized.split("\t").collect::<Vec<&str>>();
|
||||
let mut parser = TokenParser::new(&data);
|
||||
|
||||
if let Ok(acc) = UserAccount::parse_from_tokens(&mut parser) {
|
||||
if let Ok(acc) = UserAccountSerializable::parse_from_tokens(&mut parser) {
|
||||
return Ok(acc);
|
||||
}
|
||||
|
||||
// try old deserialization way
|
||||
Ok(UserAccount::new(old_deserialization(serialized)?))
|
||||
Ok(UserAccountSerializable::new(old_deserialization(
|
||||
serialized,
|
||||
)?))
|
||||
}
|
||||
|
||||
fn old_deserialization(serialized: &str) -> Result<Keypair> {
|
||||
@@ -118,7 +120,7 @@ mod tests {
|
||||
fn test_basic() {
|
||||
let kp = enostr::FullKeypair::generate().to_keypair();
|
||||
let storage = AccountStorage::mock().unwrap();
|
||||
let resp = storage.write_account(&UserAccount::new(kp.clone()));
|
||||
let resp = storage.write_account(&UserAccountSerializable::new(kp.clone()));
|
||||
|
||||
assert!(resp.is_ok());
|
||||
assert_num_storage(&storage.get_accounts(), 1);
|
||||
@@ -127,7 +129,7 @@ mod tests {
|
||||
assert_num_storage(&storage.get_accounts(), 0);
|
||||
}
|
||||
|
||||
fn assert_num_storage(keys_response: &Result<Vec<UserAccount>>, n: usize) {
|
||||
fn assert_num_storage(keys_response: &Result<Vec<UserAccountSerializable>>, n: usize) {
|
||||
match keys_response {
|
||||
Ok(keys) => {
|
||||
assert_eq!(keys.len(), n);
|
||||
@@ -143,7 +145,7 @@ mod tests {
|
||||
let kp = enostr::FullKeypair::generate().to_keypair();
|
||||
|
||||
let storage = AccountStorage::mock().unwrap();
|
||||
let _ = storage.write_account(&UserAccount::new(kp.clone()));
|
||||
let _ = storage.write_account(&UserAccountSerializable::new(kp.clone()));
|
||||
assert_num_storage(&storage.get_accounts(), 1);
|
||||
|
||||
let resp = storage.select_key(Some(kp.pubkey));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use enostr::{Keypair, KeypairUnowned};
|
||||
use tokenator::{ParseError, TokenParser, TokenSerializable};
|
||||
|
||||
use crate::wallet::ZapWallet;
|
||||
use crate::wallet::{WalletSerializable, ZapWallet};
|
||||
|
||||
pub struct UserAccount {
|
||||
pub key: Keypair,
|
||||
@@ -26,12 +26,37 @@ impl UserAccount {
|
||||
}
|
||||
}
|
||||
|
||||
enum UserAccountRoute {
|
||||
Key(Keypair),
|
||||
Wallet(ZapWallet),
|
||||
pub struct UserAccountSerializable {
|
||||
pub key: Keypair,
|
||||
pub wallet: Option<WalletSerializable>,
|
||||
}
|
||||
|
||||
impl TokenSerializable for UserAccount {
|
||||
impl UserAccountSerializable {
|
||||
pub fn new(key: Keypair) -> Self {
|
||||
Self { key, wallet: None }
|
||||
}
|
||||
|
||||
pub fn with_wallet(mut self, wallet: WalletSerializable) -> Self {
|
||||
self.wallet = Some(wallet);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&UserAccount> for UserAccountSerializable {
|
||||
fn from(value: &UserAccount) -> Self {
|
||||
Self {
|
||||
key: value.key.clone(),
|
||||
wallet: value.wallet.as_ref().map(|z| z.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum UserAccountRoute {
|
||||
Key(Keypair),
|
||||
Wallet(WalletSerializable),
|
||||
}
|
||||
|
||||
impl TokenSerializable for UserAccountSerializable {
|
||||
fn parse_from_tokens<'a>(
|
||||
parser: &mut tokenator::TokenParser<'a>,
|
||||
) -> Result<Self, tokenator::ParseError<'a>> {
|
||||
@@ -43,7 +68,11 @@ impl TokenSerializable for UserAccount {
|
||||
parser,
|
||||
&[
|
||||
|p| Ok(UserAccountRoute::Key(Keypair::parse_from_tokens(p)?)),
|
||||
|p| Ok(UserAccountRoute::Wallet(ZapWallet::parse_from_tokens(p)?)),
|
||||
|p| {
|
||||
Ok(UserAccountRoute::Wallet(
|
||||
WalletSerializable::parse_from_tokens(p)?,
|
||||
))
|
||||
},
|
||||
],
|
||||
);
|
||||
|
||||
@@ -63,7 +92,7 @@ impl TokenSerializable for UserAccount {
|
||||
return Err(ParseError::DecodeFailed);
|
||||
};
|
||||
|
||||
let mut user_acc = UserAccount::new(key);
|
||||
let mut user_acc = UserAccountSerializable::new(key);
|
||||
|
||||
if let Some(wallet) = m_wallet {
|
||||
user_acc = user_acc.with_wallet(wallet);
|
||||
@@ -88,17 +117,15 @@ mod tests {
|
||||
use enostr::FullKeypair;
|
||||
use tokenator::{TokenParser, TokenSerializable, TokenWriter};
|
||||
|
||||
use crate::Wallet;
|
||||
|
||||
use super::UserAccount;
|
||||
use crate::{user_account::UserAccountSerializable, wallet::WalletSerializable};
|
||||
|
||||
const URI: &str = "nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?relay=wss%3A%2F%2Frelay.damus.io&secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c&lud16=nostr%40nostr.com";
|
||||
|
||||
#[test]
|
||||
fn test_user_account_serialize_deserialize() {
|
||||
let kp = FullKeypair::generate();
|
||||
let acc = UserAccount::new(kp.to_keypair())
|
||||
.with_wallet(Wallet::new(URI.to_owned()).unwrap().into());
|
||||
let acc = UserAccountSerializable::new(kp.to_keypair())
|
||||
.with_wallet(WalletSerializable::new(URI.to_owned()));
|
||||
|
||||
let mut writer = TokenWriter::new("\t");
|
||||
acc.serialize_tokens(&mut writer);
|
||||
@@ -107,7 +134,7 @@ mod tests {
|
||||
|
||||
let data = &serialized.split("\t").collect::<Vec<&str>>();
|
||||
let mut parser = TokenParser::new(data);
|
||||
let m_new_acc = UserAccount::parse_from_tokens(&mut parser);
|
||||
let m_new_acc = UserAccountSerializable::parse_from_tokens(&mut parser);
|
||||
|
||||
assert!(m_new_acc.is_ok());
|
||||
let new_acc = m_new_acc.unwrap();
|
||||
@@ -118,6 +145,6 @@ mod tests {
|
||||
panic!();
|
||||
};
|
||||
|
||||
assert_eq!(wallet.wallet.uri, URI);
|
||||
assert_eq!(wallet.uri, URI);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,21 @@ pub struct Wallet {
|
||||
balance: Option<Promise<Result<u64, nwc::Error>>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WalletSerializable {
|
||||
pub uri: String,
|
||||
pub default_mzap: Option<UserZapMsats>,
|
||||
}
|
||||
|
||||
impl WalletSerializable {
|
||||
pub fn new(uri: String) -> Self {
|
||||
Self {
|
||||
uri,
|
||||
default_mzap: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Wallet {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "Wallet({})", self.uri)
|
||||
@@ -127,26 +142,6 @@ fn pay_invoice(
|
||||
promise
|
||||
}
|
||||
|
||||
impl TokenSerializable for Wallet {
|
||||
fn parse_from_tokens<'a>(
|
||||
parser: &mut tokenator::TokenParser<'a>,
|
||||
) -> Result<Self, tokenator::ParseError<'a>> {
|
||||
parser.parse_token("nwc_uri")?;
|
||||
|
||||
let raw_uri = parser.pull_token()?;
|
||||
|
||||
let wallet =
|
||||
Wallet::new(raw_uri.to_owned()).map_err(|_| tokenator::ParseError::DecodeFailed)?;
|
||||
|
||||
Ok(wallet)
|
||||
}
|
||||
|
||||
fn serialize_tokens(&self, writer: &mut tokenator::TokenWriter) {
|
||||
writer.write_token("nwc_uri");
|
||||
writer.write_token(&self.uri);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GlobalWallet {
|
||||
pub wallet: Option<ZapWallet>,
|
||||
pub ui_state: WalletUIState,
|
||||
@@ -176,7 +171,8 @@ impl GlobalWallet {
|
||||
return;
|
||||
};
|
||||
|
||||
match self.wallet_handler.save(wallet, "\t") {
|
||||
let serializable: WalletSerializable = wallet.into();
|
||||
match self.wallet_handler.save(&serializable, "\t") {
|
||||
Ok(_) => {}
|
||||
Err(e) => tracing::error!("Could not save global wallet: {e}"),
|
||||
}
|
||||
@@ -184,12 +180,15 @@ impl GlobalWallet {
|
||||
}
|
||||
|
||||
fn construct_global_wallet(wallet_handler: &TokenHandler) -> Option<ZapWallet> {
|
||||
let Ok(res) = wallet_handler.load::<ZapWallet>("\t") else {
|
||||
let Ok(res) = wallet_handler.load::<WalletSerializable>("\t") else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let wallet = match res {
|
||||
Ok(wallet) => wallet,
|
||||
Ok(wallet) => {
|
||||
let m_zap_wallet: Result<ZapWallet, crate::Error> = wallet.into();
|
||||
m_zap_wallet.ok()?
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error parsing wallet: {:?}", e);
|
||||
return None;
|
||||
@@ -206,11 +205,49 @@ pub struct ZapWallet {
|
||||
}
|
||||
|
||||
enum ZapWalletRoute {
|
||||
Wallet(Wallet),
|
||||
Wallet(String),
|
||||
DefaultZapMsats(UserZapMsats),
|
||||
}
|
||||
|
||||
impl TokenSerializable for ZapWallet {
|
||||
impl ZapWallet {
|
||||
pub fn new(wallet: Wallet) -> Self {
|
||||
Self {
|
||||
wallet,
|
||||
default_zap: DefaultZapMsats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_default_zap_msats(mut self, msats: u64) -> Self {
|
||||
self.default_zap.set_user_selection(msats);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Wallet> for ZapWallet {
|
||||
fn from(value: Wallet) -> Self {
|
||||
ZapWallet::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&ZapWallet> for WalletSerializable {
|
||||
fn from(value: &ZapWallet) -> Self {
|
||||
Self {
|
||||
uri: value.wallet.uri.to_string(),
|
||||
default_mzap: value.default_zap.try_into_user(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<WalletSerializable> for Result<ZapWallet, crate::Error> {
|
||||
fn from(value: WalletSerializable) -> Result<ZapWallet, crate::Error> {
|
||||
Ok(ZapWallet {
|
||||
wallet: Wallet::new(value.uri)?,
|
||||
default_zap: DefaultZapMsats::from_user(value.default_mzap),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TokenSerializable for WalletSerializable {
|
||||
fn parse_from_tokens<'a>(
|
||||
parser: &mut tokenator::TokenParser<'a>,
|
||||
) -> Result<Self, tokenator::ParseError<'a>> {
|
||||
@@ -220,7 +257,12 @@ impl TokenSerializable for ZapWallet {
|
||||
let res = TokenParser::alt(
|
||||
parser,
|
||||
&[
|
||||
|p| Ok(ZapWalletRoute::Wallet(Wallet::parse_from_tokens(p)?)),
|
||||
|p| {
|
||||
p.parse_token("nwc_uri")?;
|
||||
let raw_uri = p.pull_token()?;
|
||||
|
||||
Ok(ZapWalletRoute::Wallet(raw_uri.to_string()))
|
||||
},
|
||||
|p| {
|
||||
Ok(ZapWalletRoute::DefaultZapMsats(
|
||||
UserZapMsats::parse_from_tokens(p)?,
|
||||
@@ -245,49 +287,27 @@ impl TokenSerializable for ZapWallet {
|
||||
return Err(ParseError::DecodeFailed);
|
||||
};
|
||||
|
||||
let mut zap_wallet = ZapWallet::new(wallet);
|
||||
|
||||
let default_zap = DefaultZapMsats::from_user(m_default_zap);
|
||||
|
||||
zap_wallet.default_zap = default_zap;
|
||||
|
||||
Ok(zap_wallet)
|
||||
Ok(WalletSerializable {
|
||||
uri: wallet,
|
||||
default_mzap: m_default_zap,
|
||||
})
|
||||
}
|
||||
|
||||
fn serialize_tokens(&self, writer: &mut tokenator::TokenWriter) {
|
||||
self.wallet.serialize_tokens(writer);
|
||||
writer.write_token("nwc_uri");
|
||||
writer.write_token(&self.uri);
|
||||
|
||||
if let Some(user_zap_msats) = self.default_zap.try_into_user() {
|
||||
user_zap_msats.serialize_tokens(writer);
|
||||
if let Some(msats) = &self.default_mzap {
|
||||
msats.serialize_tokens(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ZapWallet {
|
||||
pub fn new(wallet: Wallet) -> Self {
|
||||
Self {
|
||||
wallet,
|
||||
default_zap: DefaultZapMsats::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_default_zap_msats(mut self, msats: u64) -> Self {
|
||||
self.default_zap.set_user_selection(msats);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Wallet> for ZapWallet {
|
||||
fn from(value: Wallet) -> Self {
|
||||
ZapWallet::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tokenator::{TokenParser, TokenSerializable, TokenWriter};
|
||||
|
||||
use crate::Wallet;
|
||||
use crate::{wallet::WalletSerializable, Wallet};
|
||||
|
||||
use super::ZapWallet;
|
||||
|
||||
@@ -301,7 +321,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_wallet_serialize_deserialize() {
|
||||
let wallet = Wallet::new(URI.to_owned()).unwrap();
|
||||
let wallet = WalletSerializable::new(URI.to_owned());
|
||||
|
||||
let mut writer = TokenWriter::new("\t");
|
||||
wallet.serialize_tokens(&mut writer);
|
||||
@@ -309,7 +329,7 @@ mod tests {
|
||||
|
||||
let data = &serialized.split("\t").collect::<Vec<&str>>();
|
||||
let mut parser = TokenParser::new(data);
|
||||
let m_new_wallet = Wallet::parse_from_tokens(&mut parser);
|
||||
let m_new_wallet = WalletSerializable::parse_from_tokens(&mut parser);
|
||||
|
||||
assert!(m_new_wallet.is_ok());
|
||||
|
||||
@@ -325,13 +345,20 @@ mod tests {
|
||||
ZapWallet::new(Wallet::new(URI.to_owned()).unwrap()).with_default_zap_msats(MSATS);
|
||||
|
||||
let mut writer = TokenWriter::new("\t");
|
||||
zap_wallet.serialize_tokens(&mut writer);
|
||||
|
||||
let serializable: WalletSerializable = (&zap_wallet).into();
|
||||
serializable.serialize_tokens(&mut writer);
|
||||
let serialized = writer.str();
|
||||
|
||||
let data = &serialized.split("\t").collect::<Vec<&str>>();
|
||||
let mut parser = TokenParser::new(data);
|
||||
|
||||
let m_new_zap_wallet = ZapWallet::parse_from_tokens(&mut parser);
|
||||
let m_deserialized = WalletSerializable::parse_from_tokens(&mut parser);
|
||||
assert!(m_deserialized.is_ok());
|
||||
|
||||
let deserialized = m_deserialized.unwrap();
|
||||
|
||||
let m_new_zap_wallet: Result<ZapWallet, crate::Error> = deserialized.into();
|
||||
|
||||
assert!(m_new_zap_wallet.is_ok());
|
||||
|
||||
|
||||
@@ -11,6 +11,16 @@ pub struct DefaultZapMsats {
|
||||
}
|
||||
|
||||
impl DefaultZapMsats {
|
||||
pub fn from_msats(msats: Option<u64>) -> Self {
|
||||
let mut default = DefaultZapMsats::default();
|
||||
|
||||
if let Some(msats) = msats {
|
||||
default.set_user_selection(msats);
|
||||
default.pending.write_msats(msats);
|
||||
}
|
||||
|
||||
default
|
||||
}
|
||||
pub fn from_user(value: Option<UserZapMsats>) -> Self {
|
||||
let mut obj = match value {
|
||||
Some(user_msats) => {
|
||||
@@ -50,7 +60,7 @@ impl DefaultZapMsats {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct UserZapMsats {
|
||||
pub msats: u64,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user