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