split bank ad socket server up

This commit is contained in:
Sebastian Hugentobler 2022-03-16 09:51:29 +01:00
parent 3d9c98eeca
commit c69654a924
22 changed files with 342 additions and 43 deletions

252
bank/Cargo.lock generated Normal file
View file

@ -0,0 +1,252 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bank-server"
version = "0.1.0"
dependencies = [
"anyhow",
"log",
"pretty_env_logger",
"thiserror",
"uuid",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "env_logger"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "getrandom"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
dependencies = [
"quick-error",
]
[[package]]
name = "libc"
version = "0.2.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "pretty_env_logger"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
dependencies = [
"env_logger",
"log",
]
[[package]]
name = "proc-macro2"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "syn"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-xid"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
]
[[package]]
name = "wasi"
version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]]
name = "winapi"
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",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

9
bank/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "bank"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow = "1.0.55"
thiserror = "1.0.30"
uuid = { version = "0.8.2", features = ["v4"] }

143
bank/src/account.rs Normal file
View file

@ -0,0 +1,143 @@
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(),
#[error("account is inactive")]
Inactive(),
#[error("amount must be > 0")]
InvalidAmount(),
}
#[derive(Debug, Clone)]
pub struct Account {
pub number: String,
pub owner: String,
pub balance: f64,
pub is_active: bool,
}
impl Default for Account {
fn default() -> Self {
Account {
number: Uuid::new_v4().to_string(),
owner: "".into(),
balance: 0_f64,
is_active: true,
}
}
}
impl PartialEq for Account {
fn eq(&self, other: &Self) -> bool {
self.number == other.number
}
}
impl Eq for Account {}
impl Hash for Account {
fn hash<H: Hasher>(&self, state: &mut H) {
self.number.hash(state);
}
}
impl Account {
#[cfg(test)]
pub fn new() -> Self {
Self { ..Default::default() }
}
pub fn deposit(&mut self, amount: f64) -> Result<()> {
self.check_account(amount)?;
self.balance += amount;
Ok(())
}
pub fn withdraw(&mut self, amount: f64) -> Result<()> {
self.check_account(amount)?;
if self.balance - amount < 0 as f64 {
bail!(Overdraw());
}
self.balance -= amount;
Ok(())
}
fn check_account(&self, amount: f64) -> Result<()> {
if !self.is_active {
bail!(Inactive());
}
if amount < 0 as f64 {
bail!(InvalidAmount());
}
Ok(())
}
pub fn passivate(&mut self) -> bool {
let is_passivated = self.balance <= 0 as f64 && self.is_active;
if is_passivated {
self.is_active = false;
}
is_passivated
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn deposits() {
let mut acc = Account::new();
let ok_result = acc.deposit(10.56);
assert!(ok_result.is_ok());
let err_result = acc.deposit(-5.89);
assert!(err_result.is_err());
}
#[test]
fn withdrawals() {
let mut acc = Account::new();
let ok_result1 = acc.deposit(10_f64);
assert!(ok_result1.is_ok());
let ok_result2 = acc.withdraw(5_f64);
assert!(ok_result2.is_ok());
let err_result1 = acc.withdraw(10_f64);
assert!(err_result1.is_err());
let err_result2 = acc.withdraw(-10_f64);
assert!(err_result2.is_err());
}
#[test]
fn passivation() {
let mut acc = Account::new();
let deposit_amount = 100_f64;
acc.deposit(deposit_amount).unwrap();
assert!(!acc.passivate());
acc.withdraw(deposit_amount).unwrap();
assert!(acc.passivate());
assert!(!acc.passivate());
}
}

86
bank/src/bank.rs Normal file
View file

@ -0,0 +1,86 @@
use std::collections::{HashMap, HashSet};
use std::sync::RwLock;
#[cfg(test)]
use anyhow::Result;
use crate::account::Account;
pub struct Bank {
pub accounts: HashMap<String, RwLock<Account>>,
}
impl Bank {
pub fn new() -> Self {
Self { accounts: HashMap::new() }
}
pub fn account_numbers(&self) -> HashSet<String> {
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();
self.accounts.insert(acc.number.clone(), RwLock::new(acc));
number
}
#[cfg(test)]
pub fn transfer(&self, from: &mut Account, to: &mut Account, amount: f64) -> Result<()> {
from.withdraw(amount)?;
to.deposit(amount)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn creation() {
let mut bank = Bank::new();
let nr = bank.create_account("Rohaja".into());
assert!(bank.accounts.get(&nr).is_some());
assert!(bank.accounts.get("thisisnotauuid").is_none());
}
#[test]
fn transfer() {
let mut bank = Bank::new();
let nr1 = bank.create_account("Rohaja".into());
let nr2 = bank.create_account("Hal".into());
{
let mut acc1 = bank.accounts.get(&nr1).unwrap().write().unwrap();
let mut acc2 = bank.accounts.get(&nr2).unwrap().write().unwrap();
let result = bank.transfer(&mut acc1, &mut acc2, 100_f64);
assert!(result.is_err());
acc1.deposit(100_f64).unwrap();
let result = bank.transfer(&mut acc1, &mut acc2, 50_f64);
assert!(result.is_ok());
assert_eq!(acc2.balance, 50_f64);
let result = bank.transfer(&mut acc1, &mut acc2, -50_f64);
assert!(result.is_err());
acc2.withdraw(50_f64).unwrap();
assert!(acc2.passivate());
let result = bank.transfer(&mut acc1, &mut acc2, 50_f64);
assert!(result.is_err());
}
assert_eq!(1, bank.account_numbers().len());
}
}

2
bank/src/lib.rs Normal file
View file

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