message handler

This commit is contained in:
Adam 2024-05-04 02:23:40 -04:00
parent 4fa78181c7
commit 33d81fd316
3 changed files with 71 additions and 63 deletions

View file

@ -1,16 +1,17 @@
use crate::gamemaster::*; use crate::gamemaster::*;
use crate::AppState; use crate::AppState;
use axum::extract::ConnectInfo;
use axum::{ use axum::{
extract::{ extract::{
ws::{Message, WebSocket, WebSocketUpgrade}, ws::{Message, WebSocket, WebSocketUpgrade},
State, ConnectInfo, State,
}, },
response::IntoResponse, response::IntoResponse,
}; };
use futures::{sink::SinkExt, stream::StreamExt}; use futures::{sink::SinkExt, stream::StreamExt};
use serde::Deserialize; use serde::Deserialize;
use std::{net::SocketAddr, sync::Arc}; use std::{net::SocketAddr, sync::Arc};
pub mod message_handler;
use crate::message_handler::*;
/// New game request structure /// New game request structure
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -51,6 +52,7 @@ fn greeting(state: &Arc<AppState>) -> String {
state.games.lock().unwrap().len(), state.games.lock().unwrap().len(),
) )
} }
pub async fn websocket(stream: WebSocket, state: Arc<AppState>, who: SocketAddr) { pub async fn websocket(stream: WebSocket, state: Arc<AppState>, who: SocketAddr) {
// By splitting, we can send and receive at the same time. // By splitting, we can send and receive at the same time.
let (mut sender, mut receiver) = stream.split(); let (mut sender, mut receiver) = stream.split();
@ -74,57 +76,10 @@ pub async fn websocket(stream: WebSocket, state: Arc<AppState>, who: SocketAddr)
} }
}); });
// clone things for receiving task
let tx = state.tx.clone();
let name = who.clone();
// handle new incoming messages // handle new incoming messages
let mut recv_task = tokio::spawn(async move { let mut recv_task = tokio::spawn(async move {
while let Some(Ok(message)) = receiver.next().await { while let Some(Ok(message)) = receiver.next().await {
match message { message_handler(message, &state, who).await
Message::Text(text) => {
tracing::debug!("{who}: {}", text);
if let Ok(new_game) = serde_json::from_str::<NewGameRequest>(&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);
}
}
} }
}); });

View file

@ -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<AppState>, who: SocketAddr) {
let tx = &state.tx;
match message {
Message::Text(text) => {
tracing::debug!("{who}: {}", text);
if let Ok(new_game) = serde_json::from_str::<NewGameRequest>(&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);
}
}
}

View file

@ -1,16 +1,16 @@
use axum::{response::Html, routing::get, Router, ServiceExt}; use axum::{response::Html, routing::get, Router};
use std::{ use std::{
collections::HashSet, // collections::HashSet,
error::Error,
fs,
net::SocketAddr, net::SocketAddr,
result::Result,
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use std::{error::Error, fs, result::Result};
use tokio::sync::broadcast; use tokio::sync::broadcast;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
pub mod gamemaster; pub mod gamemaster;
use crate::gamemaster::*; use crate::gamemaster::*;
pub mod api; pub mod api;
use crate::api::*; use crate::api::*;
@ -76,7 +76,7 @@ fn test() -> Result<(), Box<dyn Error>> {
// Our shared state // Our shared state
pub struct AppState { pub struct AppState {
// We require unique usernames. This tracks which usernames have been taken. // We require unique usernames. This tracks which usernames have been taken.
user_set: Mutex<HashSet<String>>, // user_set: Mutex<HashSet<String>>,
// Channel used to send messages to all connected clients. // Channel used to send messages to all connected clients.
tx: broadcast::Sender<String>, tx: broadcast::Sender<String>,
// Master card decks // Master card decks
@ -96,18 +96,13 @@ async fn main() -> Result<(), Box<dyn Error>> {
.init(); .init();
// Set up application state for use with with_state(). // 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); let (tx, _rx) = broadcast::channel(100);
// choose decks
let cards_input_path: &str = "data/cah-cards-full.json"; 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 all_cards = Mutex::new(load_json(cards_input_path)?);
let games = Mutex::new(vec![]); let games = Mutex::new(vec![]);
let app_state = Arc::new(AppState { let app_state = Arc::new(AppState {
user_set, // user_set,
tx, tx,
all_cards, all_cards,
games, games,