diff --git a/server/src/db.rs b/server/src/db.rs index 51046b5..720d32f 100644 --- a/server/src/db.rs +++ b/server/src/db.rs @@ -149,7 +149,7 @@ impl Db { } // FIXME: return Results intead of crashing pub fn disconnect(&mut self, user: Uuid) { - // self.leave_lobby(user).await; + self.leave_lobby(user); log::info!("{} disconnecting", user); self.conn .execute( diff --git a/server/src/server/game.rs b/server/src/server/game.rs index cd9c50c..7c4c2aa 100644 --- a/server/src/server/game.rs +++ b/server/src/server/game.rs @@ -2,8 +2,12 @@ use crate::games::{CardId, CardIdx, Pile, PileKind, RunningGame}; use crate::{db, games::Game}; use super::{ - client_id, - grpc::game::{game_server, message_status::Piles, CardKind, Image, MessageStatus}, + client_id, + grpc::game::{ + game_server, + message_status::Piles, + CardKind, Image, MessageStatus, + }, }; pub use game_server::GameServer; use tonic::{Response, Status}; @@ -14,164 +18,190 @@ use std::sync::Arc; use tokio::sync::RwLock; pub struct GameService { - conn: RwLock, - games: Arc>, - running_games: Arc>>>, + conn: RwLock, + games: Arc>, + running_games: Arc>>>, } impl GameService { - pub fn new( - conn: db::DbClient, - games: Arc>, - running_games: Arc>>>, - ) -> Self { - Self { - conn: RwLock::new(conn), - running_games, - games, - } - } + pub fn new( + conn: db::DbClient, + games: Arc>, + running_games: Arc>>>, + ) -> Self { + Self { + conn: RwLock::new(conn), + running_games, + games, + } + } } #[tonic::async_trait] impl game_server::Game for GameService { - async fn get_card_image( - &self, - request: tonic::Request, - ) -> Result, Status> { - let uuid = client_id::get(request.metadata()).map_err(|x| match x { - client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), - client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), - })?; - let mut conn = self.conn.write().await; - let lobby: u32 = match conn.get_lobby_for_user(uuid).await { - Some(l) => l, - None => return Err(Status::failed_precondition("User isn't in a lobby")), - }; - let game_id = match self.running_games.read().await.get(&lobby) { - Some(x) => x.read().await.0, - None => { - return Err(Status::failed_precondition( - "User isn't in a lobby with a running game", - )) - } - }; - let game = &self.games[game_id as usize]; - let (face, back) = game.get_card_paths(&request.into_inner().kind); - let mut face_buf = Vec::new(); - image::open(&face) - .expect(&format!("Error loading the image in {:?}", face)) - .write_to(&mut face_buf, image::ImageOutputFormat::Png) - .unwrap(); - let mut back_buf = Vec::new(); - image::open(&back) - .expect(&format!("Error loading the image in {:?}", back)) - .write_to(&mut back_buf, image::ImageOutputFormat::Png) - .unwrap(); - Ok(Response::new(Image { - face: face_buf, - back: back_buf, - })) - } + async fn get_card_image( + &self, + request: tonic::Request, + ) -> Result, Status> { + let uuid = client_id::get(request.metadata()).map_err(|x| match x { + client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), + client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), + })?; + let mut conn = self.conn.write().await; + let lobby: u32 = match conn.get_lobby_for_user(uuid).await { + Some(l) => l, + None => return Err(Status::failed_precondition("User isn't in a lobby")), + }; + let game_id = match self.running_games.read().await.get(&lobby) { + Some(x) => x.read().await.0, + None => { + return Err(Status::failed_precondition( + "User isn't in a lobby with a running game", + )) + } + }; + let game = &self.games[game_id as usize]; + let (face, back) = game.get_card_paths(&request.into_inner().kind); + let mut face_buf = Vec::new(); + image::open(&face) + .expect(&format!("Error loading the image in {:?}", face)) + .write_to(&mut face_buf, image::ImageOutputFormat::Png) + .unwrap(); + let mut back_buf = Vec::new(); + image::open(&back) + .expect(&format!("Error loading the image in {:?}", back)) + .write_to(&mut back_buf, image::ImageOutputFormat::Png) + .unwrap(); + Ok(Response::new(Image { + face: face_buf, + back: back_buf, + })) + } - async fn on_click( - &self, - request: tonic::Request, - ) -> Result, Status> { - let uuid = client_id::get(request.metadata()).map_err(|x| match x { - client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), - client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), - })?; - let mut conn = self.conn.write().await; - let lobby: u32 = match conn.get_lobby_for_user(uuid).await { - Some(l) => l, - None => return Err(Status::failed_precondition("User isn't in a lobby")), - }; - let games_lock = self.running_games.read().await; - let mut game_lock = match games_lock.get(&lobby) { - Some(x) => x.write().await, - None => { - return Err(Status::failed_precondition( - "User isn't in a lobby with a running game", - )) - } - }; - let game = &mut game_lock.1; - let card = request.into_inner(); - let idx = match card.card_index.unwrap().pos.unwrap() { - super::grpc::game::card_index::Pos::Bottom(()) => CardIdx::Bottom, - super::grpc::game::card_index::Pos::Top(()) => CardIdx::Top, - super::grpc::game::card_index::Pos::Index(x) => CardIdx::Indexed(x as usize), - }; - let pile_kind = match card.pile_kind.unwrap().kind.unwrap() { - super::grpc::game::pile_kind::Kind::Common(()) => PileKind::Common, - super::grpc::game::pile_kind::Kind::Owned(p) => PileKind::Owned(p), - }; - let card: CardId = CardId { - idx, - pile_kind, - pile_name: card.pile_name, - }; - game.on_click(card, game.get_player_for_uuid(&uuid).unwrap()); - Ok(Response::new(())) - } + async fn on_click( + &self, + request: tonic::Request, + ) -> Result, Status> { + let uuid = client_id::get(request.metadata()).map_err(|x| match x { + client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), + client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), + })?; + let mut conn = self.conn.write().await; + let lobby: u32 = match conn.get_lobby_for_user(uuid).await { + Some(l) => l, + None => return Err(Status::failed_precondition("User isn't in a lobby")), + }; + let games_lock = self.running_games.read().await; + let mut game_lock = match games_lock.get(&lobby) { + Some(x) => x.write().await, + None => { + return Err(Status::failed_precondition( + "User isn't in a lobby with a running game", + )) + } + }; + let game = &mut game_lock.1; + let card = request.into_inner(); + let idx = match card.card_index.unwrap().pos.unwrap() { + super::grpc::game::card_index::Pos::Bottom(()) => CardIdx::Bottom, + super::grpc::game::card_index::Pos::Top(()) => CardIdx::Top, + super::grpc::game::card_index::Pos::Index(x) => CardIdx::Indexed(x as usize), + }; + let pile_kind = match card.pile_kind.unwrap().kind.unwrap() { + super::grpc::game::pile_kind::Kind::Common(()) => PileKind::Common, + super::grpc::game::pile_kind::Kind::Owned(p) => PileKind::Owned(p), + }; + let card: CardId = CardId { + idx, + pile_kind, + pile_name: card.pile_name, + }; + game.on_click(card, game.get_player_for_uuid(&uuid).unwrap()); + Ok(Response::new(())) + } - async fn status( - &self, - request: tonic::Request<()>, - ) -> Result, Status> { - let uuid = client_id::get(request.metadata()).map_err(|x| match x { - client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), - client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), - })?; - let mut conn = self.conn.write().await; - let lobby: u32 = match conn.get_lobby_for_user(uuid).await { - Some(l) => l, - None => return Err(Status::failed_precondition("User isn't in a lobby")), - }; - let games_lock = self.running_games.read().await; - let game_lock = match games_lock.get(&lobby) { - Some(x) => x.read().await, - None => { - return Err(Status::failed_precondition( - "User isn't in a lobby with a running game", - )) - } - }; - let game = &game_lock.1; - let mut names = vec![]; - for (uuid, id) in &game.players { - names.push((conn.get_name_for_uuid(uuid.clone()).await, *id)) - } - names.sort_by(|(_, a), (_, b)| a.cmp(b)); - let names = names.into_iter().map(|(x, _)| super::grpc::common::Name {name: x}).collect(); - let status = MessageStatus { - current_turn: game.get_current_player(), - common_piles: Some(Piles { - piles: game - .piles - .iter() - .map(|(k, v)| (k.clone(), v.clone())) - .map(|(k, v): (String, Pile)| { - ( - k, - super::grpc::game::message_status::Pile { - cards: v - .cards - .into_iter() - .map(|c| super::grpc::game::message_status::Card { - kind: Some(CardKind { kind: c }), - visible: true, - }) - .collect(), - }, - ) - }) - .collect(), - }), - player_piles: vec![], - names, - }; - Ok(Response::new(status)) - } + async fn status( + &self, + request: tonic::Request<()>, + ) -> Result, Status> { + let uuid = client_id::get(request.metadata()).map_err(|x| match x { + client_id::Error::NotSet => Status::failed_precondition("client_id must be set"), + client_id::Error::MalformedUuid => Status::failed_precondition("malformed client_id"), + })?; + let mut conn = self.conn.write().await; + let lobby: u32 = match conn.get_lobby_for_user(uuid).await { + Some(l) => l, + None => return Err(Status::failed_precondition("User isn't in a lobby")), + }; + let games_lock = self.running_games.read().await; + let game_lock = match games_lock.get(&lobby) { + Some(x) => x.read().await, + None => { + return Err(Status::failed_precondition( + "User isn't in a lobby with a running game", + )) + } + }; + let game = &game_lock.1; + let mut names = vec![]; + for (uuid, id) in &game.players { + names.push((conn.get_name_for_uuid(uuid.clone()).await, *id)) + } + names.sort_by(|(_, a), (_, b)| a.cmp(b)); + let names = names + .into_iter() + .map(|(x, _)| super::grpc::common::Name { name: x }) + .collect(); + let status = MessageStatus { + current_turn: game.get_current_player(), + common_piles: Some(Piles { + piles: game + .piles + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .map(|(k, v): (String, Pile)| { + ( + k, + super::grpc::game::message_status::Pile { + cards: v + .cards + .into_iter() + .map(|c| super::grpc::game::message_status::Card { + kind: Some(CardKind { kind: c }), + visible: true, + }) + .collect(), + }, + ) + }) + .collect(), + }), + player_piles: game + .player_piles.clone() + .into_iter() + .map(|piles| Piles { + piles: piles + .into_iter() + .map(|(k, v)| { + ( + k, + super::grpc::game::message_status::Pile { + cards: v + .cards + .into_iter() + .map(|x| super::grpc::game::message_status::Card { + kind: Some(CardKind {kind: x}), + visible: true, + }) + .collect(), + }, + ) + }) + .collect(), + }) + .collect(), + names, + }; + Ok(Response::new(status)) + } }