more preliminary work

master
Edward Shen 2021-02-08 18:58:46 -05:00
parent 0bb86c79e3
commit ed517b6dab
Signed by: edward
GPG Key ID: 19182661E818369F
10 changed files with 159 additions and 26 deletions

54
Cargo.lock generated
View File

@ -437,9 +437,9 @@ dependencies = [
[[package]] [[package]]
name = "idna" name = "idna"
version = "0.2.0" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094"
dependencies = [ dependencies = [
"matches", "matches",
"unicode-bidi", "unicode-bidi",
@ -491,9 +491,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.85" version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ccac4b00700875e6a07c6cde370d44d32fa01c5a65cdd2fca6858c479d28bb3" checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
[[package]] [[package]]
name = "libsodium-sys" name = "libsodium-sys"
@ -597,6 +597,17 @@ dependencies = [
"winapi", "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]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.44" version = "0.1.44"
@ -849,6 +860,17 @@ dependencies = [
"winapi", "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]] [[package]]
name = "rustls" name = "rustls"
version = "0.19.0" version = "0.19.0"
@ -906,9 +928,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.61" version = "1.0.62"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -1054,10 +1076,12 @@ dependencies = [
"log", "log",
"md-5", "md-5",
"memchr", "memchr",
"num-bigint",
"once_cell", "once_cell",
"parking_lot", "parking_lot",
"percent-encoding", "percent-encoding",
"rand 0.7.3", "rand 0.7.3",
"rust_decimal",
"rustls", "rustls",
"serde", "serde",
"serde_json", "serde_json",
@ -1201,9 +1225,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.1.1" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6714d663090b6b0acb0fa85841c6d66233d150cdb2602c8f9b8abb03370beb3f" checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
@ -1221,9 +1245,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "1.0.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494" checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1243,9 +1267,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-stream" name = "tokio-stream"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76066865172052eb8796c686f0b441a93df8b08d40a950b062ffb9a426f00edd" checksum = "1981ad97df782ab506a1f43bf82c967326960d278acf3bf8279809648c3ff3ea"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"pin-project-lite", "pin-project-lite",
@ -1336,7 +1360,9 @@ version = "0.1.0"
name = "vtse-common" name = "vtse-common"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"rust_decimal",
"serde", "serde",
"sqlx",
"thiserror", "thiserror",
"uuid", "uuid",
] ]
@ -1362,6 +1388,10 @@ dependencies = [
"vtse-common", "vtse-common",
] ]
[[package]]
name = "vtse-web"
version = "0.1.0"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.9.0+wasi-snapshot-preview1" version = "0.9.0+wasi-snapshot-preview1"

View File

@ -1,2 +1,2 @@
[workspace] [workspace]
members = ["vtse-client", "vtse-common", "vtse-server"] members = ["vtse-client", "vtse-common", "vtse-server", "vtse-web"]

View File

@ -5,6 +5,8 @@ authors = ["Edward Shen <code@eddie.sh>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
rust_decimal = "1.10.2"
sqlx = { version = "0.5", features = ["postgres", "decimal"] }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
thiserror = "1" thiserror = "1"
uuid = { version = "0.8", features = ["serde", "v4"] } uuid = { version = "0.8", features = ["serde", "v4"] }

View File

@ -1,3 +1,4 @@
use crate::stock::Stock;
use serde::Serialize; use serde::Serialize;
use uuid::Uuid; use uuid::Uuid;
@ -8,6 +9,7 @@ pub enum ServerResponse {
Success, Success,
NewApiKey(Uuid), NewApiKey(Uuid),
UserError(UserError), UserError(UserError),
StockInfo(Stock),
} }
#[derive(Serialize)] #[derive(Serialize)]

View File

@ -1,10 +1,21 @@
use serde::Deserialize; use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use std::str::FromStr; use std::str::FromStr;
use thiserror::Error; 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); pub struct StockName(String);
impl From<String> for StockName {
fn from(s: String) -> Self {
Self(s)
}
}
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum StockNameParseError {} 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<String> 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<String> 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<Decimal> 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<StockName>,
symbol: impl Into<StockSymbol>,
description: impl Into<StockDescription>,
price: impl Into<StockPrice>,
) -> Self {
Self {
name: name.into(),
symbol: symbol.into(),
description: description.into(),
price: price.into(),
}
}
}

