//! Provides some CRUD functions for wallets on the filesystem. use eth2_wallet::Error as WalletError; use eth2_wallet::{Uuid, Wallet}; use std::fs::{copy as copy_file, remove_file, File}; use std::io; use std::path::{Path, PathBuf}; #[derive(Debug)] pub enum Error { WalletAlreadyExists(PathBuf), WalletDoesNotExist(PathBuf), WalletBackupAlreadyExists(PathBuf), UnableToCreateBackup(io::Error), UnableToRemoveBackup(io::Error), UnableToRemoveWallet(io::Error), UnableToCreateWallet(io::Error), UnableToReadWallet(io::Error), JsonWrite(WalletError), JsonRead(WalletError), } /// Read a wallet with the given `uuid` from the `wallet_dir`. pub fn read>(wallet_dir: P, uuid: &Uuid) -> Result { let json_path = wallet_json_path(wallet_dir, uuid); if !json_path.exists() { Err(Error::WalletDoesNotExist(json_path)) } else { File::options() .read(true) .create(false) .open(json_path) .map_err(Error::UnableToReadWallet) .and_then(|f| Wallet::from_json_reader(f).map_err(Error::JsonRead)) } } /// Update the JSON file in the `wallet_dir` with the given `wallet`. /// /// Performs a three-step copy: /// /// 1. Copy the current JSON file to a backup file. /// 2. Over-write the existing JSON file. /// 3. Delete the backup file. pub fn update>(wallet_dir: P, wallet: &Wallet) -> Result<(), Error> { let wallet_dir = wallet_dir.as_ref(); let json_path = wallet_json_path(wallet_dir, wallet.uuid()); let json_backup_path = wallet_json_backup_path(wallet_dir, wallet.uuid()); // Require that a wallet already exists. if !json_path.exists() { return Err(Error::WalletDoesNotExist(json_path)); // Require that there is no existing backup. } else if json_backup_path.exists() { return Err(Error::WalletBackupAlreadyExists(json_backup_path)); } // Copy the existing wallet to the backup location. copy_file(&json_path, &json_backup_path).map_err(Error::UnableToCreateBackup)?; // Remove the existing wallet remove_file(json_path).map_err(Error::UnableToRemoveWallet)?; // Create the new wallet. create(wallet_dir, wallet)?; // Remove the backup file. remove_file(json_backup_path).map_err(Error::UnableToRemoveBackup)?; Ok(()) } /// Writes the `wallet` into the `wallet_dir`, returning an error if it already exists. pub fn create>(wallet_dir: P, wallet: &Wallet) -> Result<(), Error> { let json_path = wallet_json_path(wallet_dir, wallet.uuid()); if json_path.exists() { Err(Error::WalletAlreadyExists(json_path)) } else { File::options() .write(true) .create_new(true) .open(json_path) .map_err(Error::UnableToCreateWallet) .and_then(|f| wallet.to_json_writer(f).map_err(Error::JsonWrite)) } } fn wallet_json_backup_path>(wallet_dir: P, uuid: &Uuid) -> PathBuf { wallet_dir.as_ref().join(format!("{}.backup", uuid)) } fn wallet_json_path>(wallet_dir: P, uuid: &Uuid) -> PathBuf { wallet_dir.as_ref().join(format!("{}", uuid)) }