// use tonic::transport::Server; use anyhow::Result; use log::{debug, 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; // pub fn decode(bytes: &[u8]) { // let p = protos::protocol::ServerClientPacket::decode(bytes).expect("AAAAH"); // match p.data.unwrap() { // protos::protocol::server_client_packet::Data::ReturnName(_) => log::info!("ReturnName"), // protos::protocol::server_client_packet::Data::ReturnConnect(_) => log::info!("ReturnConnect"), // protos::protocol::server_client_packet::Data::ReturnCreateLobby(_) => log::info!("ReturnCreateLobby"), // protos::protocol::server_client_packet::Data::ReturnGames(_) => log::info!("ReturnGames"), // protos::protocol::server_client_packet::Data::ReturnPublicLobbies(_) => log::info!("ReturnPublicLobbies"), // protos::protocol::server_client_packet::Data::ReturnUsers(_) => log::info!("ReturnUsers"), // protos::protocol::server_client_packet::Data::LobbyStatus(_) => log::info!("LobbyStatus"), // protos::protocol::server_client_packet::Data::ReturnCardImage(_) => log::info!("ReturnCardImage"), // protos::protocol::server_client_packet::Data::GameStatus(_) => log::info!("GameStatus"), // } // } // use connection::{ConnectionServer, ConnectionService}; // use game::{GameServer, GameService}; // use lobby::{LobbyServer, LobbyService}; pub async fn start( pool: db::DbClient, games: Vec, 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 { // 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, 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>, )>, >, >, > = 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) => { debug!("{:?}", 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, games: Arc>, voting: VotingSystem, running_games: Arc< RwLock< HashMap< u32, RwLock<( u32, RunningGame, votes::Modifiable>, )>, >, >, >, addr: SocketAddr, db: db::DbClient, } #[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] struct UserId(Option); 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 { 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")) } }