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.
 
 
 
 
 

156 lines
4.9 KiB

use tonic::{transport::Server, Request, Response, Status};
use log::info;
use std::sync::Arc;
mod game;
use game::connection_server::{Connection, ConnectionServer};
use game::lobby_server::{Lobby, LobbyServer};
use game::{LobbyCode, Null, UserId, Name, CardId, Image};
use crate::db;
pub struct ConnectionService {
conn: Arc<db::DbPool>,
properties: Arc<crate::server_properties::ServerProperties>
}
#[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 join_lobby_without_code(
&self,
request: Request<Null>,
) -> 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().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() }))
}
}
use tokio::sync::mpsc;
pub struct LobbyService {
conn: Arc<db::DbPool>,
games: Arc<Vec<crate::games::Game>>,
}
#[tonic::async_trait]
impl Lobby for LobbyService {
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 u64, name: game.name.clone(), version: game.version.clone(), authors: game.authors.clone()})).unwrap();
}
Ok(Response::new(receiver))
}
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!()
}
}
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 connection = ConnectionService { conn: arc.clone(), properties };
let lobby = LobbyService {conn: arc.clone(), games: Arc::new(games)};
Server::builder()
.add_service(ConnectionServer::new(connection))
.add_service(LobbyServer::new(lobby))
.serve("0.0.0.0:50052".parse().unwrap())
.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,
}
}