Using HashMap

This commit is contained in:
Martin Brodbeck 2023-10-03 21:55:26 +02:00
parent e2b995a788
commit f80f4b6035

View file

@ -1,18 +1,9 @@
use chrono::{DateTime, Local, Duration}; use chrono::{DateTime, Duration, Local};
use std::{ use std::{collections::HashMap, net::UdpSocket};
collections::{HashMap, HashSet},
net::UdpSocket,
};
const MAX_CLIENTS: usize = 10; const MAX_CLIENTS: usize = 10;
const CLIENT_TIMEOUT: u32 = 300; const CLIENT_TIMEOUT: u32 = 300;
const MY_SPEED: u8 = 20; const MY_SPEED: u8 = 30;
#[derive(Hash, Eq, PartialEq, Debug, Clone)]
struct Client {
name: String,
time: DateTime<Local>,
}
fn strip_header(msg: &[u8]) -> Vec<u8> { fn strip_header(msg: &[u8]) -> Vec<u8> {
//print_msg(msg); //print_msg(msg);
@ -111,64 +102,76 @@ fn mopp(speed: u8, data: &[u8]) -> Vec<u8> {
res.to_owned() res.to_owned()
} }
fn broadcast(socket: &UdpSocket, receivers: &HashSet<Client>, client: &Client, data: &[u8]) { fn broadcast(
socket: &UdpSocket,
receivers: &HashMap<String, DateTime<Local>>,
client: &str,
data: &[u8],
) {
for rec in receivers { for rec in receivers {
// Do not broadcast to origin // Do not broadcast to origin
if rec.name == client.name { if rec.0 == client {
continue; continue;
} }
socket.send_to(&data, &rec.name).unwrap(); socket.send_to(&data, &rec.0).unwrap();
} }
} }
fn main() -> std::io::Result<()> { fn main() -> std::io::Result<()> {
let socket = UdpSocket::bind("0.0.0.0:7373")?; let socket = UdpSocket::bind("0.0.0.0:7373")?;
socket socket
.set_read_timeout(None) .set_read_timeout(None)
.expect("Could not set read timeout"); .expect("Could not set read timeout");
let mut receivers: HashSet<Client> = HashSet::new(); let mut receivers2: HashMap<String, DateTime<Local>> = HashMap::new();
loop { loop {
let mut buf = [0; 64]; let mut buf = [0; 64];
let (number_of_bytes, src_addr) = socket.recv_from(&mut buf).expect("Didn't receive data"); let (number_of_bytes, src_addr) = socket.recv_from(&mut buf).expect("Didn't receive data");
let client_addr = src_addr.to_string(); let client_addr = src_addr.to_string();
let client = Client {
name: client_addr.clone(),
time: Local::now(),
};
let speed = buf[1] >> 2; let speed = buf[1] >> 2;
let data = &buf[0..number_of_bytes]; let data = &buf[0..number_of_bytes];
if receivers.iter().any(|x| x.name == client_addr) { if receivers2.contains_key(&client_addr) {
//println!("Client already known."); //println!("Client already known.");
broadcast(&socket, &receivers, &client, data); if strip_header(data) == strip_header(mopp(speed, b":bye").as_slice()) {
println!("TSCHAU");
socket
.send_to(mopp(speed, b":bye").as_slice(), &client_addr)
.unwrap();
receivers2.remove(&client_addr);
} else {
broadcast(&socket, &receivers2, &client_addr, data);
receivers2.insert(client_addr.to_owned(), Local::now());
}
} else if strip_header(data) == strip_header(mopp(speed, b"hi").as_slice()) { } else if strip_header(data) == strip_header(mopp(speed, b"hi").as_slice()) {
//println!("Welcome!"); //println!("Welcome!");
if receivers.len() < MAX_CLIENTS { if receivers2.len() < MAX_CLIENTS {
receivers.insert(client.clone()); receivers2.insert(client_addr.to_owned(), Local::now());
socket socket
.send_to(mopp(MY_SPEED, b"hi").as_slice(), &client.name) .send_to(
mopp(speed, format!("{}{}", ":hi ", receivers2.len()).as_bytes())
.as_slice(),
&client_addr,
)
.unwrap(); .unwrap();
} else { } else {
socket socket
.send_to(mopp(MY_SPEED, b":qrl").as_slice(), &client.name) .send_to(mopp(speed, b":qrl").as_slice(), &client_addr)
.unwrap(); .unwrap();
} }
} else { } else {
//println!("Unknown client - Ignoring"); //println!("Unknown client - Ignoring");
} }
let timestamp = Local::now(); let timestamp = Local::now();
for cl in &receivers { for cl in &receivers2 {
if cl.time + Duration::seconds(CLIENT_TIMEOUT as i64) < timestamp { if *cl.1 + Duration::seconds(CLIENT_TIMEOUT as i64) < timestamp {
socket socket
.send_to(mopp(MY_SPEED, b":bye").as_slice(), &client.name) .send_to(mopp(MY_SPEED, b":bye").as_slice(), &client_addr)
.unwrap(); .unwrap();
} }
} }
receivers.retain(|cl| cl.time + Duration::seconds(CLIENT_TIMEOUT as i64) >= timestamp); receivers2.retain(|_, val| *val + Duration::seconds(CLIENT_TIMEOUT as i64) >= timestamp);
} }
} }