use websocket::{OwnedMessage, sync::Server, client::sync::Client, server::{NoTlsAcceptor, InvalidConnection, sync::AcceptResult}}; use std::net::{SocketAddr, ToSocketAddrs, TcpStream}; use std::sync::mpsc; use std::sync::mpsc::{Sender, Receiver}; use super::lobby::Lobby; use super::backend_connection::BackendConnection; const PROTOCOL: &str = "tuesday"; 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: BackendConnection, } 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, } } 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) { std::thread::spawn(move || { println!("Token: {:?}", client.require_token()); loop { std::thread::sleep(std::time::Duration::from_millis(100)); } }); } 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) } } } }