You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

154 lines
5.3 KiB

use tonic::{Request, Response, Status};
use tokio::sync::{mpsc, RwLock};
use std::{collections::HashMap, convert::TryInto, sync::Arc};
use super::grpc::common::{HasNewStatus, LastStatusTimestamp, Name};
use super::grpc::lobby::lobby_server::Lobby;
use super::grpc::lobby::{LobbyStatus, SingleVote, Vote};
use super::grpc::game::MessageStatus;
pub use super::grpc::lobby::lobby_server::LobbyServer;
use super::votes::{self, Modifiable};
use super::client_id;
use crate::{db, games::RunningGame};
pub struct LobbyService {
conn: RwLock<db::DbClient>,
games: Arc<Vec<crate::games::Game>>,
voting: votes::VotingSystem,
running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame, Modifiable<Option<MessageStatus>>)>>>>,
}
impl LobbyService {
pub fn new(
conn: db::DbClient,
voting: votes::VotingSystem,
games: Arc<Vec<crate::games::Game>>,
running_games: Arc<RwLock<HashMap<u32, RwLock<(u32, RunningGame, Modifiable<Option<MessageStatus>>)>>>>,
) -> Self {
Self {
conn: RwLock::new(conn),
voting,
running_games,
games,
}
}
}
#[tonic::async_trait]
impl Lobby for LobbyService {
async fn vote(&self, request: Request<SingleVote>) -> Result<Response<()>, 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 req = request.into_inner();
self.voting.vote(uuid, req.game).await;
Ok(Response::new(()))
}
async fn ready(&self, request: Request<()>) -> Result<Response<()>, 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"),
})?;
if let Some(Some(winner)) = self.voting.ready(uuid).await {
let mut conn = self.conn.write().await;
let lobby = conn.get_lobby_for_user(uuid).await.unwrap();
log::info!("[{}] Starting a game ({})", lobby, winner);
let user_count = conn.get_uuids_in_lobby_where_user_is(uuid).await;
let game = self.games[winner as usize].run(&user_count);
self.running_games
.write()
.await
.insert(lobby, RwLock::new((winner, game, Modifiable::new(None))));
}
Ok(Response::new(()))
}
async fn poll_status(
&self,
request: Request<LastStatusTimestamp>,
) -> Result<Response<HasNewStatus>, 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.acquire().await;
let inner = request.into_inner();
let time = inner
.time
.ok_or(Status::failed_precondition("timestamp musn't be null"))?
.try_into()
.unwrap();
Ok(Response::new(HasNewStatus {
value: self.voting.has_new_status(&inner.lobby, time).await,
}))
}
async fn get_status(&self, request: Request<()>) -> Result<Response<LobbyStatus>, 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;
if let Some(l) = conn.get_lobby_for_user(uuid).await {
let (votes, is_starting) = self.voting.status(&l).await.unwrap_or_default();
let names = conn.get_users_in_lobby_where_user_is(uuid).await;
// log::info!("Users: {:?}", names);
Ok(Response::new(LobbyStatus {
names: names.into_iter().map(|x| Name { name: x }).collect(),
votes: votes
.into_iter()
.map(|(player, game, ready)| Vote {
player,
game,
ready,
})
.collect(),
is_starting,
}))
} else {
Err(Status::failed_precondition("User isn't in a lobby"))
}
}
async fn leave(
&self,
request: tonic::Request<()>,
) -> Result<tonic::Response<()>, tonic::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;
if let Some(l) = conn.get_lobby_for_user(uuid).await {
// log::info!("Updating lobby status");
self.voting.updated_users(&l).await;
// log::info!("Updated lobby status");
}
conn.leave_lobby(uuid).await;
Ok(Response::new(()))
}
type usersStream = mpsc::UnboundedReceiver<Result<Name, Status>>;
async fn users(&self, request: Request<()>) -> Result<Response<Self::usersStream>, 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 (sender, receiver) = mpsc::unbounded_channel();
let mut conn = self.conn.write().await;
for name in conn.get_users_in_lobby_where_user_is(uuid).await {
sender.send(Ok(Name { name })).unwrap();
}
Ok(Response::new(receiver))
}
}