feat: migration complète vers WebSockets Next + Kafka pour temps réel

- Migration de Jakarta WebSocket vers Quarkus WebSockets Next
- Implémentation de l'architecture Kafka pour événements temps réel
- Ajout des DTOs d'événements (NotificationEvent, ChatMessageEvent, ReactionEvent, PresenceEvent)
- Création des bridges Kafka → WebSocket (NotificationKafkaBridge, ChatKafkaBridge, ReactionKafkaBridge)
- Mise à jour des services pour publier dans Kafka au lieu d'appeler directement WebSocket
- Suppression des classes obsolètes (ChatWebSocket, NotificationWebSocket)
- Correction de l'injection des paramètres path dans WebSockets Next (utilisation de connection.pathParam)
- Ajout des migrations DB pour bookings, promotions, business hours, amenities, reviews
- Mise à jour de la configuration application.properties pour Kafka et WebSockets Next
- Mise à jour .gitignore pour ignorer les fichiers de logs
This commit is contained in:
dahoud
2026-01-21 13:46:16 +00:00
parent 7dd0969799
commit 93c63fd600
78 changed files with 5019 additions and 1113 deletions

View File

@@ -13,7 +13,9 @@ import com.lions.dev.exception.FriendshipNotFoundException;
import com.lions.dev.exception.UserNotFoundException;
import com.lions.dev.repository.FriendshipRepository;
import com.lions.dev.repository.UsersRepository;
import com.lions.dev.websocket.NotificationWebSocket;
import com.lions.dev.dto.events.NotificationEvent;
import org.eclipse.microprofile.reactive.messaging.Channel;
import org.eclipse.microprofile.reactive.messaging.Emitter;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
@@ -40,6 +42,10 @@ public class FriendshipService {
@Inject
NotificationService notificationService; // Injecte le service de notifications
@Inject
@Channel("notifications")
Emitter<NotificationEvent> notificationEmitter; // v2.0 - Publie dans Kafka
private static final Logger logger = Logger.getLogger(FriendshipService.class);
/**
@@ -79,24 +85,26 @@ public class FriendshipService {
Friendship friendship = new Friendship(user, friend, FriendshipStatus.PENDING);
friendshipRepository.persist(friendship);
// TEMPS RÉEL: Notifier le destinataire via WebSocket
// TEMPS RÉEL: Publier dans Kafka (v2.0)
try {
Map<String, Object> notificationData = new HashMap<>();
notificationData.put("requestId", friendship.getId().toString());
notificationData.put("senderId", user.getId().toString());
notificationData.put("senderName", user.getPrenoms() + " " + user.getNom());
// v2.0 - Utiliser les nouveaux noms de champs
notificationData.put("senderName", user.getFirstName() + " " + user.getLastName());
notificationData.put("senderProfileImage", user.getProfileImageUrl() != null ? user.getProfileImageUrl() : "");
NotificationWebSocket.sendNotificationToUser(
friend.getId(),
NotificationEvent event = new NotificationEvent(
friend.getId().toString(), // userId destinataire (clé Kafka)
"friend_request_received",
notificationData
);
logger.info("[LOG] Notification WebSocket envoyée au destinataire : " + friend.getId());
notificationEmitter.send(event);
logger.info("[LOG] Événement friend_request_received publié dans Kafka pour : " + friend.getId());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de l'envoi de la notification WebSocket : " + e.getMessage(), e);
// Ne pas bloquer la demande d'amitié si le WebSocket échoue
logger.error("[ERROR] Erreur lors de la publication dans Kafka : " + e.getMessage(), e);
// Ne pas bloquer la demande d'amitié si Kafka échoue
}
logger.info("[LOG] Demande d'amitié envoyée avec succès.");
@@ -139,11 +147,12 @@ public class FriendshipService {
// Log de succès
logger.info(String.format("[LOG] Demande d'amitié acceptée avec succès pour l'ID: %s", friendshipId)); // Correctement formaté
// TEMPS RÉEL: Notifier l'émetteur de la demande via WebSocket
// TEMPS RÉEL: Publier dans Kafka (v2.0)
try {
Users user = friendship.getUser();
Users friend = friendship.getFriend();
String friendName = friend.getPrenoms() + " " + friend.getNom();
// v2.0 - Utiliser les nouveaux noms de champs
String friendName = friend.getFirstName() + " " + friend.getLastName();
Map<String, Object> notificationData = new HashMap<>();
notificationData.put("acceptedBy", friendName);
@@ -151,24 +160,26 @@ public class FriendshipService {
notificationData.put("accepterId", friend.getId().toString());
notificationData.put("accepterProfileImage", friend.getProfileImageUrl() != null ? friend.getProfileImageUrl() : "");
NotificationWebSocket.sendNotificationToUser(
user.getId(),
NotificationEvent event = new NotificationEvent(
user.getId().toString(), // userId émetteur (destinataire de la notification)
"friend_request_accepted",
notificationData
);
logger.info("[LOG] Notification WebSocket d'acceptation envoyée à : " + user.getId());
notificationEmitter.send(event);
logger.info("[LOG] Événement friend_request_accepted publié dans Kafka pour : " + user.getId());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de l'envoi de la notification WebSocket d'acceptation : " + e.getMessage(), e);
// Ne pas bloquer l'acceptation si le WebSocket échoue
logger.error("[ERROR] Erreur lors de la publication dans Kafka : " + e.getMessage(), e);
// Ne pas bloquer l'acceptation si Kafka échoue
}
// Créer des notifications pour les deux utilisateurs
try {
Users user = friendship.getUser();
Users friend = friendship.getFriend();
String userName = user.getPrenoms() + " " + user.getNom();
String friendName = friend.getPrenoms() + " " + friend.getNom();
// v2.0 - Utiliser les nouveaux noms de champs
String userName = user.getFirstName() + " " + user.getLastName();
String friendName = friend.getFirstName() + " " + friend.getLastName();
// Notification pour l'utilisateur qui a envoyé la demande
notificationService.createNotification(
@@ -212,7 +223,7 @@ public class FriendshipService {
friendship.setStatus(FriendshipStatus.REJECTED);
friendshipRepository.persist(friendship);
// TEMPS RÉEL: Notifier l'émetteur de la demande via WebSocket (optionnel selon UX)
// TEMPS RÉEL: Publier dans Kafka (v2.0)
try {
Users user = friendship.getUser();
@@ -220,16 +231,17 @@ public class FriendshipService {
notificationData.put("friendshipId", friendshipId.toString());
notificationData.put("rejectedAt", System.currentTimeMillis());
NotificationWebSocket.sendNotificationToUser(
user.getId(),
NotificationEvent event = new NotificationEvent(
user.getId().toString(), // userId émetteur (destinataire de la notification)
"friend_request_rejected",
notificationData
);
logger.info("[LOG] Notification WebSocket de rejet envoyée à : " + user.getId());
notificationEmitter.send(event);
logger.info("[LOG] Événement friend_request_rejected publié dans Kafka pour : " + user.getId());
} catch (Exception e) {
logger.error("[ERROR] Erreur lors de l'envoi de la notification WebSocket de rejet : " + e.getMessage(), e);
// Ne pas bloquer le rejet si le WebSocket échoue
logger.error("[ERROR] Erreur lors de la publication dans Kafka : " + e.getMessage(), e);
// Ne pas bloquer le rejet si Kafka échoue
}
logger.info("[LOG] Demande d'amitié rejetée.");
@@ -288,11 +300,12 @@ public class FriendshipService {
+ user.getId() + ", ami ID : " + friend.getId());
// Création du DTO de réponse à partir des informations de l'ami et de la relation
// v2.0 - Utiliser les nouveaux noms de champs
return new FriendshipReadFriendDetailsResponseDTO(
user.getId(), // ID de l'utilisateur
friend.getId(), // ID de l'ami
friend.getNom(), // Nom de l'ami
friend.getPrenoms(),
friend.getLastName(), // Nom de famille de l'ami (v2.0)
friend.getFirstName(), // Prénom de l'ami (v2.0)
friend.getEmail(), // Email de l'ami
friend.getProfileImageUrl(), // URL de l'image de profil de l'ami
friendship.getStatus(), // Statut de la relation
@@ -325,11 +338,12 @@ public class FriendshipService {
return friendships.stream()
.map(friendship -> {
Users friend = friendship.getUser().equals(user) ? friendship.getFriend() : friendship.getUser();
// v2.0 - Utiliser les nouveaux noms de champs
return new FriendshipReadFriendDetailsResponseDTO(
user.getId(),
friend.getId(),
friend.getNom(),
friend.getPrenoms(),
friend.getLastName(), // v2.0
friend.getFirstName(), // v2.0
friend.getEmail(),
friend.getProfileImageUrl(),
friendship.getStatus(),