diff --git a/src/client.rs b/src/client.rs new file mode 100644 index 0000000..e0a9e0a --- /dev/null +++ b/src/client.rs @@ -0,0 +1,98 @@ +use std::sync::Arc; + +use tokio::sync::Mutex; +use futures::{ + select, + FutureExt, +}; + + +use hexland_server::{ + GlobalState, + Channel, + channel_pair, + GameController, + message::{Message, MessageWebSocket}, + msg, +}; + + +pub struct Client { + global_state: Arc, + ws: MessageWebSocket, + channel: Option, +} + +impl Client { + pub fn new(ws: MessageWebSocket, global_state: Arc) -> Self { + Client { + global_state, + ws, + channel: None + } + } + pub async fn run(&mut self) { + loop { + match &mut self.channel { + Some(channel) => { + select! { + msg = channel.rx.recv().fuse() => + self.handle_server_msg(msg.unwrap()).await, + msg = self.ws.next().fuse() => + self.handle_client_msg(msg.unwrap()).await, + }; + } + None => { + let msg = self.ws.next().await; + self.handle_client_msg(msg.unwrap()).await; + } + } + } + } + async fn handle_client_msg(&mut self, msg: Message) { + match msg.command.as_str() { + "HOST" => { + let room_code = self.global_state.code_generator.lock().await.generate(); + let mut game_controller = GameController::default(); + + let (client_channel, server_channel) = channel_pair(); + self.channel = Some(client_channel); + game_controller.channels.push(server_channel); + + let game_controller = Arc::new(Mutex::new(game_controller)); + self.global_state.rooms.lock().await.insert(room_code.clone(), Arc::clone(&game_controller)); + tokio::spawn(async move {game_loop(game_controller)}); + self.ws.send(msg!("ROOM_CODE", room_code)).await.unwrap(); + } + "JOIN" => { + let room_code = &msg.args[0]; + let rooms = self.global_state.rooms.lock().await; + let room = rooms.get(room_code); + + match room { + Some(room) => { + let mut room = room.lock().await; + let (client_channel, server_channel) = channel_pair(); + self.channel = Some(client_channel); + room.channels.push(server_channel); + self.ws.send(msg!("JOIN_OK")).await.unwrap(); + } + None => { + self.ws.send(msg!("JOIN_INVALID")).await.unwrap(); + } + } + } + _ => if let Some(channel) = &self.channel { + // Forward message to the server + channel.tx.send(msg).await.unwrap(); + } + } + } + async fn handle_server_msg(&mut self, _msg: Message) { + todo!(); + } +} + +fn game_loop(_gc: Arc>) { + todo!(); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..1a853b4 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,36 @@ +use std::{ + collections::HashMap, + sync::Arc, +}; + +use tokio::sync::{Mutex, mpsc}; + +pub mod message; +use message::{Message}; +mod code_generator; +use code_generator::CodeGenerator; + +#[derive(Default)] +pub struct GlobalState { + pub code_generator: Arc>, + pub rooms: Arc>>>>, +} + +pub struct Channel { + pub tx: mpsc::Sender, + pub rx: mpsc::Receiver, +} + +pub fn channel_pair() -> (Channel, Channel) { + let (atx, brx) = mpsc::channel(32); + let (btx, arx) = mpsc::channel(32); + ( + Channel { tx: atx, rx: arx }, + Channel { tx: btx, rx: brx }, + ) +} + +#[derive(Default)] +pub struct GameController { + pub channels: Vec, +} diff --git a/src/main.rs b/src/main.rs index c235a3e..ec71bd7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,17 @@ use std::{ sync::Arc, io::Error as IoError, - collections::HashMap, }; use tokio::{ net::{TcpListener}, - sync::{mpsc, Mutex}, }; -use futures::{ - select, - FutureExt, -}; +use hexland_server::GlobalState; +use hexland_server::message::MessageWebSocket; -mod message; -use message::{Message, MessageWebSocket}; -mod code_generator; -use code_generator::CodeGenerator; +mod client; +use client::Client; #[tokio::main] async fn main() -> Result<(), IoError> { @@ -31,118 +25,14 @@ async fn main() -> Result<(), IoError> { // Accept all incoming connections while let Ok((stream, addr)) = listener.accept().await { let global_state = Arc::clone(&global_state); - let mut local_state = LocalState::default(); tokio::spawn(async move { // Upgrade to a WS connection - let mut ws = MessageWebSocket(tokio_tungstenite::accept_async(stream) + let ws = MessageWebSocket(tokio_tungstenite::accept_async(stream) .await .expect("Could not establish connection")); println!("Connected to {}", addr); - - loop { - match &mut local_state.channel { - Some(channel) => { - select! { - msg = channel.rx.recv().fuse() => - handle_server_msg(msg.unwrap(), &mut local_state, &mut ws).await, - msg = ws.next().fuse() => - handle_client_msg(msg.unwrap(), &global_state, &mut local_state, &mut ws).await, - }; - } - None => { - let msg = ws.next().await; - handle_client_msg(msg.unwrap(), &global_state, &mut local_state, &mut ws).await; - } - } - } + Client::new(ws, global_state).run().await; }); } Ok(()) } - -async fn handle_client_msg( - msg: Message, - global_state: &GlobalState, - local_state: &mut LocalState, - ws: &mut MessageWebSocket -) { - match msg.command.as_str() { - "HOST" => { - let room_code = global_state.code_generator.lock().await.generate(); - let mut game_controller = GameController::default(); - - let [client_channel, server_channel] = channel_pair(); - local_state.channel = Some(client_channel); - game_controller.channels.push(server_channel); - - let game_controller = Arc::new(Mutex::new(game_controller)); - global_state.rooms.lock().await.insert(room_code.clone(), Arc::clone(&game_controller)); - tokio::spawn(async move {game_loop(game_controller)}); - ws.send(msg!("ROOM_CODE", room_code)).await.unwrap(); - } - "JOIN" => { - let room_code = &msg.args[0]; - let rooms = global_state.rooms.lock().await; - let room = rooms.get(room_code); - - match room { - Some(room) => { - let mut room = room.lock().await; - let [client_channel, server_channel] = channel_pair(); - local_state.channel = Some(client_channel); - room.channels.push(server_channel); - ws.send(msg!("JOIN_OK")).await.unwrap(); - } - None => { - ws.send(msg!("JOIN_INVALID")).await.unwrap(); - } - } - } - _ => if let Some(channel) = &local_state.channel { - // Forward message to the server - channel.tx.send(msg).await; - } - } -} - -async fn handle_server_msg( - msg: Message, - local_state: &mut LocalState, - ws: &mut MessageWebSocket -) { - todo!(); -} - -fn game_loop(game_controller: Arc>) { - todo!(); -} - -#[derive(Default)] -struct GlobalState { - code_generator: Arc>, - rooms: Arc>>>>, -} - -#[derive(Default)] -struct GameController { - channels: Vec, -} - -#[derive(Default)] -struct LocalState { - channel: Option, -} - -struct Channel { - tx: mpsc::Sender, - rx: mpsc::Receiver, -} - -fn channel_pair() -> [Channel; 2] { - let (atx, brx) = mpsc::channel(32); - let (btx, arx) = mpsc::channel(32); - [ - Channel { tx: atx, rx: arx }, - Channel { tx: btx, rx: brx }, - ] -}