View File

@ -14,9 +14,9 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
simple_logger = "1.11" simple_logger = "1.11"
sodiumoxide = "0.2" 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" thiserror = "1"
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
tokio-stream = { version = "0.1", features = ["net"] } tokio-stream = { version = "0.1", features = ["net"] }
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
vtse-common = { path = "../vtse-common" } vtse-common = { path = "../vtse-common" }

View File

@ -67,7 +67,7 @@ async fn handle_stream(mut socket: TcpStream, pool: PgPool) -> Result<()> {
debug!("Parsed operation: {:?}", parsed); debug!("Parsed operation: {:?}", parsed);
let response = match parsed { let response = match parsed {
ServerOperation::Query(op) => match op { ServerOperation::Query(op) => match op {
QueryOperation::StockInfo { stock } => todo!(), QueryOperation::StockInfo { stock } => state.stock_info(stock, &pool).await?,
QueryOperation::User(_) => todo!(), QueryOperation::User(_) => todo!(),
}, },
ServerOperation::User(op) => match op { ServerOperation::User(op) => match op {
@ -80,8 +80,8 @@ async fn handle_stream(mut socket: TcpStream, pool: PgPool) -> Result<()> {
} }
}, },
ServerOperation::Market(op) => match op { ServerOperation::Market(op) => match op {
MarketOperation::Buy(stock_name) => state.buy(stock_name)?, MarketOperation::Buy(stock_name) => state.buy(stock_name, &pool)?,
MarketOperation::Sell(stock_name) => state.sell(stock_name)?, MarketOperation::Sell(stock_name) => state.sell(stock_name, &pool)?,
}, },
}; };

View File

@ -4,7 +4,7 @@ use sqlx::{query, PgPool};
use thiserror::Error; use thiserror::Error;
use vtse_common::{ use vtse_common::{
net::{ServerResponse, UserError}, net::{ServerResponse, UserError},
stock::StockName, stock::{Stock, StockName},
}; };
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -25,6 +25,7 @@ pub(crate) enum AppState {
Authorized { user_id: i32 }, Authorized { user_id: i32 },
} }
/// Helper functions
impl AppState { impl AppState {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self::Unauthorized 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 /// User operation implementation
impl AppState { impl AppState {
pub(crate) async fn login(&mut self, api_key: ApiKey, pool: &PgPool) -> OperationResult { pub(crate) async fn login(&mut self, api_key: ApiKey, pool: &PgPool) -> OperationResult {
@ -149,13 +169,17 @@ impl AppState {
/// Market operation implementation /// Market operation implementation
impl AppState { impl AppState {
pub(crate) fn buy(&self, stock_name: StockName) -> OperationResult { pub(crate) fn buy(&self, stock_name: StockName, pool: &PgPool) -> OperationResult {
// self.assert_state(AppState::Authorized)?; if !matches!(self, Self::Authorized{..}) {
return Err(StateError::WrongState);
}
todo!() todo!()
} }
pub(crate) fn sell(&self, stock_name: StockName) -> OperationResult { pub(crate) fn sell(&self, stock_name: StockName, pool: &PgPool) -> OperationResult {
// self.assert_state(AppState::Authorized)?; if !matches!(self, Self::Authorized{..}) {
return Err(StateError::WrongState);
}
todo!() todo!()
} }
} }

9
vtse-web/Cargo.toml Normal file
View File

@ -0,0 +1,9 @@
[package]
name = "vtse-web"
version = "0.1.0"
authors = ["Edward Shen <code@eddie.sh>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

3
vtse-web/src/main.rs Normal file
View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}