128 lines
3.3 KiB
Rust
128 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
|
||
|
}
|
||
|
}
|