use super::{data_payments::PaymentDetails, Result};
use crate::WalletError;
use serde::Serialize;
use std::{
fs,
path::{Path, PathBuf},
sync::Arc,
};
use xor_name::XorName;
const PAYMENTS_DIR_NAME: &str = "payments";
pub const WALLET_DIR_NAME: &str = "wallet";
#[derive(serde::Serialize, serde::Deserialize, Clone)]
pub struct WalletApi {
wallet_dir: Arc<PathBuf>,
payment_dir: Arc<PathBuf>,
}
impl WalletApi {
pub fn new_from_root_dir(root_dir: &Path) -> Self {
let wallet_dir = root_dir.join(WALLET_DIR_NAME);
Self {
payment_dir: Arc::new(wallet_dir.join(PAYMENTS_DIR_NAME)),
wallet_dir: Arc::new(wallet_dir),
}
}
pub fn new_from_wallet_dir(wallet_dir: &Path) -> Self {
Self {
wallet_dir: Arc::new(wallet_dir.to_path_buf()),
payment_dir: Arc::new(wallet_dir.join(PAYMENTS_DIR_NAME)),
}
}
pub fn get_recent_payment(&self, xorname: &XorName) -> Result<PaymentDetails> {
let mut payments = self.read_payment_transactions(xorname)?;
let payment = payments
.pop()
.ok_or(WalletError::NoPaymentForAddress(*xorname))?;
info!("Payment retrieved for {xorname:?} from wallet");
Ok(payment)
}
pub fn get_all_payments(&self, xorname: &XorName) -> Result<Vec<PaymentDetails>> {
let payments = self.read_payment_transactions(xorname)?;
if payments.is_empty() {
return Err(WalletError::NoPaymentForAddress(*xorname));
}
info!(
"All {} payments retrieved for {xorname:?} from wallet",
payments.len()
);
Ok(payments)
}
pub fn insert_payment_transaction(&self, name: XorName, payment: PaymentDetails) -> Result<()> {
let payments = match self.read_payment_transactions(&name) {
Ok(mut stored_payments) => {
stored_payments.push(payment);
stored_payments
}
Err(_) => vec![payment],
};
let unique_file_name = format!("{}.payment", hex::encode(name));
fs::create_dir_all(self.payment_dir.as_ref())?;
let payment_file_path = self.payment_dir.join(unique_file_name);
debug!("Writing payment to {payment_file_path:?}");
let mut file = fs::File::create(payment_file_path)?;
let mut serialiser = rmp_serde::encode::Serializer::new(&mut file);
payments.serialize(&mut serialiser)?;
Ok(())
}
pub fn remove_payment_transaction(&self, name: &XorName) {
let unique_file_name = format!("{}.payment", hex::encode(*name));
let payment_file_path = self.payment_dir.join(unique_file_name);
debug!("Removing payment from {payment_file_path:?}");
let _ = fs::remove_file(payment_file_path);
}
pub fn wallet_dir(&self) -> &Path {
&self.wallet_dir
}
fn read_payment_transactions(&self, name: &XorName) -> Result<Vec<PaymentDetails>> {
let unique_file_name = format!("{}.payment", hex::encode(*name));
let payment_file_path = self.payment_dir.join(unique_file_name);
debug!("Getting payment from {payment_file_path:?}");
let file = fs::File::open(&payment_file_path)?;
let payments = rmp_serde::from_read(&file)?;
Ok(payments)
}
}