Implement the http variant of the bank server.
During that process, many shortcomings with the socket server and the bank lib were fixed. I am aware a massive commit like this is not ideal.
This commit is contained in:
parent
c69654a924
commit
dac95b7dae
34 changed files with 1797 additions and 140 deletions
|
@ -1,19 +1,20 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::account::AccountError::{Inactive, InvalidAmount, Overdraw};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AccountError {
|
||||
#[error("can not overdraw account")]
|
||||
Overdraw(),
|
||||
Overdraw,
|
||||
#[error("account is inactive")]
|
||||
Inactive(),
|
||||
Inactive,
|
||||
#[error("amount must be > 0")]
|
||||
InvalidAmount(),
|
||||
InvalidAmount,
|
||||
#[error("account does not exist")]
|
||||
NotFound,
|
||||
#[error("account still has a balance")]
|
||||
AccountNotZero,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -52,33 +53,35 @@ impl Hash for Account {
|
|||
impl Account {
|
||||
#[cfg(test)]
|
||||
pub fn new() -> Self {
|
||||
Self { ..Default::default() }
|
||||
Self {
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deposit(&mut self, amount: f64) -> Result<()> {
|
||||
pub fn deposit(&mut self, amount: f64) -> Result<f64, AccountError> {
|
||||
self.check_account(amount)?;
|
||||
self.balance += amount;
|
||||
Ok(())
|
||||
Ok(self.balance)
|
||||
}
|
||||
|
||||
pub fn withdraw(&mut self, amount: f64) -> Result<()> {
|
||||
pub fn withdraw(&mut self, amount: f64) -> Result<f64, AccountError> {
|
||||
self.check_account(amount)?;
|
||||
|
||||
if self.balance - amount < 0 as f64 {
|
||||
bail!(Overdraw());
|
||||
return Err(AccountError::Overdraw);
|
||||
}
|
||||
self.balance -= amount;
|
||||
|
||||
Ok(())
|
||||
Ok(self.balance)
|
||||
}
|
||||
|
||||
fn check_account(&self, amount: f64) -> Result<()> {
|
||||
fn check_account(&self, amount: f64) -> Result<(), AccountError> {
|
||||
if !self.is_active {
|
||||
bail!(Inactive());
|
||||
return Err(AccountError::Inactive);
|
||||
}
|
||||
|
||||
if amount < 0 as f64 {
|
||||
bail!(InvalidAmount());
|
||||
return Err(AccountError::InvalidAmount);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,38 +1,61 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::RwLock;
|
||||
use std::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
#[cfg(test)]
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::account::Account;
|
||||
use crate::account::{Account, AccountError};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Bank {
|
||||
pub accounts: HashMap<String, RwLock<Account>>,
|
||||
}
|
||||
|
||||
impl Bank {
|
||||
pub fn new() -> Self {
|
||||
Self { accounts: HashMap::new() }
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn account_action<F: Fn(&mut Account) -> Result<f64, AccountError>>(
|
||||
bank: RwLockReadGuard<'_, Bank>,
|
||||
nr: &str,
|
||||
action: F,
|
||||
) -> Result<f64, AccountError> {
|
||||
match bank.accounts.get(nr) {
|
||||
None => Err(AccountError::NotFound),
|
||||
Some(account) => {
|
||||
let mut account = account.write().unwrap();
|
||||
action(&mut account)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn account_numbers(&self) -> HashSet<String> {
|
||||
self.accounts.iter()
|
||||
self.accounts
|
||||
.iter()
|
||||
.filter(|(_, acc)| acc.read().unwrap().is_active)
|
||||
.map(|(_, acc)| acc.read().unwrap().number.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn create_account(&mut self, owner: String) -> String {
|
||||
let acc = Account { owner, ..Default::default() };
|
||||
let number = acc.number.clone();
|
||||
let acc = Account {
|
||||
owner,
|
||||
..Default::default()
|
||||
};
|
||||
let nr = acc.number.clone();
|
||||
|
||||
self.accounts.insert(acc.number.clone(), RwLock::new(acc));
|
||||
|
||||
number
|
||||
nr
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn transfer(&self, from: &mut Account, to: &mut Account, amount: f64) -> Result<()> {
|
||||
pub fn transfer(
|
||||
&self,
|
||||
from: &mut Account,
|
||||
to: &mut Account,
|
||||
amount: f64,
|
||||
) -> Result<(), AccountError> {
|
||||
from.withdraw(amount)?;
|
||||
to.deposit(amount)?;
|
||||
|
||||
|
@ -83,4 +106,4 @@ mod tests {
|
|||
|
||||
assert_eq!(1, bank.account_numbers().len());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
pub mod account;
|
||||
pub mod bank;
|
||||
pub mod bank;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue