use crate::api::*; use crate::AppState; use crate::Arc; use anyhow::Result; use axum::extract::ws::CloseFrame; use serde_json::{from_str, to_string}; use tokio::sync::broadcast::Sender; /// Handle incoming messages over the WebSocket pub async fn message_handler( state: Arc, addr: SocketAddr, message: Message, ) -> Result<()> { let tx = &state.tx; match message { Message::Text(text) => match text { _new_game if let Ok(_new_game) = from_str::(&text) => { tracing::debug!("New game request received."); handle_new_game(_new_game, &state, tx, addr)?; } _chat_message if let Ok(_chat_message) = from_str::(&text) => { handle_chat_message(_chat_message, &state, tx, addr)?; } _user_log_in if let Ok(_user_log_in) = from_str::(&text) => { handle_user_log_in(_user_log_in, &state, tx, addr)?; } _ => { tracing::debug!("Unhandled text message: {}", &text); } }, Message::Binary(data) => { tracing::debug!("Binary: {:?}", data) } Message::Close(close_frame) => { handle_close(close_frame, &state, tx, addr)?; } Message::Pong(ping) => { tracing::debug!("Pong received with: {:?}", ping); } Message::Ping(pong) => { tracing::debug!("Pong received with: {:?}", pong); } } Ok(()) } /// This runs when a NewGameRequest is received fn handle_new_game( new_game: NewGameRequest, state: &Arc, tx: &Sender, addr: SocketAddr, ) -> Result<()> { let binding = state.online_users.lock().unwrap(); let user = binding.get(&addr).unwrap(); tracing::debug!("{:#?} from {}", new_game, user.name); let manifest = NewGameManifest { name: new_game.name, host: user, }; // create game // if let Ok(new_game_object) = Game::new(new_game) { // if let Ok(game_json) = to_string(&new_game_object) { // tracing::debug!("Sent new game JSON."); // // this is a broadcast // // change this // tx.send(game_json)?; // } else { // // change this // tracing::error!("Failed to convert Game object to JSON.") // } // // state.games.lock().unwrap().push(new_game_object); // tx.send(games_update(state))?; // tx.send(server_summary_update(state))?; // } Ok(()) } /// This runs when a ChatMessage is received fn handle_chat_message( chat_message: ChatMessage, state: &Arc, tx: &Sender, addr: SocketAddr, ) -> Result<()> { let msg = format! {"{0}: {1}", state.online_users.lock().unwrap().get(&addr).unwrap().name, chat_message.text}; tracing::debug!("{msg}"); tx.send(to_string::(&ChatMessage { text: msg })?)?; Ok(()) } /// This runs when a UserLogIn is received fn handle_user_log_in( user_log_in: UserLogIn, state: &Arc, tx: &Sender, addr: SocketAddr, ) -> Result<()> { let old_name = state .online_users .lock() .unwrap() .get(&addr) .unwrap() .name .clone(); let new_name = user_log_in.username.clone(); if state.offline_users.lock().unwrap().contains_key(&new_name) { state .online_users .lock() .unwrap() .insert( addr, state .offline_users .lock() .unwrap() .remove(&new_name) .unwrap(), ) .unwrap(); let msg = format! { "{0} changed name to {1}. Welcome back!", old_name, new_name }; tracing::debug!("{msg}"); } else { state .online_users .lock() .unwrap() .get_mut(&addr) .unwrap() .change_name(user_log_in.username); let msg = format! { "{0} changed name to {1}.", old_name, new_name }; tracing::debug!("{msg}"); tx.send(to_string::(&ChatMessage { text: msg })?)?; } tracing::debug!( "User updated at ptr: {:p}", state.online_users.lock().unwrap().get(&addr).unwrap() ); tracing::debug!( "User updated deref ptr: {:p}", *state.online_users.lock().unwrap().get(&addr).unwrap() ); tracing::debug!( "Online Users: {} Offline Users: {}", state.online_users.lock().unwrap().len(), state.offline_users.lock().unwrap().len() ); Ok(()) } /// This runs when a connection closes fn handle_close( close_frame: Option, state: &Arc, tx: &Sender, addr: SocketAddr, ) -> Result<()> { if let Some(cf) = close_frame { tracing::debug!( "Close received from {0} with code: {1} and reason: {2}", state.online_users.lock().unwrap().get(&addr).unwrap().name, cf.code, cf.reason ) } else { tracing::debug!("close received without close frame") } let msg = ChatMessage { text: format!( "{0} left.", state.online_users.lock().unwrap().get(&addr).unwrap().name ), }; tracing::debug!("{}", msg.text); tx.send(to_string::(&msg)?)?; let name = state .online_users .lock() .unwrap() .get(&addr) .unwrap() .name .clone(); state.offline_users.lock().unwrap().insert( name.clone(), state.online_users.lock().unwrap().remove(&addr).unwrap(), ); tracing::debug!( "User moved to offline ptr: {:p}", state.offline_users.lock().unwrap().get(&name).unwrap() ); tracing::debug!( "User offline deref ptr: {:p}", *state.offline_users.lock().unwrap().get(&name).unwrap() ); tx.send(server_summary_update(&state))?; tx.send(chat_meta_update(&state))?; Ok(()) }