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]]
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"

View File

@ -1,2 +1,2 @@
[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"
[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"] }

View File

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

View File

@ -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<String> 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<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"
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" }
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);
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)?,
},
};

View File

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

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!");
}