engine/networking/src/server.rs
2025-03-01 06:43:44 +01:00

127 lines
3.3 KiB
Rust

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<SocketAddr, ClientInfo>,
}
impl Server {
pub fn new(create_info: SocketCreateInfo) -> Result<Self> {
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<SocketAddr>) {
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<SocketAddr>, 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<Vec<SocketContent>> {
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
}
}