use std::{collections::HashMap, net::SocketAddr, time::Instant}; use super::socket::{Socket, SocketContent, SocketCreateInfo}; use crate::Sender; use anyhow::Result; struct ClientInfo { last_send: Instant, last_received: Instant, } pub struct Server { socket: Socket, clients: HashMap, } impl Server { pub fn new(create_info: SocketCreateInfo) -> Result { Ok(Self { socket: Socket::new(create_info)?, clients: HashMap::new(), }) } pub fn check_heartbeat(&mut self) -> Result<()> { let now = Instant::now(); for (addr, client_info) in self.clients.iter_mut() { if (now - client_info.last_send) > self.socket.heartbeat_interval { client_info.last_send += self.socket.heartbeat_interval; self.socket.send(*addr, "")?; } } Ok(()) } pub fn remove_client(&mut self, addr: impl Into) { let addr = addr.into(); debug_assert!(self.clients.get(&addr).is_some(), "client not found!"); self.clients.remove(&addr); } pub fn send(&self, addr: impl Into, msg: &str) -> Result<()> { let address = addr.into(); #[cfg(debug_assertions)] if self.clients.get(&address).is_none() { println!( "sending message to a not connected client ({}, available {:?})", address, self.clients.keys() ); } self.socket.send(address, msg) } pub fn receive(&mut self) -> Result> { let now = Instant::now(); let mut content = Vec::new(); while let Some((addr, msg)) = match self.socket.receive() { Ok(r) => r, Err(err) => { // if content is empty return the error // if not, ignore the error and break the loop if content.is_empty() { return Err(err); } else { None } } } { match self.clients.get_mut(&addr) { Some(info) => { info.last_received = now; } None => { self.clients.insert( addr, ClientInfo { last_send: now, last_received: now, }, ); content.push(SocketContent::NewConnection(addr)); } } if !msg.is_empty() { content.push(SocketContent::Message(addr, msg)); } } let mut to_remove = Vec::new(); for (addr, info) in self.clients.iter() { if (now - info.last_received) > self.socket.connection_time_out() { content.push(SocketContent::TimeOut(*addr)); to_remove.push(*addr); } } for addr in to_remove.into_iter() { self.remove_client(addr); } Ok(content) } } impl Sender for Server { fn send(&mut self, addr: SocketAddr, msg: &str) -> Result<()> { Server::send(self, addr, msg) } fn is_server(&self) -> bool { true } }