use crate::domain::events::channel::{ChannelCreatedEvent, ChannelDeletedEvent}; use crate::domain::events::channel_permission::{ ChannelRolePermissionUpdatedEvent, ChannelUserPermissionCreatedEvent, ChannelUserPermissionDeletedEvent, ChannelUserPermissionUpdatedEvent, }; use crate::domain::events::role::{RoleUserCreatedEvent, RoleUserDeletedEvent}; use crate::domain::events::server::{ ServerCreatedEvent, ServerUserCreatedEvent, ServerUserDeletedEvent, }; use crate::domain::events::server_permission::{ ServerRolePermissionUpdatedEvent, ServerUserPermissionUpdatedEvent, }; use crate::domain::events::server_tree::ServerTreeInvalidatedEvent; use crate::repositories::Repositories; use crate::services::ServicesContext; use event_bus::EventBus; use std::sync::Arc; use uuid::Uuid; // list of all events : // server_user_created // server_user_deleted // // role_user_created // role_user_deleted // // server_role_permission_created // server_role_permission_updated // server_role_permission_deleted // // server_user_permission_created // server_user_permission_updated // server_user_permission_deleted // // channel_role_permission_created // channel_role_permission_updated // channel_role_permission_deleted // // channel_user_permission_created // channel_user_permission_updated // channel_user_permission_deleted // // channel_created // channel_deleted // [Requête HTTP Admin] // │ // ▼ // 1. Repositories (Ecriture BDD) // │ // ▼ (Emit Event ex: server_role_permission_updated) // 2. EventBus // │ // ├────────────────────────────────────────┐ // ▼ ▼ // 3. PermissionSyncService (Async Task) [Réponse HTTP 200/204] // │ // ├─► Recalcule computed_permission (full_sync_user) // │ // └─► Emit Event "user_permissions_updated" // │ // ▼ // 4. Gateway WebSocket // │ // ▼ (Push WS) // 5. Client Frontend (Vue 3 / Pinia) #[derive(Debug, Clone)] pub struct PermissionSyncService { service_context: Arc, } impl PermissionSyncService { fn invalidate_tree(event_bus: &Arc, server_id: Uuid, user_ids: Option>) { event_bus.emit(ServerTreeInvalidatedEvent { server_id, user_ids, }); } pub fn new(service_context: Arc) -> Self { Self { service_context } } /// Enregistre les listeners sur l'EventBus pour mettre à jour le cache /// des permissions calculées lors des modifications de structure ou de droits. pub async fn start_listen_event(&self) { let repositories = self.service_context.repositories.clone(); let event_bus = self.service_context.event_bus.clone(); // --------------------------------------------------------------------- // Événements Serveur & Membres Serveur // --------------------------------------------------------------------- let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| async move { Self::sync_server(repositories, event.server.id).await; }, ); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let server_id = event.server_user.server_id; let user_id = event.server_user.user_id; let notify = notify.clone(); async move { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let server_id = event.server_user.server_id; let user_id = event.server_user.user_id; let notify = notify.clone(); async move { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } }, ); // --------------------------------------------------------------------- // Événements Rôles & Membres de Rôle // --------------------------------------------------------------------- let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let server_id = event.server_id; let user_id = event.role_user.user_id; let notify = notify.clone(); async move { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let server_id = event.server_id; let user_id = event.role_user.user_id; let notify = notify.clone(); async move { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } }, ); // --------------------------------------------------------------------- // Overrides de Permissions Serveur // --------------------------------------------------------------------- let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let role_id = event.role_id; let server_id = event.server_id; let notify = notify.clone(); async move { Self::sync_role_members(repositories, role_id, server_id).await; Self::invalidate_tree(¬ify, server_id, None); } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let server_id = event.server_id; let user_id = event.user_id; let notify = notify.clone(); async move { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } }, ); // --------------------------------------------------------------------- // Événements Canaux & Overrides de Permissions Canaux // --------------------------------------------------------------------- let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let notify = notify.clone(); async move { if let Some(server_id) = event.channel.server_id { Self::sync_server(repositories, server_id).await; Self::invalidate_tree(¬ify, server_id, None); } } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let notify = notify.clone(); async move { if let Some(server_id) = event.channel.server_id { Self::sync_server(repositories, server_id).await; Self::invalidate_tree(¬ify, server_id, None); } } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let role_id = event.role_id; let server_id = event.server_id; let notify = notify.clone(); async move { Self::sync_role_members(repositories, role_id, server_id).await; Self::invalidate_tree(¬ify, server_id, None); } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let user_id = event.user_id; let notify = notify.clone(); async move { if let Some(channel) = repositories .channel .get_by_id(event.channel_id) .await .ok() .flatten() { if let Some(server_id) = channel.server_id { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } } } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories.clone(), move |repositories, event| { let channel_id = event.permission.channel_id; let user_id = event.permission.user_id; let notify = notify.clone(); async move { if let Some(channel) = repositories .channel .get_by_id(channel_id) .await .ok() .flatten() { if let Some(server_id) = channel.server_id { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } } } }, ); let notify = event_bus.clone(); event_bus.on_async_with::( repositories, move |repositories, event| { let channel_id = event.permission.channel_id; let user_id = event.permission.user_id; let notify = notify.clone(); async move { if let Some(channel) = repositories .channel .get_by_id(channel_id) .await .ok() .flatten() { if let Some(server_id) = channel.server_id { Self::sync_user(repositories, user_id, server_id).await; Self::invalidate_tree(¬ify, server_id, Some(vec![user_id])); } } } }, ); } // ------------------------------------------------------------------------- // Méthodes d'exécution Asynchrones // ------------------------------------------------------------------------- /// Recalcule le cache pour un utilisateur sur un serveur donné. async fn sync_user(repositories: Arc, user_id: Uuid, server_id: Uuid) { if let Err(err) = repositories .computed_permission .full_sync_user(user_id, server_id) .await { tracing::error!( "Erreur lors de la synchronisation des permissions pour l'utilisateur {} sur le serveur {}: {:?}", user_id, server_id, err ); } } /// Recalcule le cache pour tous les membres d'un rôle. async fn sync_role_members(repositories: Arc, role_id: Uuid, server_id: Uuid) { if let Err(err) = repositories .computed_permission .sync_role_members(role_id, server_id) .await { tracing::error!( "Erreur lors de la synchronisation des membres du rôle {} sur le serveur {}: {:?}", role_id, server_id, err ); } } /// Recalcule le cache pour TOUS les utilisateurs d'un serveur. async fn sync_server(repositories: Arc, server_id: Uuid) { if let Err(err) = repositories .computed_permission .full_sync_server(server_id) .await { tracing::error!( "Erreur lors de la synchronisation complète du serveur {}: {:?}", server_id, err ); } } }