diff --git a/server/src/game_handler.rs b/server/src/game_handler.rs index 2d3501a..48204f5 100644 --- a/server/src/game_handler.rs +++ b/server/src/game_handler.rs @@ -29,6 +29,7 @@ pub enum GameHandlerMessage { /// Handles game stuff pub struct GameHandler { + /// Global state pointer state: Arc, } diff --git a/server/src/lib.rs b/server/src/lib.rs index 3589631..e230e65 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -3,7 +3,7 @@ use crate::game_handler::*; use anyhow::{Context, Result}; use axum::extract::ws::Message; -use game_handler::GameHandlerMessage; +use game_handler::*; use lib::*; use std::{ collections::{HashMap, HashSet}, @@ -14,7 +14,7 @@ use std::{ }; use tokio::sync::mpsc::Sender; use tokio::sync::{broadcast, mpsc}; -use user_handler::UserHandlerMessage; +use user_handler::*; use uuid::Uuid; pub mod game_handler; pub mod message_handler; diff --git a/server/src/message_handler.rs b/server/src/message_handler.rs index 9784132..b4de9cb 100644 --- a/server/src/message_handler.rs +++ b/server/src/message_handler.rs @@ -7,15 +7,19 @@ use serde_json::{from_str, to_string}; use std::net::SocketAddr; use std::sync::Arc; +/// Handles incoming messages pub struct MessageHandler { + /// Global state pointer state: Arc, } impl MessageHandler { + /// Returns new MessageHandler object pub fn new(state: Arc) -> Self { MessageHandler { state } } + /// Handles incoming messages pub async fn handle(&self, addr: SocketAddr, message: Message) { match message { Message::Text(text) => match text { @@ -28,7 +32,9 @@ impl MessageHandler { .send(to_string::(&ChatMessage { text: msg }).unwrap()) .unwrap(); } - _user_log_in if let Ok(user_log_in) = from_str::(&text) => { + _user_log_in_request + if let Ok(user_log_in) = from_str::(&text) => + { self.state .users_tx .send(UserHandlerMessage::UserLogIn { @@ -39,7 +45,7 @@ impl MessageHandler { .unwrap(); tracing::debug!("passed login to user handler"); } - _new_game if let Ok(new_game) = from_str::(&text) => { + _new_game_request if let Ok(new_game) = from_str::(&text) => { self.state .games_tx .send(GameHandlerMessage::NewGame { addr, new_game }) @@ -50,21 +56,28 @@ impl MessageHandler { _join_game_request if let Ok(join_request) = from_str::(&text) => { self.state .games_tx - .send(GameHandlerMessage::JoinGame { addr, id: join_request.id }) + .send(GameHandlerMessage::JoinGame { + addr, + id: join_request.id, + }) .await .unwrap(); } _ => tracing::debug!("Unhandled text from {}", addr), }, + Message::Binary(data) => tracing::debug!("{} sent binary: {:?}", addr, data), + Message::Close(close_frame) => { self.handle_close(close_frame, addr); } - Message::Pong(ping) => { + + Message::Ping(ping) => { tracing::debug!("Pong received with: {:?}", ping); } - Message::Ping(pong) => { + + Message::Pong(pong) => { tracing::debug!("Pong received with: {:?}", pong); } } @@ -72,48 +85,7 @@ impl MessageHandler { /// This runs when a connection closes fn handle_close(&self, close_frame: Option, addr: SocketAddr) { - if let Some(cf) = close_frame { - tracing::debug!( - "Close received from {0} with code: {1} and reason: {2}", - self.state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .name, - cf.code, - cf.reason - ) - } else { - tracing::debug!("close received without close frame") - } - - let msg = ChatMessage { - text: format!( - "{0} left.", - self.state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .name - ), - }; - - tracing::debug!("{}", msg.text); - self.state - .broadcast_tx - .send(to_string::(&msg).unwrap()) - .unwrap(); - - // Move user to offline - let name = self + let user_name = self .state .online_users .read() @@ -125,16 +97,7 @@ impl MessageHandler { .name .clone(); - self.state.offline_users.write().unwrap().insert( - name.clone(), - self.state - .online_users - .write() - .unwrap() - .remove(&addr) - .unwrap(), - ); - + // Send client updates self.state .broadcast_tx .send(meta_server_summary_update(&self.state)) @@ -143,5 +106,39 @@ impl MessageHandler { .broadcast_tx .send(meta_chat_update(&self.state)) .unwrap(); + + // Announce User left in chat + let msg = ChatMessage { + text: format!("{0} left.", &user_name), + }; + tracing::debug!("{}", msg.text); + self.state + .broadcast_tx + .send(to_string::(&msg).unwrap()) + .unwrap(); + + // Process close frame + if let Some(cf) = close_frame { + tracing::debug!( + "Close received from {0} with code: {1} and reason: {2}", + &user_name, + cf.code, + cf.reason + ) + } else { + tracing::debug!("close received without close frame") + } + + // Move user to offline + // This should probably happen first/immediately but moving down here avoids a clone + self.state.offline_users.write().unwrap().insert( + user_name, + self.state + .online_users + .write() + .unwrap() + .remove(&addr) + .unwrap(), + ); } } diff --git a/server/src/user_handler.rs b/server/src/user_handler.rs index bf8491a..df5d5f3 100644 --- a/server/src/user_handler.rs +++ b/server/src/user_handler.rs @@ -1,4 +1,5 @@ use crate::AppState; +use crate::SendUserMessage::*; use crate::User; use crate::UserHandlerMessage::*; use lib::*; @@ -6,21 +7,41 @@ use serde_json::to_string; use std::net::SocketAddr; use std::sync::{Arc, RwLock}; -pub enum UserHandlerMessage { - NewUser { user: User, addr: SocketAddr }, - UserLogIn { username: String, addr: SocketAddr }, - DmUserAddr { addr: SocketAddr, message: String }, -} - +/// Handles users pub struct UserHandler { + /// Pointer to global state state: Arc, } +/// For interacting with the user handler +pub enum UserHandlerMessage { + NewUser { + user: User, + addr: SocketAddr, + }, + UserLogIn { + username: String, + addr: SocketAddr, + }, + DmUserAddr { + addr: SocketAddr, + message: SendUserMessage, + }, +} + +/// Types of messages that can be sent to a user as a DM +pub enum SendUserMessage { + SendUserUpdate(UserUpdate), + SendChatMessage(ChatMessage), +} + impl UserHandler { + /// Returns new UserHandler pub fn new(state: Arc) -> Self { UserHandler { state } } + /// Handles incoming messages pub async fn handle(&self, message: UserHandlerMessage) { match message { NewUser { user, addr } => { @@ -32,8 +53,8 @@ impl UserHandler { } } - async fn send_message_addr(&self, addr: SocketAddr, message: String) { - let msg = to_string::(&ChatMessage { text: message }).unwrap(); + /// Send message direct to a single user via addr + async fn send_message_addr(&self, addr: SocketAddr, message: SendUserMessage) { let tx = self .state .online_users @@ -45,14 +66,20 @@ impl UserHandler { .unwrap() .tx .clone(); - - tx.send(msg).await.unwrap() + match message { + SendUserUpdate(message) => { + let msg = to_string::(&message).unwrap(); + tx.send(msg).await.unwrap() + } + SendChatMessage(message) => { + let msg = to_string::(&message).unwrap(); + tx.send(msg).await.unwrap() + } + } } + /// Create, register, and hydrate new user async fn set_up_new_user(&self, user: User, addr: SocketAddr) { - // - // Create, Register, and Hydrate new user - // let tx = user.tx.clone(); let new_user = Arc::new(RwLock::new(user)); @@ -77,7 +104,6 @@ impl UserHandler { tx.send(meta_games_browser_update(&self.state)) .await .unwrap(); - tx.send(meta_new_game_card_packs(&self.state)) .await .unwrap(); @@ -87,39 +113,21 @@ impl UserHandler { let _ = &self .state .broadcast_tx - .send(meta_announce_user_join(&self.state, &addr)) - .unwrap(); + .send(meta_announce_user_join(&self.state, &addr)); let _ = &self .state .broadcast_tx - .send(meta_server_summary_update(&self.state)) - .unwrap(); - let _ = &self - .state - .broadcast_tx - .send(meta_chat_update(&self.state)) - .unwrap(); + .send(meta_server_summary_update(&self.state)); + let _ = &self.state.broadcast_tx.send(meta_chat_update(&self.state)); - // TODO: this races the broadcasts but if it's done last it'll probably show up last + // TODO: this races the broadcasts but if it's done last it'll probably show up last... tx.send(meta_motd()).await.unwrap(); } + /// Handle user login async fn login(&self, username: String, addr: SocketAddr) { - // User's DM channel - let dm = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .tx - .clone(); - - let broadcast = self.state.broadcast_tx.clone(); - + let broadcast_tx = self.state.broadcast_tx.clone(); + let new_name = username.clone(); let old_name = self .state .online_users @@ -132,8 +140,7 @@ impl UserHandler { .name .clone(); - let new_name = username.clone(); - + // Resume user's old session if they exist as offline if self .state .offline_users @@ -156,47 +163,47 @@ impl UserHandler { ) .unwrap(); + // Send welcome back messages let msg = format! { "{0} changed name to {1}. Welcome back!", old_name, new_name }; - dm.send( - serde_json::to_string(&ChatMessage { - text: "Welcome back!".to_string(), - }) - .unwrap(), - ) - .await - .unwrap(); - - tracing::debug!("{msg}"); - } else if self + tracing::debug!("{}", &msg); + let _ = broadcast_tx.send(to_string(&ChatMessage { text: msg }).unwrap()); + } + // Check if name is taken by an online user + else if self .state .reserved_names .read() .unwrap() .contains(&new_name) { - tracing::debug!("name is taken"); - dm.send( - serde_json::to_string(&ChatMessage { + self.send_message_addr( + addr, + SendChatMessage(ChatMessage { text: "Name is taken".to_string(), - }) - .unwrap(), + }), ) - .await - .unwrap(); + .await; tracing::debug!("{}", old_name.clone()); - dm.send( - to_string::(&UserUpdate { + self.send_message_addr( + addr, + SendUserUpdate(UserUpdate { username: old_name.clone(), - }) - .unwrap(), + }), ) - .await - .unwrap(); + .await; } else { + // Reserve name + self.state + .reserved_names + .write() + .unwrap() + .insert(new_name.clone()); + + // Change user's name self.state .online_users .write() @@ -207,48 +214,31 @@ impl UserHandler { .unwrap() .change_name(username); + // send the user their new name + self.send_message_addr( + addr, + SendUserUpdate(UserUpdate { + username: new_name.clone(), + }), + ) + .await; + + // Send chat updates let msg = format! { "{0} changed name to {1}.", old_name, new_name }; - - // Reserve name - self.state - .reserved_names - .write() - .unwrap() - .insert(new_name.clone()); - - tracing::debug!("{msg}"); - broadcast + broadcast_tx .send(to_string::(&ChatMessage { text: msg }).unwrap()) .unwrap(); - tracing::debug!("Name {} reserved.", &new_name); - - // send the user their new name - dm.send( - to_string::(&UserUpdate { - username: new_name.clone(), - }) - .unwrap(), - ) - .await - .unwrap(); } - tracing::debug!( - "Online Users: {} Offline Users: {}", - self.state.online_users.read().unwrap().len(), - self.state.offline_users.read().unwrap().len() - ); - - broadcast + // Send client updates + broadcast_tx .send(meta_games_browser_update(&self.state)) .unwrap(); - broadcast.send(meta_chat_update(&self.state)).unwrap(); - - tracing::debug!(" HI! login received {} {} {}", addr, new_name, old_name) + broadcast_tx.send(meta_chat_update(&self.state)).unwrap(); } }