reduce potential explosions and add error messages

This commit is contained in:
Adam 2024-08-27 22:03:27 -04:00
parent 13ba4944ca
commit 1550772995
2 changed files with 194 additions and 260 deletions

View file

@ -46,123 +46,101 @@ impl GameHandler {
/// Delete game /// Delete game
async fn delete_game(&self, request: GameDeleteRequest) { async fn delete_game(&self, request: GameDeleteRequest) {
// TODO: add auth lol // TODO: add auth lol
let _ = self if self
.state .state
.games .games
.write() .write()
.unwrap() .unwrap()
.remove(&request.delete_game_id) .remove(&request.delete_game_id)
.unwrap(); .is_some()
{
// Broadcast game browser update // Broadcast game browser update
self.state self.state
.broadcast_tx .broadcast_tx
.send(meta_games_browser_update(&self.state)) .send(meta_games_browser_update(&self.state))
.unwrap(); .unwrap();
} else {
tracing::error!("User tried to delete a nonexistent game!");
}
} }
/// Process judging /// Process judging
async fn handle_judging(&self, request: JudgeDecisionRequest, addr: SocketAddr) { async fn handle_judging(&self, request: JudgeDecisionRequest, addr: SocketAddr) {
// Get pointers if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) {
let player_user_id = self if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) {
.state let player_user_id = player_user.read().unwrap().uuid.to_string();
.online_users let game_id = request.game_id.to_string();
.read()
.unwrap()
.get(&addr)
.unwrap()
.read()
.unwrap()
.uuid
.to_string();
let this_game = self // Send to game
.state this_game
.games .write()
.read() .unwrap()
.unwrap() .judge_round(request, player_user_id);
.get(&request.game_id)
.unwrap()
.clone();
// Send to game self.send_game_state_update(game_id);
this_game } else {
.write() tracing::error!("Received judge request for nonexistent judge player!");
.unwrap() }
.judge_round(request.clone(), player_user_id.clone()); } else {
tracing::error!("Received judge request for nonexistent game!");
let this_game_id = this_game.read().unwrap().uuid.to_string(); }
self.send_game_state_update(this_game_id).await
} }
/// Process player move request /// Process player move request
async fn handle_player_move(&self, request: PlayerMoveRequest, addr: SocketAddr) { async fn handle_player_move(&self, request: PlayerMoveRequest, addr: SocketAddr) {
// Get pointers if let Some(this_game) = self.state.games.read().unwrap().get(&request.game_id) {
let player_user_id = self if let Some(player_user) = self.state.online_users.read().unwrap().get(&addr) {
.state let player_user_id = player_user.read().unwrap().uuid.to_string();
.online_users
.read()
.unwrap()
.get(&addr)
.unwrap()
.read()
.unwrap()
.uuid
.to_string();
let this_game = self // Do the stuff
.state match this_game
.games .write()
.read() .unwrap()
.unwrap() .player_move(request, player_user_id)
.get(&request.game_id) {
.unwrap() Err(err) => {
.clone(); 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 tokio::spawn(async move {
match this_game let _ = tx
.write() .send(DmUser(SendJudgeRound(judge_round), Id(czar_id)))
.unwrap() .await;
.player_move(request, player_user_id) })
{ }
Err(err) => { };
let message = ChatMessage { text: err }; } else {
let tx = self.state.users_tx.clone(); tracing::error!("Nonexistent player tried to submit move for game!");
tokio::spawn(async move {
let _ = tx.send(DmUser(SendChatMessage(message), Addr(addr))).await;
})
} }
Ok(None) => tokio::spawn(async move { tracing::debug!("None") }), } else {
Ok(Some((judge_round, czar_id))) => { tracing::error!("Player tried to submit move for nonexistent game!");
let tx = self.state.users_tx.clone(); }
tokio::spawn(async move {
let _ = tx
.send(DmUser(SendJudgeRound(judge_round), Id(czar_id)))
.await;
})
}
};
} }
/// Puts a user in a game /// Puts a user in a game
async fn join_game(&self, id: String, addr: SocketAddr) { async fn join_game(&self, id: String, addr: SocketAddr) {
// Get pointers if let Some(this_game) = self.state.games.read().unwrap().get(&id) {
let this_game = self.state.games.read().unwrap().get(&id).unwrap().clone(); if let Some(this_user) = self.state.online_users.read().unwrap().get(&addr) {
let this_user = self // Create player
.state this_game.write().unwrap().create_player(this_user.clone());
.online_users } else {
.read() tracing::error!("Tried to add a nonexistent user to game!");
.unwrap() return;
.get(&addr) }
.unwrap() } else {
.clone(); tracing::error!("User tried to join a nonexistent game!");
return;
// Create player }
this_game.write().unwrap().create_player(this_user);
// Send updates for all players // Send updates for all players
self.send_game_state_update(id).await; self.send_game_state_update(id);
// Broadcast game browser update // Broadcast game browser update
self.state self.state
@ -178,57 +156,52 @@ impl GameHandler {
} }
/// Send game state update for all players of a game /// Send game state update for all players of a game
async fn send_game_state_update(&self, game_id: String) { fn send_game_state_update(&self, game_id: String) {
let this_game = self if let Some(this_game) = self.state.games.read().unwrap().get(&game_id) {
.state let players = this_game
.games .read()
.read() .unwrap()
.unwrap() .players
.get(&game_id) .values()
.unwrap() .map(|player| GamePlayerMeta {
.clone(); name: player.user.read().unwrap().name.clone(),
score: player.black.len(),
})
.collect::<Vec<GamePlayerMeta>>();
let players = this_game for player in this_game.read().unwrap().players.values() {
.read() // Create update for user's game view
.unwrap() let meta = GameStateMeta {
.players uuid: game_id.clone(),
.values() name: this_game.read().unwrap().name.clone(),
.map(|player| GamePlayerMeta { host: this_game.read().unwrap().host.read().unwrap().name.clone(),
name: player.user.read().unwrap().name.clone(), players: players.clone(),
score: player.black.len(), czar: this_game.read().unwrap().czar.read().unwrap().name.clone(),
}) black: (
.collect::<Vec<GamePlayerMeta>>(); 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() { // Send user's update
// Create update for user's game view let msg = serde_json::to_string(&meta).unwrap();
let meta = GameStateMeta { let user_tx = player.user.read().unwrap().tx.clone();
uuid: game_id.clone(), tokio::spawn(async move { user_tx.send(msg).await });
name: this_game.read().unwrap().name.clone(), }
host: this_game.read().unwrap().host.read().unwrap().name.clone(), } else {
players: players.clone(), tracing::error!("Attempted to create game state update for nonexistent game!");
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 });
} }
} }
@ -242,49 +215,43 @@ impl GameHandler {
return; return;
} }
// Get host pointer if let Some(host) = self.state.online_users.read().unwrap().get(&addr) {
let host = self // Create manifest
.state let manifest = NewGameManifest {
.online_users name: new_game.name,
.read() host: host.clone(),
.unwrap() packs: new_game.packs,
.get(&addr) };
.unwrap()
.clone();
// Create manifest // Create game using manifest
let manifest = NewGameManifest { let mut new_game_object = Game::new(self.state.clone(), manifest);
name: new_game.name,
host: host.clone(),
packs: new_game.packs,
};
// Create game using manifest // Don't forget to create the host player!!!
let mut new_game_object = Game::new(self.state.clone(), manifest); new_game_object.create_player(host.clone());
// Don't forget to create the host player!!! let game_id = new_game_object.uuid.to_string();
new_game_object.create_player(host.clone());
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.send_game_state_update(game_id);
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).await; // Broadcast game browser update
self.state
.broadcast_tx
.send(meta_games_browser_update(&self.state))
.unwrap();
// Broadcast game browser update // Broadcast server meta update
self.state self.state
.broadcast_tx .broadcast_tx
.send(meta_games_browser_update(&self.state)) .send(meta_server_summary_update(&self.state))
.unwrap(); .unwrap();
} else {
// Broadcast server meta update tracing::error!("Attempted to create game for nonexistent player!");
self.state }
.broadcast_tx
.send(meta_server_summary_update(&self.state))
.unwrap();
} }
} }

