//! Gestion des clients pour les connexions UDP //! //! Ce module fournit les structures et méthodes pour gérer les clients //! connectés au serveur UDP, incluant leur tracking et leurs modifications. use std::net::SocketAddr; use std::sync::Arc; use dashmap::DashMap; use tokio::time::Instant; use uuid::Uuid; use std::hash::{Hash, Hasher}; use std::time::Duration; /// Représente un client connecté au serveur UDP /// /// Chaque client est identifié par un UUID unique et contient /// son adresse réseau ainsi que l'heure de sa dernière activité. #[derive(Debug)] pub struct Client { id: Uuid, address: SocketAddr, last_seen: Instant, } /// Gestionnaire threadsafe pour les clients connectés /// /// Utilise `DashMap` pour permettre un accès concurrent sécurisé /// aux clients depuis plusieurs threads. #[derive(Clone)] pub struct ClientManager { clients: Arc>, } impl Client { /// Crée un nouveau client avec un UUID généré automatiquement pub fn new(address: SocketAddr) -> Self { let id = Uuid::new_v4(); Self { id, address, last_seen: Instant::now(), } } /// Retourne le UUID unique du client pub fn id(&self) -> Uuid { self.id } /// Retourne l'adresse socket du client pub fn address(&self) -> SocketAddr { self.address } /// Retourne l'instant de la dernière activité du client pub fn last_seen(&self) -> Instant { self.last_seen } /// Met à jour l'heure de dernière activité du client à maintenant pub fn update_last_seen(&mut self) { self.last_seen = Instant::now(); } } impl Hash for Client { fn hash(&self, state: &mut H) { self.id.hash(state); } } impl PartialEq for Client { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl Eq for Client {} impl ClientManager { /// Crée un nouveau gestionnaire de clients vide pub fn new() -> Self { Self { clients: Arc::new(DashMap::new()), } } /// Ajoute un client au gestionnaire pub fn add(&self, client: Client) { self.clients.insert(client.address(), client); } /// Supprime un client du gestionnaire pub fn remove(&self, client: Client) { self.clients.remove(&client.address()); } /// Vérifie si un client existe pour une adresse donnée pub fn client_exists(&self, address: SocketAddr) -> bool { self.clients.contains_key(&address) } /// Récupère une référence vers un client par son adresse pub fn get_client_by_address(&self, address: SocketAddr) -> Option> { self.clients.get(&address) } /// Récupère toutes les adresses des clients connectés pub fn get_all_adresses(&self) -> Vec { self.clients.iter().map(|entry| *entry.key()).collect() } /// Met à jour l'heure de dernière activité d'un client pub fn update_client_last_seen(&self, address: SocketAddr) { if let Some(mut client) = self.clients.get_mut(&address) { client.update_last_seen(); } } /// Supprimer les clients trop vieux pub fn cleanup(&self, max_age: Duration) { let now = Instant::now(); self.clients.retain(|_, client| now - client.last_seen() < max_age); } /// Modifie un client via une closure /// /// # Arguments /// * `address` - L'adresse du client à modifier /// * `f` - La closure qui recevra une référence mutable vers le client /// /// # Returns /// `true` si le client a été trouvé et modifié, `false` sinon /// /// # Examples /// ```ignore /// let client_manager = ClientManager::new(); /// let addr = "127.0.0.1:8080".parse().unwrap(); /// /// // Mise à jour simple /// client_manager.modify_client(addr, |client| { /// client.update_last_seen(); /// }); /// /// // Modifications multiples /// let success = client_manager.modify_client(addr, |client| { /// client.update_last_seen(); /// // autres modifications... /// }); /// ``` pub fn modify_client(&self, address: SocketAddr, f: F) -> bool where F: FnOnce(&mut Client), { if let Some(mut client) = self.clients.get_mut(&address) { f(&mut *client); true } else { false } } }