diff --git a/Cargo.lock b/Cargo.lock index 712e0e5..035b2eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -902,6 +902,7 @@ dependencies = [ "env_logger", "futures-util", "log", + "rand", "serde 1.0.116", "serde_derive", "shipyard", diff --git a/Cargo.toml b/Cargo.toml index dcb8ee2..fcca469 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,15 +5,16 @@ authors = ["Hamcha "] edition = "2018" [dependencies] -tungstenite = "0.11" -shipyard = { version = "0.4", features = ["parallel", "serde"] } +actix = "0.10" config = "0.10" -serde = { version = "1", features = ["derive"] } -serde_derive = "1" -tokio = { version = "0.2", features = ["full"] } -tokio-tungstenite = "0.11" +env_logger = "0.7" futures-util = { version = "0.3", default-features = false, features = ["async-await", "sink", "std"] } log = { version = "0.4", features = ["std", "serde"] } -ultraviolet = { version = "0.7", features = [ "f64", "int", "serde" ] } -env_logger = "0.7" -actix = "0.10" \ No newline at end of file +rand = "0.7" +serde = { version = "1", features = ["derive"] } +serde_derive = "1" +shipyard = { version = "0.4", features = ["parallel", "serde"] } +tokio = { version = "0.2", features = ["full"] } +tokio-tungstenite = "0.11" +tungstenite = "0.11" +ultraviolet = { version = "0.7", features = [ "f64", "int", "serde" ] } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8f30264..e90eaf6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,14 @@ mod components; mod config; +mod network; mod systems; use crate::config::Settings; +use crate::network::{listen_websocket, NetworkManager}; use actix::prelude::*; use env_logger::Env; -use log::info; use shipyard::World; use std::time::Duration; -use tokio::net::{TcpListener, TcpStream}; -use tokio_tungstenite::WebSocketStream; // Minimum delay between updates, in milliseconds const MIN_UPDATE_MS: u64 = 10; @@ -29,24 +28,6 @@ impl Actor for Game { } } -struct NetworkConnection { - stream: WebSocketStream, -} - -impl Actor for NetworkConnection { - type Context = Context; - - fn started(&mut self, _ctx: &mut Self::Context) { - //TODO Read - } -} - -struct NetworkManager {} - -impl Actor for NetworkManager { - type Context = Context; -} - fn main() { let env = Env::default().filter_or("LOG_LEVEL", "info"); env_logger::init_from_env(env); @@ -54,6 +35,7 @@ fn main() { let settings = Settings::new().unwrap(); let system = System::new("main"); + Game::create(|_ctx| { // Create world let world = World::default(); @@ -64,27 +46,7 @@ fn main() { Game { world } }); - Arbiter::spawn(listen_websocket(settings.bind)); + NetworkManager::new(settings.bind).start(); system.run().unwrap(); } - -async fn listen_websocket(bind: String) { - let try_socket = TcpListener::bind(&bind).await; - let mut listener = try_socket.expect("Failed to bind"); - info!("Listening on: {}", bind); - - while let Ok((stream, _)) = listener.accept().await { - let addr = stream - .peer_addr() - .expect("connected streams should have a peer address"); - info!("Peer address: {}", addr); - - let stream = tokio_tungstenite::accept_async(stream) - .await - .expect("Error during the websocket handshake occurred"); - info!("New WebSocket connection: {}", addr); - - NetworkConnection::create(|_ctx| NetworkConnection { stream }); - } -} diff --git a/src/network.rs b/src/network.rs new file mode 100644 index 0000000..3064859 --- /dev/null +++ b/src/network.rs @@ -0,0 +1,94 @@ +use actix::prelude::*; +use log::info; +use rand::prelude::*; +use std::collections::HashMap; +use tokio::net::{TcpListener, TcpStream}; +use tokio_tungstenite::WebSocketStream; + +pub struct NetworkConnection { + conn_id: u64, + connected: bool, + stream: WebSocketStream, + manager: Addr, +} + +impl Actor for NetworkConnection { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + // Send manager my info and get a connection ID assigned + let addr = ctx.address(); + self.manager + .send(ClientConnected { addr }) + .into_actor(self) + .then(move |res, act, _| { + act.conn_id = res.unwrap(); + act.connected = true; + async {}.into_actor(act) + }) + .wait(ctx); + //TODO Start recv/send loop + } +} + +#[derive(Message)] +#[rtype(result = "u64")] +struct ClientConnected { + addr: Addr, +} + +pub struct NetworkManager { + bind: String, + clients: HashMap>, +} + +impl Actor for NetworkManager { + type Context = Context; + + fn started(&mut self, ctx: &mut Self::Context) { + Arbiter::spawn(listen_websocket(self.bind.clone(), ctx.address())); + } +} + +impl Handler for NetworkManager { + type Result = u64; + fn handle(&mut self, msg: ClientConnected, _ctx: &mut Self::Context) -> Self::Result { + let client_id = rand::thread_rng().gen(); + self.clients.insert(client_id, msg.addr); + client_id + } +} + +impl NetworkManager { + pub fn new(bind: String) -> Self { + NetworkManager { + bind, + clients: HashMap::new(), + } + } +} + +pub async fn listen_websocket(bind: String, manager: Addr) { + let try_socket = TcpListener::bind(&bind).await; + let mut listener = try_socket.expect("Failed to bind"); + info!("Listening on: {}", bind); + + while let Ok((stream, _)) = listener.accept().await { + let addr = stream + .peer_addr() + .expect("connected streams should have a peer address"); + info!("Peer address: {}", addr); + + let stream = tokio_tungstenite::accept_async(stream) + .await + .expect("Error during the websocket handshake occurred"); + info!("New WebSocket connection: {}", addr); + + NetworkConnection::create(|_ctx| NetworkConnection { + conn_id: 0, + connected: false, + stream, + manager: manager.clone(), + }); + } +}