View file

@ -63,6 +63,8 @@ impl UserHandler {
tx = user.read().unwrap().tx.clone(); tx = user.read().unwrap().tx.clone();
} else { } else {
tracing::error!("Attempted to send message to invalid user id!"); 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; return;
} }
} }
@ -77,6 +79,7 @@ impl UserHandler {
} }
// Serialize and send message // Serialize and send message
// TODO: Send failures are suppressed
match message { match message {
SendUserUpdate(message) => { SendUserUpdate(message) => {
let msg = to_string::<UserUpdate>(&message).unwrap(); let msg = to_string::<UserUpdate>(&message).unwrap();
@ -99,7 +102,7 @@ impl UserHandler {
let new_user = Arc::new(RwLock::new(user)); let new_user = Arc::new(RwLock::new(user));
// Notify client of new username // 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 // Register uuid
self.state self.state
@ -116,12 +119,8 @@ impl UserHandler {
.insert(addr, new_user.clone()); .insert(addr, new_user.clone());
// Hydrate client // Hydrate client
tx.send(meta_games_browser_update(&self.state)) let _ = tx.send(meta_games_browser_update(&self.state)).await;
.await let _ = tx.send(meta_new_game_card_packs(&self.state)).await;
.unwrap();
tx.send(meta_new_game_card_packs(&self.state))
.await
.unwrap();
// Broadcast new user's existence // Broadcast new user's existence
// TODO: this should probably be combined and sent as one // 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)); 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(); let _ = tx.send(meta_motd()).await;
} }
/// Handle user login /// Handle user login
async fn login(&self, request: UserLogInRequest, addr: SocketAddr) { async fn login(&self, request: UserLogInRequest, addr: SocketAddr) {
let broadcast_tx = self.state.broadcast_tx.clone(); let broadcast_tx = self.state.broadcast_tx.clone();
let new_name = request.username.clone(); let new_name = request.username.clone();
let old_name = self let old_name;
.state
.online_users if let Some(user) = self.state.online_users.read().unwrap().get(&addr) {
.read() old_name = user.read().unwrap().name.clone();
.unwrap() } else {
.get(&addr) tracing::error!("Nonexistent user attempting login");
.unwrap() return;
.read() }
.unwrap()
.name
.clone();
// Resume user's old session if they exist as offline // Resume user's old session if they exist as offline
if self if self
@ -163,42 +159,25 @@ impl UserHandler {
.unwrap() .unwrap()
.contains_key(&new_name) .contains_key(&new_name)
{ {
let buf;
// Copy over new tx // Copy over new tx
self.state if let Some(online_user) = self.state.online_users.write().unwrap().remove(&addr) {
.offline_users if let Some(offline_user) =
.read() self.state.offline_users.write().unwrap().remove(&new_name)
.unwrap() {
.get(&new_name) offline_user.write().unwrap().tx = online_user.write().unwrap().tx.clone();
.unwrap() buf = offline_user;
.write() } else {
.unwrap() tracing::error!("Error copying tx to new user: Can't find offline user!");
.tx = self return;
.state }
.online_users } else {
.read() tracing::error!("Error copying tx to new user: Can't find online user!");
.unwrap() return;
.get(&addr) }
.unwrap()
.read()
.unwrap()
.tx
.clone();
// Move offline user object to online // Move offline user object to online
self.state self.state.online_users.write().unwrap().insert(addr, buf);
.online_users
.write()
.unwrap()
.insert(
addr,
self.state
.offline_users
.write()
.unwrap()
.remove(&new_name)
.unwrap(),
)
.unwrap();
// Send welcome back messages // Send welcome back messages
let msg = format! { let msg = format! {
@ -241,15 +220,12 @@ impl UserHandler {
.insert(new_name.clone()); .insert(new_name.clone());
// Change user's name // Change user's name
self.state if let Some(user) = self.state.online_users.write().unwrap().get_mut(&addr) {
.online_users user.write().unwrap().change_name(request.username);
.write() } else {
.unwrap() tracing::error!("Error updating username: Can't find user!");
.get_mut(&addr) return;
.unwrap() }
.write()
.unwrap()
.change_name(request.username);
// Send chat updates // Send chat updates
let msg = format! { let msg = format! {
@ -257,9 +233,8 @@ impl UserHandler {
old_name, old_name,
new_name new_name
}; };
broadcast_tx let _ =
.send(to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap()) broadcast_tx.send(to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap());
.unwrap();
} }
// Send the user their new name // Send the user their new name
@ -270,12 +245,9 @@ impl UserHandler {
Addr(addr), Addr(addr),
) )
.await; .await;
// Send client updates // Send client updates
broadcast_tx let _ = broadcast_tx.send(meta_games_browser_update(&self.state));
.send(meta_games_browser_update(&self.state)) let _ = broadcast_tx.send(meta_chat_update(&self.state));
.unwrap();
broadcast_tx.send(meta_chat_update(&self.state)).unwrap();
} }
} }
@ -347,18 +319,13 @@ pub fn meta_games_browser_update(state: &Arc<AppState>) -> String {
/// Generate chatroom join announcement /// Generate chatroom join announcement
pub fn meta_announce_user_join(state: &Arc<AppState>, addr: &SocketAddr) -> String { pub fn meta_announce_user_join(state: &Arc<AppState>, addr: &SocketAddr) -> String {
let msg = format!( let msg = format!("{} joined.", {
"{} joined.", if let Some(user) = state.online_users.read().unwrap().get(addr) {
state user.read().unwrap().name.clone()
.online_users } else {
.read() return Default::default();
.unwrap() }
.get(addr) });
.unwrap()
.read()
.unwrap()
.name
);
tracing::debug!("{}", &msg); tracing::debug!("{}", &msg);
to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap() to_string::<ChatMessage>(&ChatMessage { text: msg }).unwrap()