diff --git a/kubi-udp/Cargo.toml b/kubi-udp/Cargo.toml index f99b6ad..86da226 100644 --- a/kubi-udp/Cargo.toml +++ b/kubi-udp/Cargo.toml @@ -8,5 +8,6 @@ edition = "2021" [dependencies] bincode = "2.0.0-rc" anyhow = "1.0" +hashbrown = "0.13" nohash-hasher = "0.2.0" log = "0.4" diff --git a/kubi-udp/src/client.rs b/kubi-udp/src/client.rs index 8707e18..731dab0 100644 --- a/kubi-udp/src/client.rs +++ b/kubi-udp/src/client.rs @@ -3,6 +3,7 @@ use std::{ net::{UdpSocket, SocketAddr}, time::{Instant, Duration}, marker::PhantomData, + collections::{VecDeque, vec_deque::Drain}, }; use bincode::{Encode, Decode}; use crate::{ @@ -24,6 +25,12 @@ pub struct ClientConfig { pub heartbeat_interval: Duration, } +pub enum ClientEvent where T: Encode + Decode { + Connected, + Disconnected(DisconnectReason), + MessageReceived(T) +} + pub struct Client where S: Encode + Decode, R: Encode + Decode { pub config: ClientConfig, addr: SocketAddr, @@ -33,8 +40,8 @@ pub struct Client where S: Encode + Decode, R: Encode + Decode { last_heartbeat: Instant, client_id: Option, disconnect_reason: DisconnectReason, + event_queue: VecDeque>, _s: PhantomData<*const S>, - _r: PhantomData<*const R>, } impl Client where S: Encode + Decode, R: Encode + Decode { pub fn new(addr: SocketAddr, config: ClientConfig) -> Result { @@ -50,8 +57,8 @@ impl Client where S: Encode + Decode, R: Encode + Decode { last_heartbeat: Instant::now(), client_id: None, disconnect_reason: DisconnectReason::default(), + event_queue: VecDeque::new(), _s: PhantomData, - _r: PhantomData, }) } @@ -69,6 +76,7 @@ impl Client where S: Encode + Decode, R: Encode + Decode { self.client_id = None; self.status = ClientStatus::Disconnected; self.disconnect_reason = reason; + self.event_queue.push_back(ClientEvent::Disconnected(self.disconnect_reason.clone())); Ok(()) } @@ -105,7 +113,7 @@ impl Client where S: Encode + Decode, R: Encode + Decode { Ok(()) } - pub fn update(&mut self, callback: fn(R) -> Result<()>) -> Result<()> { + pub fn update(&mut self) -> Result<()> { // , callback: fn(ClientEvent) -> Result<()> if self.status == ClientStatus::Disconnected { return Ok(()) } @@ -137,6 +145,7 @@ impl Client where S: Encode + Decode, R: Encode + Decode { ServerPacket::Connected(client_id) => { self.client_id = Some(client_id); self.status = ClientStatus::Connected; + self.event_queue.push_back(ClientEvent::Connected); return Ok(()) }, ServerPacket::Disconnected(reason) => { @@ -146,7 +155,7 @@ impl Client where S: Encode + Decode, R: Encode + Decode { return Ok(()) }, ServerPacket::Data(message) => { - callback(message)?; + self.event_queue.push_back(ClientEvent::MessageReceived(message)); } } } else { @@ -156,4 +165,11 @@ impl Client where S: Encode + Decode, R: Encode + Decode { } Ok(()) } + + pub fn get_event(&mut self) -> Option> { + self.event_queue.pop_front() + } + pub fn process_events(&mut self) -> Drain> { + self.event_queue.drain(..) + } } diff --git a/kubi-udp/src/common.rs b/kubi-udp/src/common.rs index 83a40ef..26c56f8 100644 --- a/kubi-udp/src/common.rs +++ b/kubi-udp/src/common.rs @@ -2,8 +2,9 @@ use std::num::NonZeroU8; use bincode::{Encode, Decode}; pub type ClientId = NonZeroU8; +pub const MAX_CLIENTS: usize = u8::MAX as _; -#[derive(Default, Encode, Decode)] +#[derive(Default, Encode, Decode, Clone)] #[repr(u8)] pub enum DisconnectReason { #[default] diff --git a/kubi-udp/src/lib.rs b/kubi-udp/src/lib.rs index b906e02..e4b9002 100644 --- a/kubi-udp/src/lib.rs +++ b/kubi-udp/src/lib.rs @@ -2,6 +2,7 @@ pub mod client; pub mod server; pub(crate) mod packet; pub(crate) mod common; +pub use common::{ClientId, DisconnectReason}; //pub(crate) trait Serializable: bincode::Encode + bincode::Decode {} pub(crate) const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard() diff --git a/kubi-udp/src/server.rs b/kubi-udp/src/server.rs index 9935fc3..ff91845 100644 --- a/kubi-udp/src/server.rs +++ b/kubi-udp/src/server.rs @@ -1,14 +1,26 @@ -use std::net::{UdpSocket, SocketAddr}; -use crate::BINCODE_CONFIG; +use std::{net::{UdpSocket, SocketAddr}, time::Instant}; +use hashbrown::HashMap; +use nohash_hasher::BuildNoHashHasher; +use crate::{BINCODE_CONFIG, common::{ClientId, MAX_CLIENTS}}; + +pub struct ConnectedClient { + id: ClientId, + addr: SocketAddr, + timeout: Instant, +} pub struct Server { socket: UdpSocket, + clients: HashMap> } impl Server { pub fn bind(addr: SocketAddr) -> anyhow::Result { let socket = UdpSocket::bind(addr)?; socket.set_nonblocking(true)?; socket.set_broadcast(true)?; - Ok(Self { socket }) + Ok(Self { + socket, + clients: HashMap::with_capacity_and_hasher(MAX_CLIENTS, BuildNoHashHasher::default()) + }) } }