diff --git a/server/src/game_handler.rs b/server/src/game_handler.rs index eb28e0c..f735689 100644 --- a/server/src/game_handler.rs +++ b/server/src/game_handler.rs @@ -46,123 +46,101 @@ impl GameHandler { /// Delete game async fn delete_game(&self, request: GameDeleteRequest) { // TODO: add auth lol - let _ = self + if self .state .games .write() .unwrap() .remove(&request.delete_game_id) - .unwrap(); - - // Broadcast game browser update - self.state - .broadcast_tx - .send(meta_games_browser_update(&self.state)) - .unwrap(); + .is_some() + { + // Broadcast game browser update + self.state + .broadcast_tx + .send(meta_games_browser_update(&self.state)) + .unwrap(); + } else { + tracing::error!("User tried to delete a nonexistent game!"); + } } /// Process judging async fn handle_judging(&self, request: JudgeDecisionRequest, addr: SocketAddr) { - // Get pointers - let player_user_id = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .uuid - .to_string(); + if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) { + if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) { + let player_user_id = player_user.read().unwrap().uuid.to_string(); + let game_id = request.game_id.to_string(); - let this_game = self - .state - .games - .read() - .unwrap() - .get(&request.game_id) - .unwrap() - .clone(); + // Send to game + this_game + .write() + .unwrap() + .judge_round(request, player_user_id); - // Send to game - this_game - .write() - .unwrap() - .judge_round(request.clone(), player_user_id.clone()); - - let this_game_id = this_game.read().unwrap().uuid.to_string(); - self.send_game_state_update(this_game_id).await + self.send_game_state_update(game_id); + } else { + tracing::error!("Received judge request for nonexistent judge player!"); + } + } else { + tracing::error!("Received judge request for nonexistent game!"); + } } /// Process player move request async fn handle_player_move(&self, request: PlayerMoveRequest, addr: SocketAddr) { - // Get pointers - let player_user_id = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .uuid - .to_string(); + if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) { + if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) { + let player_user_id = player_user.read().unwrap().uuid.to_string(); - let this_game = self - .state - .games - .read() - .unwrap() - .get(&request.game_id) - .unwrap() - .clone(); + // Do the stuff + match this_game + .write() + .unwrap() + .player_move(request, player_user_id) + { + Err(err) => { + let message = ChatMessage { text: err }; + let tx = self.state.users_tx.clone(); + tokio::spawn(async move { + let _ = tx.send(DmUser(SendChatMessage(message), Addr(addr))).await; + }) + } + Ok(None) => tokio::spawn(async move { tracing::debug!("None") }), + Ok(Some((judge_round, czar_id))) => { + let tx = self.state.users_tx.clone(); - // Do the stuff - match this_game - .write() - .unwrap() - .player_move(request, player_user_id) - { - Err(err) => { - let message = ChatMessage { text: err }; - let tx = self.state.users_tx.clone(); - tokio::spawn(async move { - let _ = tx.send(DmUser(SendChatMessage(message), Addr(addr))).await; - }) + tokio::spawn(async move { + let _ = tx + .send(DmUser(SendJudgeRound(judge_round), Id(czar_id))) + .await; + }) + } + }; + } else { + tracing::error!("Nonexistent player tried to submit move for game!"); } - Ok(None) => tokio::spawn(async move { tracing::debug!("None") }), - Ok(Some((judge_round, czar_id))) => { - let tx = self.state.users_tx.clone(); - - tokio::spawn(async move { - let _ = tx - .send(DmUser(SendJudgeRound(judge_round), Id(czar_id))) - .await; - }) - } - }; + } else { + tracing::error!("Player tried to submit move for nonexistent game!"); + } } /// Puts a user in a game async fn join_game(&self, id: String, addr: SocketAddr) { - // Get pointers - let this_game = self.state.games.read().unwrap().get(&id).unwrap().clone(); - let this_user = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .clone(); - - // Create player - this_game.write().unwrap().create_player(this_user); + if let Some(this_game) = self.state.games.read().unwrap().get(&id) { + if let Some(this_user) = self.state.online_users.read().unwrap().get(&addr) { + // Create player + this_game.write().unwrap().create_player(this_user.clone()); + } else { + tracing::error!("Tried to add a nonexistent user to game!"); + return; + } + } else { + tracing::error!("User tried to join a nonexistent game!"); + return; + } // Send updates for all players - self.send_game_state_update(id).await; + self.send_game_state_update(id); // Broadcast game browser update self.state @@ -178,57 +156,52 @@ impl GameHandler { } /// Send game state update for all players of a game - async fn send_game_state_update(&self, game_id: String) { - let this_game = self - .state - .games - .read() - .unwrap() - .get(&game_id) - .unwrap() - .clone(); + fn send_game_state_update(&self, game_id: String) { + if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) { + let players = this_game + .read() + .unwrap() + .players + .values() + .map(|player| GamePlayerMeta { + name: player.user.read().unwrap().name.clone(), + score: player.black.len(), + }) + .collect::>(); - let players = this_game - .read() - .unwrap() - .players - .values() - .map(|player| GamePlayerMeta { - name: player.user.read().unwrap().name.clone(), - score: player.black.len(), - }) - .collect::>(); + for player in this_game.read().unwrap().players.values() { + // Create update for user's game view + let meta = GameStateMeta { + uuid: game_id.clone(), + name: this_game.read().unwrap().name.clone(), + host: this_game.read().unwrap().host.read().unwrap().name.clone(), + players: players.clone(), + czar: this_game.read().unwrap().czar.read().unwrap().name.clone(), + black: ( + this_game.read().unwrap().current_black.text.clone(), + this_game.read().unwrap().current_black.pick, + ), + white: player + .white + .iter() + .map(|card| WhiteCardMeta { + uuid: card.uuid.to_string(), + text: card.text.clone(), + }) + .collect(), + packs: this_game.read().unwrap().packs.clone(), + white_count: this_game.read().unwrap().white.len(), + black_count: this_game.read().unwrap().black.len(), + white_discard_count: this_game.read().unwrap().white_discard.len(), + }; - for player in this_game.read().unwrap().players.values() { - // Create update for user's game view - let meta = GameStateMeta { - uuid: game_id.clone(), - name: this_game.read().unwrap().name.clone(), - host: this_game.read().unwrap().host.read().unwrap().name.clone(), - players: players.clone(), - czar: this_game.read().unwrap().czar.read().unwrap().name.clone(), - black: ( - this_game.read().unwrap().current_black.text.clone(), - this_game.read().unwrap().current_black.pick, - ), - white: player - .white - .iter() - .map(|card| WhiteCardMeta { - uuid: card.uuid.to_string(), - text: card.text.clone(), - }) - .collect(), - packs: this_game.read().unwrap().packs.clone(), - white_count: this_game.read().unwrap().white.len(), - black_count: this_game.read().unwrap().black.len(), - white_discard_count: this_game.read().unwrap().white_discard.len(), - }; - - // Send user's update - let msg = serde_json::to_string(&meta).unwrap(); - let user_tx = player.user.read().unwrap().tx.clone(); - tokio::spawn(async move { user_tx.send(msg).await }); + // Send user's update + let msg = serde_json::to_string(&meta).unwrap(); + let user_tx = player.user.read().unwrap().tx.clone(); + tokio::spawn(async move { user_tx.send(msg).await }); + } + } else { + tracing::error!("Attempted to create game state update for nonexistent game!"); } } @@ -242,49 +215,43 @@ impl GameHandler { return; } - // Get host pointer - let host = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .clone(); + if let Some(host) = self.state.online_users.read().unwrap().get(&addr) { + // Create manifest + let manifest = NewGameManifest { + name: new_game.name, + host: host.clone(), + packs: new_game.packs, + }; - // Create manifest - let manifest = NewGameManifest { - name: new_game.name, - host: host.clone(), - packs: new_game.packs, - }; + // Create game using manifest + let mut new_game_object = Game::new(self.state.clone(), manifest); - // Create game using manifest - let mut new_game_object = Game::new(self.state.clone(), manifest); + // Don't forget to create the host player!!! + new_game_object.create_player(host.clone()); - // Don't forget to create the host player!!! - new_game_object.create_player(host.clone()); + let game_id = new_game_object.uuid.to_string(); - let game_id = new_game_object.uuid.to_string(); + // Add game to active list + self.state.games.write().unwrap().insert( + new_game_object.uuid.to_string(), + Arc::new(RwLock::new(new_game_object)), + ); - // Add game to active list - self.state.games.write().unwrap().insert( - new_game_object.uuid.to_string(), - Arc::new(RwLock::new(new_game_object)), - ); + self.send_game_state_update(game_id); - self.send_game_state_update(game_id).await; + // Broadcast game browser update + self.state + .broadcast_tx + .send(meta_games_browser_update(&self.state)) + .unwrap(); - // Broadcast game browser update - self.state - .broadcast_tx - .send(meta_games_browser_update(&self.state)) - .unwrap(); - - // Broadcast server meta update - self.state - .broadcast_tx - .send(meta_server_summary_update(&self.state)) - .unwrap(); + // Broadcast server meta update + self.state + .broadcast_tx + .send(meta_server_summary_update(&self.state)) + .unwrap(); + } else { + tracing::error!("Attempted to create game for nonexistent player!"); + } } } diff --git a/server/src/user_handler.rs b/server/src/user_handler.rs index 36672fc..7b6668b 100644 --- a/server/src/user_handler.rs +++ b/server/src/user_handler.rs @@ -63,6 +63,8 @@ impl UserHandler { tx = user.read().unwrap().tx.clone(); } else { tracing::error!("Attempted to send message to invalid user id!"); + // TODO: User can still be offline causing send to fail. This is suppressed + // below return; } } @@ -77,6 +79,7 @@ impl UserHandler { } // Serialize and send message + // TODO: Send failures are suppressed match message { SendUserUpdate(message) => { let msg = to_string::(&message).unwrap(); @@ -99,7 +102,7 @@ impl UserHandler { let new_user = Arc::new(RwLock::new(user)); // Notify client of new username - tx.send(user_client_self_update(&new_user)).await.unwrap(); + let _ = tx.send(user_client_self_update(&new_user)).await; // Register uuid self.state @@ -116,12 +119,8 @@ impl UserHandler { .insert(addr, new_user.clone()); // Hydrate client - tx.send(meta_games_browser_update(&self.state)) - .await - .unwrap(); - tx.send(meta_new_game_card_packs(&self.state)) - .await - .unwrap(); + let _ = tx.send(meta_games_browser_update(&self.state)).await; + let _ = tx.send(meta_new_game_card_packs(&self.state)).await; // Broadcast new user's existence // TODO: this should probably be combined and sent as one @@ -136,24 +135,21 @@ impl UserHandler { 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... - tx.send(meta_motd()).await.unwrap(); + let _ = tx.send(meta_motd()).await; } /// Handle user login async fn login(&self, request: UserLogInRequest, addr: SocketAddr) { let broadcast_tx = self.state.broadcast_tx.clone(); let new_name = request.username.clone(); - let old_name = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .name - .clone(); + let old_name; + + if let Some(user) = self.state.online_users.read().unwrap().get(&addr) { + old_name = user.read().unwrap().name.clone(); + } else { + tracing::error!("Nonexistent user attempting login"); + return; + } // Resume user's old session if they exist as offline if self @@ -163,42 +159,25 @@ impl UserHandler { .unwrap() .contains_key(&new_name) { + let buf; // Copy over new tx - self.state - .offline_users - .read() - .unwrap() - .get(&new_name) - .unwrap() - .write() - .unwrap() - .tx = self - .state - .online_users - .read() - .unwrap() - .get(&addr) - .unwrap() - .read() - .unwrap() - .tx - .clone(); + if let Some(online_user) = self.state.online_users.write().unwrap().remove(&addr) { + if let Some(offline_user) = + self.state.offline_users.write().unwrap().remove(&new_name) + { + offline_user.write().unwrap().tx = online_user.write().unwrap().tx.clone(); + buf = offline_user; + } else { + tracing::error!("Error copying tx to new user: Can't find offline user!"); + return; + } + } else { + tracing::error!("Error copying tx to new user: Can't find online user!"); + return; + } // Move offline user object to online - self.state - .online_users - .write() - .unwrap() - .insert( - addr, - self.state - .offline_users - .write() - .unwrap() - .remove(&new_name) - .unwrap(), - ) - .unwrap(); + self.state.online_users.write().unwrap().insert(addr, buf); // Send welcome back messages let msg = format! { @@ -241,15 +220,12 @@ impl UserHandler { .insert(new_name.clone()); // Change user's name - self.state - .online_users - .write() - .unwrap() - .get_mut(&addr) - .unwrap() - .write() - .unwrap() - .change_name(request.username); + if let Some(user) = self.state.online_users.write().unwrap().get_mut(&addr) { + user.write().unwrap().change_name(request.username); + } else { + tracing::error!("Error updating username: Can't find user!"); + return; + } // Send chat updates let msg = format! { @@ -257,9 +233,8 @@ impl UserHandler { old_name, new_name }; - broadcast_tx - .send(to_string::(&ChatMessage { text: msg }).unwrap()) - .unwrap(); + let _ = + broadcast_tx.send(to_string::(&ChatMessage { text: msg }).unwrap()); } // Send the user their new name @@ -270,12 +245,9 @@ impl UserHandler { Addr(addr), ) .await; - // Send client updates - broadcast_tx - .send(meta_games_browser_update(&self.state)) - .unwrap(); - broadcast_tx.send(meta_chat_update(&self.state)).unwrap(); + let _ = broadcast_tx.send(meta_games_browser_update(&self.state)); + let _ = broadcast_tx.send(meta_chat_update(&self.state)); } } @@ -347,18 +319,13 @@ pub fn meta_games_browser_update(state: &Arc) -> String { /// Generate chatroom join announcement pub fn meta_announce_user_join(state: &Arc, addr: &SocketAddr) -> String { - let msg = format!( - "{} joined.", - state - .online_users - .read() - .unwrap() - .get(addr) - .unwrap() - .read() - .unwrap() - .name - ); + let msg = format!("{} joined.", { + if let Some(user) = state.online_users.read().unwrap().get(addr) { + user.read().unwrap().name.clone() + } else { + return Default::default(); + } + }); tracing::debug!("{}", &msg); to_string::(&ChatMessage { text: msg }).unwrap()