12 changed files with 435 additions and 266 deletions
@ -1,223 +0,0 @@ |
|||
use tonic::{transport::Server, Request, Response, Status}; |
|||
|
|||
use log::info; |
|||
|
|||
use std::sync::Arc; |
|||
|
|||
#[allow(non_camel_case_types)] |
|||
mod game; |
|||
|
|||
use game::connection_server::{Connection, ConnectionServer}; |
|||
use game::lobby_server::{Lobby, LobbyServer}; |
|||
use game::{CardId, Image, LobbyCode, LobbyConfig, Name, Null, UserId}; |
|||
|
|||
use crate::db; |
|||
|
|||
pub struct ConnectionService { |
|||
conn: Arc<db::DbPool>, |
|||
properties: Arc<crate::server_properties::ServerProperties>, |
|||
games: Arc<Vec<crate::games::Game>>, |
|||
} |
|||
|
|||
#[tonic::async_trait] |
|||
impl Connection for ConnectionService { |
|||
async fn connect(&self, request: Request<Name>) -> Result<Response<UserId>, Status> { |
|||
let name = request.into_inner().name; |
|||
let mut conn = self.conn.acquire().await; |
|||
let uuid = conn.add_user(&name).await; |
|||
info!("Connected {}[{}]", name, uuid); |
|||
conn.close().await; |
|||
Ok(Response::new(UserId { |
|||
id: uuid.to_hyphenated().to_string(), |
|||
})) |
|||
} |
|||
|
|||
async fn join_lobby_with_code( |
|||
&self, |
|||
request: Request<LobbyCode>, |
|||
) -> Result<Response<Null>, 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 lobby = request.get_ref().code; |
|||
let mut conn = self.conn.acquire().await; |
|||
conn.join_lobby(uuid, lobby).await; |
|||
conn.close().await; |
|||
Ok(Response::new(Null {})) |
|||
} |
|||
|
|||
async fn create_lobby( |
|||
&self, |
|||
request: Request<LobbyConfig>, |
|||
) -> Result<Response<LobbyCode>, 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 lobby = conn.create_lobby(request.into_inner().public).await; |
|||
conn.join_lobby(uuid, lobby).await; |
|||
conn.close().await; |
|||
Ok(Response::new(LobbyCode { code: lobby })) |
|||
} |
|||
|
|||
async fn name(&self, _request: Request<Null>) -> Result<Response<game::Name>, Status> { |
|||
Ok(Response::new(game::Name { |
|||
name: self.properties.name.clone(), |
|||
})) |
|||
} |
|||
|
|||
type getGamesStream = mpsc::UnboundedReceiver<Result<game::Game, tonic::Status>>; |
|||
|
|||
async fn get_games(&self, _: Request<Null>) -> Result<Response<Self::getGamesStream>, Status> { |
|||
let (sender, receiver) = mpsc::unbounded_channel(); |
|||
for (id, game) in self.games.iter().enumerate() { |
|||
sender |
|||
.send(Ok(game::Game { |
|||
id: id as u32, |
|||
name: game.name.clone(), |
|||
version: game.version.clone(), |
|||
authors: game.authors.clone(), |
|||
})) |
|||
.unwrap(); |
|||
} |
|||
Ok(Response::new(receiver)) |
|||
} |
|||
|
|||
type getPublicLobbiesStream = mpsc::UnboundedReceiver<Result<LobbyCode, tonic::Status>>; |
|||
|
|||
async fn get_public_lobbies( |
|||
&self, |
|||
_request: Request<Null>, |
|||
) -> Result<Response<Self::getPublicLobbiesStream>, Status> { |
|||
let (sender, receiver) = mpsc::unbounded_channel(); |
|||
let mut conn = self.conn.acquire().await; |
|||
for id in conn.getPublicLobbies().await { |
|||
sender.send(Ok(LobbyCode { code: id })).unwrap(); |
|||
} |
|||
conn.close().await; |
|||
Ok(Response::new(receiver)) |
|||
} |
|||
|
|||
async fn disconnect(&self, request: Request<Null>) -> Result<Response<Null>, 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; |
|||
conn.disconnect(&uuid).await; |
|||
conn.close().await; |
|||
Ok(Response::new(Null {})) |
|||
} |
|||
} |
|||
|
|||
use tokio::sync::mpsc; |
|||
|
|||
pub struct LobbyService { |
|||
conn: Arc<db::DbPool>, |
|||
games: Arc<Vec<crate::games::Game>>, |
|||
} |
|||
|
|||
#[tonic::async_trait] |
|||
impl Lobby for LobbyService { |
|||
async fn get_card_image( |
|||
&self, |
|||
request: tonic::Request<CardId>, |
|||
) -> Result<tonic::Response<Image>, tonic::Status> { |
|||
let id = request.into_inner(); |
|||
let game = &self.games.as_ref()[id.game_id as usize]; |
|||
let card = game.get_card_path(&id.card_id); |
|||
let mut buffer = Vec::new(); |
|||
image::open(&card) |
|||
.expect(&format!("Error loading the image in {:?}", card)) |
|||
.write_to(&mut buffer, image::ImageOutputFormat::Png) |
|||
.unwrap(); |
|||
Ok(Response::new(Image { content: buffer })) |
|||
} |
|||
|
|||
async fn vote(&self, _request: Request<game::Vote>) -> Result<Response<Null>, Status> { |
|||
todo!() |
|||
} |
|||
|
|||
async fn ready(&self, _request: Request<Null>) -> Result<Response<Null>, Status> { |
|||
todo!() |
|||
} |
|||
|
|||
async fn status(&self, _request: Request<Null>) -> Result<Response<game::LobbyStatus>, Status> { |
|||
todo!() |
|||
} |
|||
|
|||
async fn leave( |
|||
&self, |
|||
request: tonic::Request<Null>, |
|||
) -> Result<tonic::Response<Null>, 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.acquire().await; |
|||
conn.leave_lobby(&uuid).await; |
|||
conn.close().await; |
|||
Ok(Response::new(Null {})) |
|||
} |
|||
|
|||
type usersStream = mpsc::UnboundedReceiver<Result<Name, tonic::Status>>; |
|||
|
|||
async fn users(&self, request: Request<Null>) -> 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.acquire().await; |
|||
for name in conn.getUsersInLobbyWhereUserIs(uuid).await { |
|||
sender.send(Ok(Name {name})).unwrap(); |
|||
} |
|||
conn.close().await; |
|||
Ok(Response::new(receiver)) |
|||
} |
|||
} |
|||
|
|||
pub async fn start( |
|||
pool: db::DbPool, |
|||
games: Vec<crate::games::Game>, |
|||
properties: crate::server_properties::ServerProperties, |
|||
) { |
|||
let arc = Arc::new(pool); |
|||
let properties = Arc::new(properties); |
|||
let games = Arc::new(games); |
|||
let connection = ConnectionService { |
|||
conn: arc.clone(), |
|||
properties: properties.clone(), |
|||
games: games.clone(), |
|||
}; |
|||
let lobby = LobbyService { |
|||
conn: arc.clone(), |
|||
games, |
|||
}; |
|||
|
|||
Server::builder() |
|||
.add_service(ConnectionServer::new(connection)) |
|||
.add_service(LobbyServer::new(lobby)) |
|||
.serve(properties.addr) |
|||
.await |
|||
.unwrap(); |
|||
} |
|||
|
|||
mod client_id { |
|||
pub fn get(metadata: &tonic::metadata::MetadataMap) -> Result<uuid::Uuid, Error> { |
|||
metadata |
|||
.get("client_id") |
|||
.ok_or(Error::NotSet) |
|||
.and_then(|x| { |
|||
uuid::Uuid::parse_str(x.to_str().map_err(|_| Error::MalformedUuid)?) |
|||
.map_err(|_| Error::MalformedUuid) |
|||
}) |
|||
} |
|||
|
|||
pub enum Error { |
|||
MalformedUuid, |
|||
NotSet, |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
use tonic::transport::Server; |
|||
|
|||
use std::sync::Arc; |
|||
|
|||
use crate::db; |
|||
|
|||
mod connection; |
|||
mod grpc; |
|||
mod lobby; |
|||
|
|||
use grpc::game::connection_server::ConnectionServer; |
|||
use grpc::game::lobby_server::LobbyServer; |
|||
|
|||
use connection::ConnectionService; |
|||
use lobby::LobbyService; |
|||
|
|||
pub async fn start( |
|||
pool: db::DbPool, |
|||
games: Vec<crate::games::Game>, |
|||
properties: crate::server_properties::ServerProperties, |
|||
) { |
|||
let arc = Arc::new(pool); |
|||
let properties = Arc::new(properties); |
|||
let games = Arc::new(games); |
|||
let connection = ConnectionService { |
|||
conn: arc.clone(), |
|||
properties: properties.clone(), |
|||
games: games.clone(), |
|||
}; |
|||
let lobby = LobbyService::new(arc.clone(), games); |
|||
|
|||
Server::builder() |
|||
.add_service(ConnectionServer::new(connection)) |
|||
.add_service(LobbyServer::new(lobby)) |
|||
.serve(properties.addr) |
|||
.await |
|||
.unwrap(); |
|||
} |
|||
|
|||
mod client_id { |
|||
pub fn get(metadata: &tonic::metadata::MetadataMap) -> Result<uuid::Uuid, Error> { |
|||
metadata |
|||
.get("client_id") |
|||
.ok_or(Error::NotSet) |
|||
.and_then(|x| { |
|||
uuid::Uuid::parse_str(x.to_str().map_err(|_| Error::MalformedUuid)?) |
|||
.map_err(|_| Error::MalformedUuid) |
|||
}) |
|||
} |
|||
|
|||
pub enum Error { |
|||
MalformedUuid, |
|||
NotSet, |
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
use tonic::{Request, Response, Status}; |
|||
|
|||
use log::info; |
|||
|
|||
use tokio::sync::mpsc; |
|||
|
|||
use std::sync::Arc; |
|||
|
|||
use super::grpc::game::connection_server::Connection; |
|||
use super::grpc::game::{LobbyCode, LobbyConfig, Name, Null, UserId, Game}; |
|||
|
|||
use super::client_id; |
|||
|
|||
use crate::db; |
|||
|
|||
pub struct ConnectionService { |
|||
pub conn: Arc<db::DbPool>, |
|||
pub properties: Arc<crate::server_properties::ServerProperties>, |
|||
pub games: Arc<Vec<crate::games::Game>>, |
|||
} |
|||
|
|||
#[tonic::async_trait] |
|||
impl Connection for ConnectionService { |
|||
async fn connect(&self, request: Request<Name>) -> Result<Response<UserId>, Status> { |
|||
let name = request.into_inner().name; |
|||
let mut conn = self.conn.acquire().await; |
|||
let uuid = conn.add_user(&name).await; |
|||
info!("Connected {}[{}]", name, uuid); |
|||
conn.close().await; |
|||
Ok(Response::new(UserId { |
|||
id: uuid.to_hyphenated().to_string(), |
|||
})) |
|||
} |
|||
|
|||
async fn join_lobby_with_code( |
|||
&self, |
|||
request: Request<LobbyCode>, |
|||
) -> Result<Response<Null>, 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 lobby = request.get_ref().code; |
|||
let mut conn = self.conn.acquire().await; |
|||
conn.join_lobby(uuid, lobby).await; |
|||
conn.close().await; |
|||
Ok(Response::new(Null {})) |
|||
} |
|||
|
|||
async fn create_lobby( |
|||
&self, |
|||
request: Request<LobbyConfig>, |
|||
) -> Result<Response<LobbyCode>, 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 lobby = conn.create_lobby(request.into_inner().public).await; |
|||
conn.join_lobby(uuid, lobby).await; |
|||
conn.close().await; |
|||
Ok(Response::new(LobbyCode { code: lobby })) |
|||
} |
|||
|
|||
async fn name(&self, _request: Request<Null>) -> Result<Response<Name>, Status> { |
|||
Ok(Response::new(Name { |
|||
name: self.properties.name.clone(), |
|||
})) |
|||
} |
|||
|
|||
type getGamesStream = mpsc::UnboundedReceiver<Result<Game, tonic::Status>>; |
|||
|
|||
async fn get_games(&self, _: Request<Null>) -> Result<Response<Self::getGamesStream>, Status> { |
|||
let (sender, receiver) = mpsc::unbounded_channel(); |
|||
for (id, game) in self.games.iter().enumerate() { |
|||
sender |
|||
.send(Ok(Game { |
|||
id: id as u32, |
|||
name: game.name.clone(), |
|||
version: game.version.clone(), |
|||
authors: game.authors.clone(), |
|||
})) |
|||
.unwrap(); |
|||
} |
|||
Ok(Response::new(receiver)) |
|||
} |
|||
|
|||
type getPublicLobbiesStream = mpsc::UnboundedReceiver<Result<LobbyCode, tonic::Status>>; |
|||
|
|||
async fn get_public_lobbies( |
|||
&self, |
|||
_request: Request<Null>, |
|||
) -> Result<Response<Self::getPublicLobbiesStream>, Status> { |
|||
let (sender, receiver) = mpsc::unbounded_channel(); |
|||
let mut conn = self.conn.acquire().await; |
|||
for id in conn.get_public_lobbies().await { |
|||
sender.send(Ok(LobbyCode { code: id })).unwrap(); |
|||
} |
|||
conn.close().await; |
|||
Ok(Response::new(receiver)) |
|||
} |
|||
|
|||
async fn disconnect(&self, request: Request<Null>) -> Result<Response<Null>, 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; |
|||
conn.disconnect(&uuid).await; |
|||
conn.close().await; |
|||
Ok(Response::new(Null {})) |
|||
} |
|||
} |
|||
@ -0,0 +1,2 @@ |
|||
#[allow(non_camel_case_types)] |
|||
pub mod game; |
|||
@ -0,0 +1,94 @@ |
|||
mod votes; |
|||
|
|||
use tonic::{Request, Response, Status}; |
|||
|
|||
use log::info; |
|||
|
|||
use tokio::sync::mpsc; |
|||
|
|||
use std::sync::Arc; |
|||
|
|||
use super::grpc::game::lobby_server::Lobby; |
|||
use super::grpc::game::{CardId, Image, LobbyStatus, Name, Null, Vote}; |
|||
|
|||
use super::client_id; |
|||
|
|||
use crate::db; |
|||
|
|||
pub struct LobbyService { |
|||
conn: Arc<db::DbPool>, |
|||
games: Arc<Vec<crate::games::Game>>, |
|||
voting: votes::VotingSystem, |
|||
} |
|||
|
|||
impl LobbyService { |
|||
pub fn new(conn: Arc<db::DbPool>, games: Arc<Vec<crate::games::Game>>) -> Self { |
|||
Self { games, conn: conn.clone(), voting: votes::VotingSystem::new(conn).0 } |
|||
} |
|||
} |
|||
|
|||
#[tonic::async_trait] |
|||
impl Lobby for LobbyService { |
|||
async fn get_card_image( |
|||
&self, |
|||
request: tonic::Request<CardId>, |
|||
) -> Result<tonic::Response<Image>, tonic::Status> { |
|||
let id = request.into_inner(); |
|||
let game = &self.games.as_ref()[id.game_id as usize]; |
|||
let card = game.get_card_path(&id.card_id); |
|||
let mut buffer = Vec::new(); |
|||
image::open(&card) |
|||
.expect(&format!("Error loading the image in {:?}", card)) |
|||
.write_to(&mut buffer, image::ImageOutputFormat::Png) |
|||
.unwrap(); |
|||
Ok(Response::new(Image { content: buffer })) |
|||
} |
|||
|
|||
async fn vote(&self, request: Request<Vote>) -> Result<Response<Null>, 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"), |
|||
})?; |
|||
// self.votes.vote(uuid, request.into_inner().id).await;
|
|||
// log::info!("Votes: {:?}", self.votes.get_votes().await);
|
|||
Ok(Response::new(Null {})) |
|||
} |
|||
|
|||
async fn ready(&self, _request: Request<Null>) -> Result<Response<Null>, Status> { |
|||
todo!() |
|||
} |
|||
|
|||
async fn status(&self, _request: Request<Null>) -> Result<Response<LobbyStatus>, Status> { |
|||
todo!() |
|||
} |
|||
|
|||
async fn leave( |
|||
&self, |
|||
request: tonic::Request<Null>, |
|||
) -> Result<tonic::Response<Null>, 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.acquire().await; |
|||
conn.leave_lobby(&uuid).await; |
|||
conn.close().await; |
|||
Ok(Response::new(Null {})) |
|||
} |
|||
|
|||
type usersStream = mpsc::UnboundedReceiver<Result<Name, tonic::Status>>; |
|||
|
|||
async fn users(&self, request: Request<Null>) -> 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.acquire().await; |
|||
for name in conn.get_users_in_lobby_where_user_is(uuid).await { |
|||
sender.send(Ok(Name { name })).unwrap(); |
|||
} |
|||
conn.close().await; |
|||
Ok(Response::new(receiver)) |
|||
} |
|||
} |
|||
@ -0,0 +1,59 @@ |
|||
use tokio::sync::broadcast; |
|||
use uuid::Uuid; |
|||
|
|||
use std::sync::Arc; |
|||
|
|||
use crate::db; |
|||
|
|||
type Message = Vec<(String, u32, bool)>; |
|||
|
|||
pub struct VotingSystem { |
|||
conn: Arc<db::DbPool>, |
|||
// games: Arc<Vec<crate::games::Game>>,
|
|||
broadcast: broadcast::Sender<Message>, |
|||
} |
|||
|
|||
impl VotingSystem { |
|||
pub fn new( |
|||
conn: Arc<db::DbPool>, |
|||
// games: Arc<Vec<crate::games::Game>>,
|
|||
) -> (Self, broadcast::Receiver<Message>) { |
|||
let (tx, rx) = broadcast::channel(1); |
|||
( |
|||
Self { |
|||
conn, |
|||
// games,
|
|||
broadcast: tx, |
|||
}, |
|||
rx, |
|||
) |
|||
} |
|||
|
|||
pub fn subscribe(&self) -> broadcast::Receiver<Message> { |
|||
self.broadcast.subscribe() |
|||
} |
|||
|
|||
pub async fn vote(&self, user: Uuid, game: u32) { |
|||
let mut conn = self.conn.acquire().await; |
|||
if let Some(lobby) = conn.get_lobby_for_user(&user).await { |
|||
conn.vote(user, game).await; |
|||
let status = conn.get_votes(lobby).await; |
|||
self.broadcast.send(status).unwrap(); |
|||
|
|||
} |
|||
conn.close().await; |
|||
|
|||
} |
|||
|
|||
pub async fn ready(&self, user: Uuid) { |
|||
let mut conn = self.conn.acquire().await; |
|||
if let Some(lobby) = conn.get_lobby_for_user(&user).await { |
|||
conn.vote_ready(user).await; |
|||
let status = conn.get_votes(lobby).await; |
|||
self.broadcast.send(status).unwrap(); |
|||
|
|||
} |
|||
|
|||
conn.close().await; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue