use crate::client_transfers::SpendRequest;
use super::{
error::{Error, Result},
KeyLessWallet,
};
use sn_dbc::{Dbc, DbcId};
use sn_protocol::storage::DbcAddress;
use std::{
collections::BTreeSet,
fs,
path::{Path, PathBuf},
};
const WALLET_FILE_NAME: &str = "wallet";
const CREATED_DBCS_DIR_NAME: &str = "created_dbcs";
const RECEIVED_DBCS_DIR_NAME: &str = "received_dbcs";
const UNCONFRIMED_TX_NAME: &str = "unconfirmed_txs";
pub(super) fn create_received_dbcs_dir(wallet_dir: &Path) -> Result<()> {
let received_dbcs_dir = wallet_dir.join(RECEIVED_DBCS_DIR_NAME);
fs::create_dir_all(received_dbcs_dir)?;
Ok(())
}
pub(super) fn store_wallet(wallet_dir: &Path, wallet: &KeyLessWallet) -> Result<()> {
let wallet_path = wallet_dir.join(WALLET_FILE_NAME);
let bytes = bincode::serialize(&wallet)?;
fs::write(wallet_path, bytes)?;
Ok(())
}
pub(super) fn get_wallet(wallet_dir: &Path) -> Result<Option<KeyLessWallet>> {
let path = wallet_dir.join(WALLET_FILE_NAME);
if !path.is_file() {
return Ok(None);
}
let bytes = fs::read(&path)?;
let wallet = bincode::deserialize(&bytes)?;
Ok(Some(wallet))
}
pub(super) fn store_unconfirmed_txs(
wallet_dir: &Path,
unconfirmed_txs: &BTreeSet<SpendRequest>,
) -> Result<()> {
let unconfirmed_txs_path = wallet_dir.join(UNCONFRIMED_TX_NAME);
let bytes = bincode::serialize(&unconfirmed_txs)?;
fs::write(unconfirmed_txs_path, bytes)?;
Ok(())
}
pub(super) fn get_unconfirmed_txs(wallet_dir: &Path) -> Result<Option<BTreeSet<SpendRequest>>> {
let path = wallet_dir.join(UNCONFRIMED_TX_NAME);
if !path.is_file() {
return Ok(None);
}
let bytes = fs::read(&path)?;
let unconfirmed_txs = bincode::deserialize(&bytes)?;
Ok(Some(unconfirmed_txs))
}
pub(super) fn store_created_dbcs(created_dbcs: Vec<&Dbc>, wallet_dir: &Path) -> Result<()> {
let created_dbcs_path = wallet_dir.join(CREATED_DBCS_DIR_NAME);
for dbc in created_dbcs.iter() {
let dbc_id_name = *DbcAddress::from_dbc_id(&dbc.id()).xorname();
let dbc_id_file_name = format!("{}.dbc", hex::encode(dbc_id_name));
fs::create_dir_all(&created_dbcs_path)?;
let dbc_file_path = created_dbcs_path.join(dbc_id_file_name);
let hex = dbc.to_hex().map_err(Error::Dbc)?;
fs::write(dbc_file_path, &hex)?;
}
Ok(())
}
pub(super) fn load_received_dbcs(wallet_dir: &Path) -> Result<Vec<Dbc>> {
let received_dbcs_path = match std::env::var("RECEIVED_DBCS_PATH") {
Ok(path) => PathBuf::from(path),
Err(_) => wallet_dir.join(RECEIVED_DBCS_DIR_NAME),
};
let mut deposits = vec![];
for entry in walkdir::WalkDir::new(&received_dbcs_path)
.into_iter()
.flatten()
{
if entry.file_type().is_file() {
let file_name = entry.file_name();
println!("Reading deposited tokens from {file_name:?}.");
let dbc_data = fs::read_to_string(entry.path())?;
let dbc = match Dbc::from_hex(dbc_data.trim()) {
Ok(dbc) => dbc,
Err(_) => {
println!(
"This file does not appear to have valid hex-encoded DBC data. \
Skipping it."
);
continue;
}
};
deposits.push(dbc);
}
}
if deposits.is_empty() {
println!("No deposits found at {}.", received_dbcs_path.display());
}
Ok(deposits)
}
pub fn load_dbc(dbc_id: &DbcId, wallet_dir: &Path) -> Option<Dbc> {
let created_dbcs_path = wallet_dir.join(CREATED_DBCS_DIR_NAME);
let dbc_id_name = *DbcAddress::from_dbc_id(dbc_id).xorname();
let dbc_id_file_name = format!("{}.dbc", hex::encode(dbc_id_name));
let dbc_file_path = created_dbcs_path.join(dbc_id_file_name);
match fs::read_to_string(dbc_file_path) {
Ok(dbc_data) => {
match Dbc::from_hex(dbc_data.trim()) {
Ok(dbc) => Some(dbc),
Err(error) => {
warn!("Failed to convert dbc data from hex: {}", error);
None
}
}
}
Err(error) => {
warn!("Failed to read dbc file: {}", error);
None
}
}
}