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.
 
 
 
 
 

308 lines
7.8 KiB

// use tonic::transport::Server;
use anyhow::Result;
use log::warn;
use tokio::{
io::{AsyncReadExt, BufReader},
net::TcpListener,
sync::RwLock,
};
use uuid::Uuid;
use std::{collections::HashMap, io::ErrorKind, net::SocketAddr, sync::Arc};
use crate::{
db,
games::RunningGame,
server::{
connection::{
connect, create_lobby, disconnect, get_public_lobbies, join_lobby_with_code, name,
},
game::{get_card_image, on_click, query_status},
lobby::{leave, ready, users, vote},
},
server_properties::ServerProperties,
};
use prost::Message;
use self::{socket_manager::SocketManager, votes::VotingSystem};
mod connection;
mod game;
mod lobby;
mod protos;
mod socket_manager;
mod votes;
// use connection::{ConnectionServer, ConnectionService};
// use game::{GameServer, GameService};
// use lobby::{LobbyServer, LobbyService};
pub async fn start(
pool: db::DbClient,
games: Vec<crate::games::Game>,
properties: crate::server_properties::ServerProperties,
) {
serve(pool, games, properties)
.await
.expect("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
// let connection = ConnectionService {
// conn: RwLock::new(pool.clone().await),
// properties: properties.clone(),
// games: games.clone(),
// voting: voting.clone(),
// running_games: running_games.clone(),
// };
// let lobby = LobbyService::new(
// pool.clone().await,
// voting,
// games.clone(),
// running_games.clone(),
// );
// let game = GameService::new(pool, games, running_games);
// Server::builder()
// .add_service(ConnectionServer::new(connection))
// .add_service(LobbyServer::new(lobby))
// .add_service(GameServer::new(game))
// .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,
// }
// }
pub async fn serve(
mut pool: db::DbClient,
games: Vec<crate::games::Game>,
properties: crate::server_properties::ServerProperties,
) -> Result<(), std::io::Error> {
let properties = Arc::new(properties);
let games = Arc::new(games);
let voting = votes::VotingSystem::new(pool.clone().await);
let running_games: Arc<
RwLock<
HashMap<
u32,
RwLock<(
u32,
RunningGame,
votes::Modifiable<Option<protos::game::GameStatus>>,
)>,
>,
>,
> = Default::default();
let listener = TcpListener::bind(properties.addr.clone()).await?;
let socket_manager = Arc::new(SocketManager::new());
loop {
let (stream, addr) = listener.accept().await?;
let (reader, writer) = stream.into_split();
let mut writer = Some(writer);
let mut reader = BufReader::new(reader);
let mut service_data = ServiceData {
user_id: UserId::new_empty(),
properties: properties.clone(),
games: games.clone(),
running_games: running_games.clone(),
voting: voting.clone(),
addr,
db: pool.clone().await,
};
let socket_manager = socket_manager.clone();
tokio::spawn(async move {
loop {
let length = match reader.read_u32_le().await {
Err(e) => match e.kind() {
ErrorKind::UnexpectedEof => {
if let Some(user) = service_data.user_id.0 {
warn!(
"Unexpected EOF for {} from {}, disconnecting",
user, service_data.addr
);
} else {
warn!("Unexpected EOF from {}, disconnecting", service_data.addr);
}
break;
}
_ => Err(e),
},
x => x,
}
.expect("Unexpected inability to read the length of a packet (U32 LE)");
let mut data = vec![0; length as usize];
match reader.read_exact(&mut data).await {
Err(e) => match e.kind() {
ErrorKind::UnexpectedEof => {
if let Some(user) = service_data.user_id.0 {
warn!(
"Unexpected EOF for {} from {}, disconnecting",
user, service_data.addr
);
} else {
warn!("Unexpected EOF from {}, disconnecting", service_data.addr);
}
break;
}
_ => Err(e),
},
x => x,
}
.expect("Error reading packet");
let packet = match protos::protocol::ClientServerPacket::decode(data.as_slice()) {
Err(e) => {
warn!("Error decoding the packet, skipping ({})", e);
continue;
}
Ok(d) => d,
};
let packet = match packet.data {
Some(packet) => packet,
None => {
warn!("Unexpected data in packet ({:?}), skipping", packet);
continue;
}
};
use protos::protocol::client_server_packet::Data;
match packet {
// CONNECTION
Data::QueryName(()) => name(&mut service_data, &socket_manager)
.await
.expect("Error handling name query"),
Data::Connect(name) => connect(
&mut service_data,
writer
.take()
.ok_or(anyhow::anyhow!(
"Connect shouldn't be called more than once"
))
.unwrap(),
&socket_manager,
name,
)
.await
.expect("Error handling connect"),
Data::Disconnect(()) => {
break;
}
Data::JoinLobby(code) => join_lobby_with_code(&mut service_data, code)
.await
.expect("Error handling join with code"),
Data::CreateLobby(config) => {
create_lobby(&mut service_data, &socket_manager, config)
.await
.expect("Error handling create lobby")
}
Data::QueryGames(()) => connection::games(&mut service_data, &socket_manager)
.await
.expect("Error handling games query"),
Data::QueryPublicLobbies(()) => {
get_public_lobbies(&mut service_data, &socket_manager)
.await
.expect("Error handling public lobbies query")
}
// LOBBY
Data::QueryUsers(()) => users(&mut service_data, &socket_manager)
.await
.expect("Error handling users query"),
Data::Vote(v) => vote(&mut service_data, &socket_manager, v)
.await
.expect("Error handling vote"),
Data::Ready(()) => ready(&mut service_data, &socket_manager)
.await
.expect("Error handling ready"),
Data::Leave(()) => leave(&mut service_data, &socket_manager)
.await
.expect("Error handling leave"),
// GAME
Data::QueryCardImage(card_kind) => {
get_card_image(&mut service_data, &socket_manager, card_kind)
.await
.expect("Error handling card image query")
}
Data::CallOnClick(card_id) => {
on_click(&mut service_data, &socket_manager, card_id)
.await
.expect("Error handling on_click call")
}
Data::QueryGameStatus(()) => query_status(&mut service_data, &socket_manager)
.await
.expect("Error handling game_status query"),
}
}
if let Some(user) = service_data.user_id.0 {
disconnect(&mut service_data)
.await
.expect("Error handling disconnect");
socket_manager.disconnect(&user).await;
}
});
}
}
struct ServiceData {
user_id: UserId,
properties: Arc<ServerProperties>,
games: Arc<Vec<crate::games::Game>>,
voting: VotingSystem,
running_games: Arc<
RwLock<
HashMap<
u32,
RwLock<(
u32,
RunningGame,
votes::Modifiable<Option<protos::game::GameStatus>>,
)>,
>,
>,
>,
addr: SocketAddr,
db: db::DbClient,
}
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
struct UserId(Option<uuid::Uuid>);
impl UserId {
pub fn new_empty() -> Self {
Self(None)
}
// pub fn new_filled(uuid: Uuid) -> Self {
// Self(Some(uuid))
// }
pub fn set(&mut self, uuid: Uuid) {
self.0 = Some(uuid);
}
pub fn get(self) -> Result<Uuid> {
self.0.ok_or(anyhow::anyhow!("User should have connected"))
}
pub fn get_ref(&self) -> Result<&Uuid> {
self.0
.as_ref()
.ok_or(anyhow::anyhow!("User should have connected"))
}
}