diff --git a/src/api.rs b/src/api.rs index a8ce87a..82ae3e2 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,16 +1,17 @@ use crate::gamemaster::*; use crate::AppState; -use axum::extract::ConnectInfo; use axum::{ extract::{ ws::{Message, WebSocket, WebSocketUpgrade}, - State, + ConnectInfo, State, }, response::IntoResponse, }; use futures::{sink::SinkExt, stream::StreamExt}; use serde::Deserialize; use std::{net::SocketAddr, sync::Arc}; +pub mod message_handler; +use crate::message_handler::*; /// New game request structure #[derive(Debug, Deserialize)] @@ -51,6 +52,7 @@ fn greeting(state: &Arc) -> String { state.games.lock().unwrap().len(), ) } + pub async fn websocket(stream: WebSocket, state: Arc, who: SocketAddr) { // By splitting, we can send and receive at the same time. let (mut sender, mut receiver) = stream.split(); @@ -74,57 +76,10 @@ pub async fn websocket(stream: WebSocket, state: Arc, who: SocketAddr) } }); - // clone things for receiving task - let tx = state.tx.clone(); - let name = who.clone(); - // handle new incoming messages let mut recv_task = tokio::spawn(async move { while let Some(Ok(message)) = receiver.next().await { - match message { - Message::Text(text) => { - tracing::debug!("{who}: {}", text); - - if let Ok(new_game) = serde_json::from_str::(&text) { - tracing::debug!("{:#?}", &new_game); - // create game - if let Ok(new_game_object) = CAHGame::new(new_game) { - state.games.lock().unwrap().push(new_game_object); - let _update = tx.send(greeting(&state)); - } else { - let _res = tx.send(format!("error creating game")); - } - } else { - // just echo - let msg = format!{"{who}: {text}"}; - tracing::debug!("{msg}"); - let _res = tx.send(msg); - } - } - Message::Binary(data) => { - tracing::debug!("Binary: {:?}", data) - } - Message::Close(c) => { - if let Some(cf) = c { - tracing::debug!( - "Close received from {who} with code: {} and reason: {}", - cf.code, - cf.reason - ) - } else { - tracing::debug!("close received without close frame") - } - let msg = format!("{name} left."); - tracing::debug!("{msg}"); - let _ = tx.send(msg); - } - Message::Pong(ping) => { - tracing::debug!("Pong received with: {:?}", ping); - } - Message::Ping(pong) => { - tracing::debug!("Pong received with: {:?}", pong); - } - } + message_handler(message, &state, who).await } }); diff --git a/src/api/message_handler.rs b/src/api/message_handler.rs new file mode 100644 index 0000000..162bf1f --- /dev/null +++ b/src/api/message_handler.rs @@ -0,0 +1,58 @@ +use crate::api::{greeting, Message, SocketAddr}; +use crate::AppState; +use crate::Arc; +use crate::CAHGame; +use crate::NewGameRequest; + +pub async fn message_handler(message: Message, state: &Arc, who: SocketAddr) { + let tx = &state.tx; + + match message { + Message::Text(text) => { + tracing::debug!("{who}: {}", text); + + if let Ok(new_game) = serde_json::from_str::(&text) { + tracing::debug!("{:#?}", &new_game); + // create game + if let Ok(new_game_object) = CAHGame::new(new_game) { + state.games.lock().unwrap().push(new_game_object); + let _update = tx.send(greeting(&state)); + } else { + let _res = tx.send(format!("error creating game")); + } + } else { + // just echo + let msg = format! {"{who}: {text}"}; + tracing::debug!("{msg}"); + let _res = tx.send(msg); + } + } + + Message::Binary(data) => { + tracing::debug!("Binary: {:?}", data) + } + + Message::Close(c) => { + if let Some(cf) = c { + tracing::debug!( + "Close received from {who} with code: {} and reason: {}", + cf.code, + cf.reason + ) + } else { + tracing::debug!("close received without close frame") + } + let msg = format!("{who} left."); + tracing::debug!("{msg}"); + let _ = tx.send(msg); + } + + Message::Pong(ping) => { + tracing::debug!("Pong received with: {:?}", ping); + } + + Message::Ping(pong) => { + tracing::debug!("Pong received with: {:?}", pong); + } + } +} diff --git a/src/main.rs b/src/main.rs index e104e61..d256ff1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,16 @@ -use axum::{response::Html, routing::get, Router, ServiceExt}; +use axum::{response::Html, routing::get, Router}; use std::{ - collections::HashSet, + // collections::HashSet, + error::Error, + fs, net::SocketAddr, + result::Result, sync::{Arc, Mutex}, }; -use std::{error::Error, fs, result::Result}; use tokio::sync::broadcast; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - pub mod gamemaster; use crate::gamemaster::*; - pub mod api; use crate::api::*; @@ -76,7 +76,7 @@ fn test() -> Result<(), Box> { // Our shared state pub struct AppState { // We require unique usernames. This tracks which usernames have been taken. - user_set: Mutex>, + // user_set: Mutex>, // Channel used to send messages to all connected clients. tx: broadcast::Sender, // Master card decks @@ -96,18 +96,13 @@ async fn main() -> Result<(), Box> { .init(); // Set up application state for use with with_state(). - let user_set = Mutex::new(HashSet::new()); + // let user_set = Mutex::new(HashSet::new()); let (tx, _rx) = broadcast::channel(100); - - // choose decks let cards_input_path: &str = "data/cah-cards-full.json"; - - // TODO: this should be a master card database and pointers - // to the cards should be passed to the game instead of actual cards let all_cards = Mutex::new(load_json(cards_input_path)?); let games = Mutex::new(vec![]); let app_state = Arc::new(AppState { - user_set, + // user_set, tx, all_cards, games,