From 14c163e415a8ad37d9111e6a5a4a34e3cbe0ad74 Mon Sep 17 00:00:00 2001 From: natrixaeria Date: Sun, 19 May 2019 17:55:04 +0200 Subject: Rename gameserver module to server --- game_server/src/server.rs | 164 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 game_server/src/server.rs (limited to 'game_server/src/server.rs') diff --git a/game_server/src/server.rs b/game_server/src/server.rs new file mode 100644 index 0000000..a4b1ed5 --- /dev/null +++ b/game_server/src/server.rs @@ -0,0 +1,164 @@ +use websocket::{OwnedMessage, + sync::Server, + client::sync::Client, + server::{NoTlsAcceptor, InvalidConnection, + sync::AcceptResult}}; +use std::net::{SocketAddr, ToSocketAddrs, TcpStream}; +use std::sync::{mpsc, + mpsc::{Sender, Receiver}, + Arc, Mutex}; +use std::collections::HashMap; +use super::lobby::Lobby; +use super::backend_connection::BackendConnection; + +const PROTOCOL: &str = "tuesday"; + +pub type Token = u32; + +#[derive(Debug)] +pub enum GameServerError { + BindError(std::io::Error), + HandshakeRequestError, + InvalidProtocolError, + AcceptError(std::io::Error) +} + +pub struct GameServer { + addr: SocketAddr, + lobby: Lobby, + backend: Arc>, + clients: Arc>>, +} + +pub struct GameClient { + addr: SocketAddr, + client: Client, +} + +impl GameClient { + fn from_raw(client: Client) -> Result { + let addr = client.peer_addr().map_err(|_| ())?; + info!("got a client connection from: {}", addr); + Ok(GameClient { + addr, + client, + }) + } + + fn require_token(&mut self) -> Option { + let message = self.client + .recv_message() + .ok()?; + if let OwnedMessage::Text(text) = message { + text.parse().ok() + } else { + None + } + } +} + +type ClientConnection = Result; + +impl GameServer { + pub fn new(addr: T) -> Self { + let addr = addr.to_socket_addrs().unwrap().next().unwrap(); + debug!("ws address: {}", addr); + info!("create lobby"); + let lobby = Lobby::new(); + let backend = BackendConnection::new("https://kobert.dev"); + info!("got a C# backend connection"); + GameServer { + addr, + lobby, + backend: Arc::new(Mutex::new(backend)), + clients: Arc::new(Mutex::new(HashMap::new())), + } + } + + pub fn run(&self) -> Result<(), GameServerError> { + let reader = self.read_clients(); + loop { + let mut connection = reader.recv().unwrap()?; + self.add_client(connection); + } + Ok(()) + } + + fn add_client(&self, mut client: GameClient) { + let clients = Arc::clone(&self.clients); + let backend = Arc::clone(&self.backend); + std::thread::spawn(move || { + let token = client.require_token(); + if let Some(token) = token { + println!("Token: {}", token); + let locked_backend = backend.lock().unwrap(); + let result = locked_backend.validate_token(&token); + if let Err(err) = result { + warn!("token {} is invalid: '{:?}'", token, err); + } else { + clients.lock().unwrap().insert(token, client); + } + } else { + warn!("client sent invalid token"); + } + }); + } + + fn read_clients(&self) -> Receiver { + let (s, r): (Sender, Receiver) + = mpsc::channel(); + let addr = self.addr; + std::thread::spawn(move || { + let result = Self::handle_requests(addr, &s).or_else(|e| s.send(Err(e))); + }); + r + } + + fn handle_requests(addr: SocketAddr, s: &Sender) -> Result<(), GameServerError> { + let server = match Server::::bind(addr) { + Ok(v) => v, + Err(e) => { + error!("websocket binding error"); + Err(GameServerError::BindError(e))? + }, + }; + info!("webserver is being launched"); + for req in server { + s.send(Ok(Self::handle_request(req)?)).unwrap(); + } + info!("webserver is being shut down"); + Ok(()) + } + + fn handle_request(req: AcceptResult) -> ClientConnection { + match req { + Ok(req) => { + if !req.protocols().contains(&PROTOCOL.to_string()) { + warn!("a client tried to connect without {} protocol", PROTOCOL); + req.reject().unwrap(); + Err(GameServerError::InvalidProtocolError) + } else { + match req.use_protocol(PROTOCOL).accept() { + Ok(client) => { + match GameClient::from_raw(client) { + Ok(client) => Ok(client), + Err(_) => { + error!("could not create a client"); + Err(GameServerError::HandshakeRequestError) + } + } + }, + Err((_, e)) => { + warn!("client handshake failed"); + Err(GameServerError::AcceptError(e)) + } + } + } + }, + Err(e) => { + warn!("invalid client request"); + Err(GameServerError::HandshakeRequestError) + } + } + } +} -- cgit v1.2.3-54-g00ecf