db = $dbConnection; $this->config = $mqttConfig; // Initialiser le client MQTT $this->initializeMqttClient(); } private function initializeMqttClient() { $this->mqtt = new MqttClient( $this->config['host'], $this->config['port'], 'geosector_api_' . uniqid(), // Client ID unique MqttClient::MQTT_3_1_1 ); $connectionSettings = (new ConnectionSettings) ->setUsername($this->config['username']) ->setPassword($this->config['password']) ->setKeepAliveInterval(60) ->setConnectTimeout(30) ->setUseTls($this->config['use_ssl'] ?? false); $this->mqtt->connect($connectionSettings, true); } /** * Envoie une notification pour un nouveau message */ public function sendMessageNotification($receiverId, $senderId, $messageId, $content, $conversationId) { try { // Vérifier les préférences de notification $settings = $this->getUserNotificationSettings($receiverId); if (!$this->shouldSendNotification($settings, $conversationId)) { return ['status' => 'skipped', 'reason' => 'notification_settings']; } // Obtenir les informations de l'expéditeur $sender = $this->getSenderInfo($senderId); // Obtenir le nom de la conversation $conversationName = $this->getConversationName($conversationId, $receiverId); // Préparer le payload de la notification $payload = [ 'type' => 'chat_message', 'messageId' => $messageId, 'conversationId' => $conversationId, 'senderId' => $senderId, 'senderName' => $sender['name'] ?? 'Utilisateur', 'content' => $settings['show_preview'] ? $content : 'Nouveau message', 'conversationName' => $conversationName, 'timestamp' => time(), ]; // Définir le topic MQTT $topic = sprintf('chat/user/%s/messages', $receiverId); // Publier le message $this->mqtt->publish($topic, json_encode($payload), 1); // Enregistrer la notification dans la base de données $this->saveNotificationToDatabase($receiverId, $messageId, $conversationId, $payload); return [ 'status' => 'success', 'topic' => $topic ]; } catch (Exception $e) { return [ 'status' => 'error', 'reason' => $e->getMessage() ]; } } /** * Envoie une annonce à plusieurs utilisateurs */ public function sendBroadcastAnnouncement($audienceTargets, $messageId, $title, $content, $conversationId) { $results = []; $userIds = $this->resolveAudienceTargets($audienceTargets); foreach ($userIds as $userId) { // Préparer le payload pour l'annonce $payload = [ 'type' => 'announcement', 'messageId' => $messageId, 'conversationId' => $conversationId, 'title' => $title, 'content' => $content, 'timestamp' => time(), ]; // Envoyer à chaque utilisateur $topic = sprintf('chat/user/%s/messages', $userId); try { $this->mqtt->publish($topic, json_encode($payload), 1); $results[$userId] = ['status' => 'success']; // Enregistrer la notification $this->saveNotificationToDatabase($userId, $messageId, $conversationId, $payload); } catch (Exception $e) { $results[$userId] = ['status' => 'error', 'reason' => $e->getMessage()]; } } // Publier aussi sur le topic général des annonces $this->mqtt->publish('chat/announcement', json_encode($payload), 1); return $results; } /** * Envoie une notification à une conversation spécifique */ public function sendConversationNotification($conversationId, $messageId, $senderId, $content) { $participants = $this->getConversationParticipants($conversationId); foreach ($participants as $participant) { if ($participant['id'] !== $senderId) { $this->sendMessageNotification( $participant['id'], $senderId, $messageId, $content, $conversationId ); } } } /** * Vérifie si une notification doit être envoyée */ private function shouldSendNotification($settings, $conversationId) { if (!$settings['enable_notifications']) { return false; } if (in_array($conversationId, $settings['muted_conversations'])) { return false; } if ($settings['do_not_disturb'] && $this->isInDoNotDisturbPeriod($settings)) { return false; } return true; } /** * Récupère les paramètres de notification de l'utilisateur */ private function getUserNotificationSettings($userId) { $stmt = $this->db->prepare(" SELECT * FROM notification_settings WHERE user_id = ? "); $stmt->execute([$userId]); $result = $stmt->fetch(PDO::FETCH_ASSOC); // Valeurs par défaut si pas de préférences return $result ?: [ 'enable_notifications' => true, 'show_preview' => true, 'muted_conversations' => [], 'do_not_disturb' => false, 'do_not_disturb_start' => null, 'do_not_disturb_end' => null, ]; } /** * Vérifie si on est dans la période "Ne pas déranger" */ private function isInDoNotDisturbPeriod($settings) { if (!$settings['do_not_disturb']) { return false; } $now = new DateTime(); $start = new DateTime($settings['do_not_disturb_start']); $end = new DateTime($settings['do_not_disturb_end']); if ($start < $end) { return $now >= $start && $now <= $end; } else { // Période qui chevauche minuit return $now >= $start || $now <= $end; } } /** * Enregistre la notification dans la base de données */ private function saveNotificationToDatabase($userId, $messageId, $conversationId, $payload) { $stmt = $this->db->prepare(" INSERT INTO chat_notifications (fk_user, fk_message, fk_room, type, contenu, statut) VALUES (?, ?, ?, ?, ?, 'non_lue') "); $stmt->execute([ $userId, $messageId, $conversationId, $payload['type'], json_encode($payload) ]); } /** * Récupère les informations de l'expéditeur */ private function getSenderInfo($senderId) { $stmt = $this->db->prepare(" SELECT id, name, username FROM users WHERE id = ? "); $stmt->execute([$senderId]); return $stmt->fetch(PDO::FETCH_ASSOC); } /** * Récupère le nom de la conversation */ private function getConversationName($conversationId, $userId) { $stmt = $this->db->prepare(" SELECT title FROM chat_rooms WHERE id = ? "); $stmt->execute([$conversationId]); return $stmt->fetchColumn(); } /** * Récupère les participants d'une conversation */ private function getConversationParticipants($conversationId) { $stmt = $this->db->prepare(" SELECT id_user as id, role FROM chat_participants WHERE id_room = ? AND notification_activee = 1 "); $stmt->execute([$conversationId]); return $stmt->fetchAll(PDO::FETCH_ASSOC); } /** * Résout les cibles d'audience en une liste d'IDs utilisateur */ private function resolveAudienceTargets($targets) { $userIds = []; foreach ($targets as $target) { switch ($target['target_type']) { case 'all': $stmt = $this->db->query("SELECT id FROM users WHERE chk_active = 1"); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; case 'role': $stmt = $this->db->prepare("SELECT id FROM users WHERE fk_role = ?"); $stmt->execute([$target['role_filter']]); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; case 'entity': $stmt = $this->db->prepare("SELECT id FROM users WHERE fk_entite = ?"); $stmt->execute([$target['entity_filter']]); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; case 'combined': $stmt = $this->db->prepare(" SELECT id FROM users WHERE fk_role = ? AND fk_entite = ? "); $stmt->execute([$target['role_filter'], $target['entity_filter']]); $userIds = array_merge($userIds, $stmt->fetchAll(PDO::FETCH_COLUMN)); break; } } return array_unique($userIds); } /** * Ferme la connexion MQTT */ public function disconnect() { if ($this->mqtt) { $this->mqtt->disconnect(); } } }