vtse/vtse-server/src/main.rs

125 lines
4.4 KiB
Rust
Raw Normal View History

2021-02-04 01:40:06 +00:00
use crate::operations::ServerOperation;
2021-02-08 17:33:24 +00:00
use anyhow::{bail, Result};
2021-02-11 18:55:28 +00:00
use args::Args;
2021-02-04 01:40:06 +00:00
use bytes::BytesMut;
2021-02-11 18:55:28 +00:00
use clap::Clap;
2021-02-08 17:33:24 +00:00
use log::{debug, error, info};
2021-02-11 18:55:28 +00:00
use market::Market;
2021-02-08 17:33:24 +00:00
use operations::{MarketOperation, QueryOperation, UserOperation};
2021-02-11 18:55:28 +00:00
use simple_logger::SimpleLogger;
use sqlx::{postgres::PgConnectOptions, ConnectOptions, PgPool};
2021-02-08 17:33:24 +00:00
use state::AppState;
2021-02-11 18:55:28 +00:00
use std::{str::FromStr, sync::Arc};
2021-02-08 17:33:24 +00:00
use tokio::io::{AsyncReadExt, AsyncWriteExt};
2021-02-04 01:40:06 +00:00
use tokio::net::{TcpListener, TcpStream};
use tokio_stream::{wrappers::TcpListenerStream, StreamExt};
2021-02-11 18:55:28 +00:00
mod args;
2021-02-08 17:33:24 +00:00
mod market;
2021-02-04 01:40:06 +00:00
mod operations;
2021-02-08 17:33:24 +00:00
mod state;
mod user;
2021-02-04 01:40:06 +00:00
#[tokio::main]
async fn main() -> Result<()> {
2021-02-11 18:55:28 +00:00
// Must init dotenv before initializing args, else args won't default from
// env properly
2021-02-08 17:33:24 +00:00
dotenv::dotenv().ok();
2021-02-11 18:55:28 +00:00
let args: Args = Args::parse();
2021-02-08 17:33:24 +00:00
// If we can't successfully initialize our crypto library, fail immediately.
2021-02-11 18:55:28 +00:00
sodiumoxide::init().expect("to initialize crypto library");
SimpleLogger::default().init()?;
2021-02-04 01:40:06 +00:00
2021-02-11 18:55:28 +00:00
let mut listener_stream = TcpListener::bind(&args.bind_address)
2021-02-04 01:40:06 +00:00
.await
.map(TcpListenerStream::new)?;
2021-02-08 17:33:24 +00:00
info!("Successfully bound to port.");
2021-02-11 18:55:28 +00:00
let db_pool = {
let mut connect_options = PgConnectOptions::from_str(&args.database_url)?;
connect_options.log_statements(args.db_log_level);
PgPool::connect_with(connect_options).await?
};
2021-02-08 17:33:24 +00:00
info!("Successfully established connection to database.");
2021-02-04 01:40:06 +00:00
2021-02-11 18:55:28 +00:00
let market = Arc::new(Market::new());
2021-02-04 01:40:06 +00:00
while let Some(Ok(stream)) = listener_stream.next().await {
2021-02-08 17:33:24 +00:00
// clone simply clones the arc reference, so this is cheap.
let db_pool = db_pool.clone();
2021-02-11 18:55:28 +00:00
let market = Arc::clone(&market);
2021-02-04 01:40:06 +00:00
tokio::task::spawn(async {
2021-02-11 18:55:28 +00:00
if let Err(e) = handle_stream(stream, db_pool, market).await {
2021-02-09 01:54:00 +00:00
error!("{}", e);
2021-02-04 01:40:06 +00:00
}
});
}
info!("Cleanly shut down. Goodbye!");
Ok(())
}
2021-02-11 18:55:28 +00:00
async fn handle_stream(mut socket: TcpStream, pool: PgPool, mut market: Arc<Market>) -> Result<()> {
2021-02-04 01:40:06 +00:00
// only accept data that can fit in 256 bytes
2021-02-08 17:33:24 +00:00
// the assumption is that a single request should always be within n bytes,
// otherwise there's a good chance that it's mal{formed,icious}.
2021-02-04 01:40:06 +00:00
let mut buffer = BytesMut::with_capacity(256);
2021-02-08 17:33:24 +00:00
let mut state = AppState::new();
2021-02-04 01:40:06 +00:00
loop {
let bytes_read = socket.read_buf(&mut buffer).await?;
2021-02-08 17:33:24 +00:00
if bytes_read == 0 {
bail!("Failed to read bytes, assuming socket is closed.")
2021-02-04 01:40:06 +00:00
}
2021-02-11 18:55:28 +00:00
2021-02-08 17:33:24 +00:00
let data = buffer.split_to(bytes_read); // O(1)
2021-02-11 18:55:28 +00:00
dbg!(&data);
let iter = serde_json::Deserializer::from_slice(&data).into_iter();
for messages in iter {
let message = match messages {
Ok(p) => p,
Err(e) if e.is_eof() || e.is_io() => return Ok(()),
Err(e) => return Err(e.into()),
};
2021-02-09 01:54:00 +00:00
2021-02-11 18:55:28 +00:00
debug!("Parsed operation: {:?}", message);
let response = match message {
ServerOperation::Query(op) => match op {
QueryOperation::StockInfo { stock } => {
AppState::stock_info(stock, &pool).await?
}
QueryOperation::User { username } => {
AppState::user_info(username, &pool).await?
}
},
ServerOperation::User(op) => match op {
UserOperation::Login { api_key } => state.login(api_key, &pool).await?,
UserOperation::Register { username, password } => {
state.register(username, password, &pool).await?
}
UserOperation::GetKey { username, password } => {
state.generate_api_key(username, password, &pool).await?
}
},
ServerOperation::Market(op) => match op {
MarketOperation::Buy { symbol, amount } => {
state.buy(symbol, amount, &pool, &mut market).await?
}
MarketOperation::Sell { symbol, amount } => {
state.sell(symbol, amount, &pool, &mut market).await?
}
},
};
socket
.write_all(serde_json::to_string(&response).unwrap().as_bytes())
.await?;
}
2021-02-08 17:33:24 +00:00
buffer.unsplit(data); // O(1)
2021-02-04 01:40:06 +00:00
buffer.clear();
}
}