This commit is contained in:
2025-07-15 17:05:04 +02:00
commit d72254c7d0
25 changed files with 2074 additions and 0 deletions

162
src/domain/client.rs Normal file
View File

@@ -0,0 +1,162 @@
//! 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<DashMap<SocketAddr, Client>>,
}
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<H: Hasher>(&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<dashmap::mapref::one::Ref<SocketAddr, Client>> {
self.clients.get(&address)
}
/// Récupère toutes les adresses des clients connectés
pub fn get_all_adresses(&self) -> Vec<SocketAddr> {
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<F>(&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
}
}
}