From ed517b6dab37e1171d0155667286f9a356b11c20 Mon Sep 17 00:00:00 2001 From: Edward Shen Date: Mon, 8 Feb 2021 18:58:46 -0500 Subject: [PATCH] more preliminary work --- Cargo.lock | 54 ++++++++++++++++++++++++------- Cargo.toml | 2 +- vtse-common/Cargo.toml | 2 ++ vtse-common/src/net.rs | 2 ++ vtse-common/src/stock.rs | 69 ++++++++++++++++++++++++++++++++++++++-- vtse-server/Cargo.toml | 4 +-- vtse-server/src/main.rs | 6 ++-- vtse-server/src/state.rs | 34 +++++++++++++++++--- vtse-web/Cargo.toml | 9 ++++++ vtse-web/src/main.rs | 3 ++ 10 files changed, 159 insertions(+), 26 deletions(-) create mode 100644 vtse-web/Cargo.toml create mode 100644 vtse-web/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 37aca1b..b107deb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -437,9 +437,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" dependencies = [ "matches", "unicode-bidi", @@ -491,9 +491,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.85" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "libsodium-sys" @@ -597,6 +597,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e9a41747ae4633fce5adffb4d2e81ffc5e89593cb19917f8fb2cc5ff76507bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-integer" version = "0.1.44" @@ -849,6 +860,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "rust_decimal" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e5a94e2006dd60c603d8481c65b665b4b6694f78d23e15869ad10eb883e36e" +dependencies = [ + "arrayvec", + "num-traits", + "serde", +] + [[package]] name = "rustls" version = "0.19.0" @@ -906,9 +928,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" +checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" dependencies = [ "itoa", "ryu", @@ -1054,10 +1076,12 @@ dependencies = [ "log", "md-5", "memchr", + "num-bigint", "once_cell", "parking_lot", "percent-encoding", "rand 0.7.3", + "rust_decimal", "rustls", "serde", "serde_json", @@ -1201,9 +1225,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6714d663090b6b0acb0fa85841c6d66233d150cdb2602c8f9b8abb03370beb3f" +checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a" dependencies = [ "autocfg", "bytes", @@ -1221,9 +1245,9 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" dependencies = [ "proc-macro2", "quote", @@ -1243,9 +1267,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd" +checksum = "1981ad97df782ab506a1f43bf82c967326960d278acf3bf8279809648c3ff3ea" dependencies = [ "futures-core", "pin-project-lite", @@ -1336,7 +1360,9 @@ version = "0.1.0" name = "vtse-common" version = "0.1.0" dependencies = [ + "rust_decimal", "serde", + "sqlx", "thiserror", "uuid", ] @@ -1362,6 +1388,10 @@ dependencies = [ "vtse-common", ] +[[package]] +name = "vtse-web" +version = "0.1.0" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 033c869..9c569f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["vtse-client", "vtse-common", "vtse-server"] \ No newline at end of file +members = ["vtse-client", "vtse-common", "vtse-server", "vtse-web"] \ No newline at end of file diff --git a/vtse-common/Cargo.toml b/vtse-common/Cargo.toml index 80990c8..30bb573 100644 --- a/vtse-common/Cargo.toml +++ b/vtse-common/Cargo.toml @@ -5,6 +5,8 @@ authors = ["Edward Shen "] edition = "2018" [dependencies] +rust_decimal = "1.10.2" +sqlx = { version = "0.5", features = ["postgres", "decimal"] } serde = { version = "1", features = ["derive"] } thiserror = "1" uuid = { version = "0.8", features = ["serde", "v4"] } \ No newline at end of file diff --git a/vtse-common/src/net.rs b/vtse-common/src/net.rs index 17a9a95..59495ef 100644 --- a/vtse-common/src/net.rs +++ b/vtse-common/src/net.rs @@ -1,3 +1,4 @@ +use crate::stock::Stock; use serde::Serialize; use uuid::Uuid; @@ -8,6 +9,7 @@ pub enum ServerResponse { Success, NewApiKey(Uuid), UserError(UserError), + StockInfo(Stock), } #[derive(Serialize)] diff --git a/vtse-common/src/stock.rs b/vtse-common/src/stock.rs index e18ed94..dbb1af8 100644 --- a/vtse-common/src/stock.rs +++ b/vtse-common/src/stock.rs @@ -1,10 +1,21 @@ -use serde::Deserialize; +use rust_decimal::Decimal; +use serde::{Deserialize, Serialize}; use std::str::FromStr; use thiserror::Error; -#[derive(Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] +#[derive( + Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default, sqlx::Type, +)] +#[serde(transparent)] +#[sqlx(transparent)] pub struct StockName(String); +impl From for StockName { + fn from(s: String) -> Self { + Self(s) + } +} + #[derive(Error, Debug)] pub enum StockNameParseError {} @@ -16,4 +27,56 @@ impl FromStr for StockName { } } -pub(crate) struct Stock {} +#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] +#[serde(transparent)] +pub struct StockSymbol(String); + +impl From for StockSymbol { + fn from(s: String) -> Self { + Self(s) + } +} + +#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Default)] +#[serde(transparent)] +pub struct StockDescription(String); + +impl From for StockDescription { + fn from(s: String) -> Self { + Self(s) + } +} + +#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, PartialOrd, Debug, Default)] +#[serde(transparent)] +pub struct StockPrice(Decimal); + +impl From for StockPrice { + fn from(p: Decimal) -> Self { + Self(p) + } +} + +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct Stock { + name: StockName, + symbol: StockSymbol, + description: StockDescription, + price: StockPrice, +} + +impl Stock { + pub fn new( + name: impl Into, + symbol: impl Into, + description: impl Into, + price: impl Into, + ) -> Self { + Self { + name: name.into(), + symbol: symbol.into(), + description: description.into(), + price: price.into(), + } + } +} diff --git a/vtse-server/Cargo.toml b/vtse-server/Cargo.toml index 584fb2d..1897d00 100644 --- a/vtse-server/Cargo.toml +++ b/vtse-server/Cargo.toml @@ -14,9 +14,9 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" simple_logger = "1.11" sodiumoxide = "0.2" -sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "macros", "uuid", "postgres" ] } +sqlx = { version = "0.5", features = [ "runtime-tokio-rustls", "macros", "uuid", "postgres", "decimal" ] } thiserror = "1" tokio = { version = "1", features = ["full"] } tokio-stream = { version = "0.1", features = ["net"] } uuid = { version = "0.8", features = ["v4"] } -vtse-common = { path = "../vtse-common" } \ No newline at end of file +vtse-common = { path = "../vtse-common" } diff --git a/vtse-server/src/main.rs b/vtse-server/src/main.rs index f28e911..fc65c46 100644 --- a/vtse-server/src/main.rs +++ b/vtse-server/src/main.rs @@ -67,7 +67,7 @@ async fn handle_stream(mut socket: TcpStream, pool: PgPool) -> Result<()> { debug!("Parsed operation: {:?}", parsed); let response = match parsed { ServerOperation::Query(op) => match op { - QueryOperation::StockInfo { stock } => todo!(), + QueryOperation::StockInfo { stock } => state.stock_info(stock, &pool).await?, QueryOperation::User(_) => todo!(), }, ServerOperation::User(op) => match op { @@ -80,8 +80,8 @@ async fn handle_stream(mut socket: TcpStream, pool: PgPool) -> Result<()> { } }, ServerOperation::Market(op) => match op { - MarketOperation::Buy(stock_name) => state.buy(stock_name)?, - MarketOperation::Sell(stock_name) => state.sell(stock_name)?, + MarketOperation::Buy(stock_name) => state.buy(stock_name, &pool)?, + MarketOperation::Sell(stock_name) => state.sell(stock_name, &pool)?, }, }; diff --git a/vtse-server/src/state.rs b/vtse-server/src/state.rs index 092ff8a..f363178 100644 --- a/vtse-server/src/state.rs +++ b/vtse-server/src/state.rs @@ -4,7 +4,7 @@ use sqlx::{query, PgPool}; use thiserror::Error; use vtse_common::{ net::{ServerResponse, UserError}, - stock::StockName, + stock::{Stock, StockName}, }; #[derive(Error, Debug)] @@ -25,6 +25,7 @@ pub(crate) enum AppState { Authorized { user_id: i32 }, } +/// Helper functions impl AppState { pub(crate) fn new() -> Self { Self::Unauthorized @@ -39,6 +40,25 @@ impl AppState { } } +/// Query operations impl +impl AppState { + pub(crate) async fn stock_info(&self, stock_name: StockName, pool: &PgPool) -> OperationResult { + let stock = query!( + "SELECT name, symbol, description, price FROM stocks WHERE name = $1::text", + stock_name as StockName + ) + .fetch_one(pool) + .await?; + + Ok(ServerResponse::StockInfo(Stock::new( + stock.name, + stock.symbol, + stock.description, + stock.price, + ))) + } +} + /// User operation implementation impl AppState { pub(crate) async fn login(&mut self, api_key: ApiKey, pool: &PgPool) -> OperationResult { @@ -149,13 +169,17 @@ impl AppState { /// Market operation implementation impl AppState { - pub(crate) fn buy(&self, stock_name: StockName) -> OperationResult { - // self.assert_state(AppState::Authorized)?; + pub(crate) fn buy(&self, stock_name: StockName, pool: &PgPool) -> OperationResult { + if !matches!(self, Self::Authorized{..}) { + return Err(StateError::WrongState); + } todo!() } - pub(crate) fn sell(&self, stock_name: StockName) -> OperationResult { - // self.assert_state(AppState::Authorized)?; + pub(crate) fn sell(&self, stock_name: StockName, pool: &PgPool) -> OperationResult { + if !matches!(self, Self::Authorized{..}) { + return Err(StateError::WrongState); + } todo!() } } diff --git a/vtse-web/Cargo.toml b/vtse-web/Cargo.toml new file mode 100644 index 0000000..2d064d9 --- /dev/null +++ b/vtse-web/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "vtse-web" +version = "0.1.0" +authors = ["Edward Shen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/vtse-web/src/main.rs b/vtse-web/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/vtse-web/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +}