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:
Sebastian Hugentobler 2022-03-18 19:35:34 +01:00
parent c69654a924
commit dac95b7dae
Signed by: shu
GPG key ID: BB32CF3CA052C2F0
34 changed files with 1797 additions and 140 deletions

78
bank/Cargo.lock generated
View file

@ -8,7 +8,7 @@ version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
"memchr",
]
[[package]]
@ -23,20 +23,20 @@ version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bank-server"
version = "0.1.0"
dependencies = [
"anyhow",
"log",
"pretty_env_logger",
"thiserror",
"uuid",
"anyhow",
"log",
"pretty_env_logger",
"thiserror",
"uuid",
]
[[package]]
@ -51,11 +51,11 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
@ -64,9 +64,9 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
"wasi",
"cfg-if",
"libc",
"wasi",
]
[[package]]
@ -75,7 +75,7 @@ version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
"libc",
]
[[package]]
@ -84,7 +84,7 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
"quick-error",
]
[[package]]
@ -99,7 +99,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
"cfg-if",
]
[[package]]
@ -114,8 +114,8 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
dependencies = [
"env_logger",
"log",
"env_logger",
"log",
]
[[package]]
@ -124,7 +124,7 @@ version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
"unicode-xid",
]
[[package]]
@ -139,7 +139,7 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
"proc-macro2",
]
[[package]]
@ -148,9 +148,9 @@ version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
@ -165,9 +165,9 @@ version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
@ -176,7 +176,7 @@ version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
"winapi-util",
]
[[package]]
@ -185,7 +185,7 @@ version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
"thiserror-impl",
]
[[package]]
@ -194,9 +194,9 @@ version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"proc-macro2",
"quote",
"syn",
]
[[package]]
@ -211,7 +211,7 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
"getrandom",
]
[[package]]
@ -226,8 +226,8 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
@ -242,7 +242,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
"winapi",
]
[[package]]

View file

@ -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(())

View file

@ -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());
}
}
}

View file

@ -1,2 +1,2 @@
pub mod account;
pub mod bank;
pub mod bank;