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
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))
|
|
}
|
|
}
|
|
|