Versions stable (inachevée mais prête à un déploiement en prod)
This commit is contained in:
209
src/main/java/dev/lions/services/WebSocketService.java
Normal file
209
src/main/java/dev/lions/services/WebSocketService.java
Normal file
@@ -0,0 +1,209 @@
|
||||
package dev.lions.services;
|
||||
|
||||
import dev.lions.dtos.NotificationDTO;
|
||||
import dev.lions.exceptions.WebSocketException;
|
||||
|
||||
import jakarta.enterprise.context.ApplicationScoped;
|
||||
import jakarta.websocket.*;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Service gérant les communications WebSocket de l'application.
|
||||
* Cette classe assure la gestion des connexions temps réel et la diffusion
|
||||
* des notifications aux clients connectés.
|
||||
*/
|
||||
@Slf4j
|
||||
@ApplicationScoped
|
||||
@ServerEndpoint("/ws/notifications")
|
||||
public class WebSocketService {
|
||||
|
||||
private static final Map<String, Session> sessions = new ConcurrentHashMap<>();
|
||||
private static final int MAX_MESSAGE_SIZE = 8192;
|
||||
private static final long IDLE_TIMEOUT = 300000; // 5 minutes
|
||||
|
||||
/**
|
||||
* Gère l'ouverture d'une nouvelle connexion WebSocket.
|
||||
*
|
||||
* @param session Session WebSocket ouverte
|
||||
*/
|
||||
@OnOpen
|
||||
public void onOpen(Session session) {
|
||||
log.info("Nouvelle connexion WebSocket établie : {}", session.getId());
|
||||
|
||||
try {
|
||||
configureSession(session);
|
||||
sessions.put(session.getId(), session);
|
||||
|
||||
sendWelcomeMessage(session);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Erreur lors de l'initialisation de la session WebSocket", e);
|
||||
closeSession(session, "Erreur d'initialisation");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure une nouvelle session WebSocket.
|
||||
*/
|
||||
private void configureSession(Session session) {
|
||||
session.setMaxIdleTimeout(IDLE_TIMEOUT);
|
||||
session.setMaxTextMessageBufferSize(MAX_MESSAGE_SIZE);
|
||||
session.setMaxBinaryMessageBufferSize(MAX_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie un message de bienvenue au client connecté.
|
||||
*/
|
||||
private void sendWelcomeMessage(Session session) {
|
||||
try {
|
||||
String message = "{\"type\":\"welcome\",\"message\":\"Connexion établie\"}";
|
||||
session.getBasicRemote().sendText(message);
|
||||
} catch (Exception e) {
|
||||
log.warn("Impossible d'envoyer le message de bienvenue", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère la réception d'un message depuis un client.
|
||||
*
|
||||
* @param message Message reçu
|
||||
* @param session Session WebSocket active
|
||||
*/
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
String sessionId = session.getId();
|
||||
log.debug("Message reçu de la session {} : {}", sessionId, message);
|
||||
|
||||
try {
|
||||
validateMessage(message);
|
||||
processMessage(message, session);
|
||||
} catch (Exception e) {
|
||||
log.error("Erreur lors du traitement du message", e);
|
||||
sendErrorResponse(session, "Erreur de traitement du message");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide le contenu d'un message reçu.
|
||||
*/
|
||||
private void validateMessage(String message) {
|
||||
if (message == null || message.trim().isEmpty()) {
|
||||
throw new WebSocketException("Message vide non autorisé");
|
||||
}
|
||||
if (message.length() > MAX_MESSAGE_SIZE) {
|
||||
throw new WebSocketException("Message trop long");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Traite un message reçu.
|
||||
*/
|
||||
private void processMessage(String message, Session session) {
|
||||
// Implémentation du traitement des messages selon les besoins
|
||||
log.debug("Traitement du message de la session {}", session.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère la fermeture d'une connexion WebSocket.
|
||||
*
|
||||
* @param session Session WebSocket fermée
|
||||
*/
|
||||
@OnClose
|
||||
public void onClose(Session session) {
|
||||
String sessionId = session.getId();
|
||||
log.info("Fermeture de la connexion WebSocket : {}", sessionId);
|
||||
|
||||
sessions.remove(sessionId);
|
||||
cleanupSession(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gère les erreurs survenant sur une connexion WebSocket.
|
||||
*
|
||||
* @param session Session WebSocket concernée
|
||||
* @param throwable Erreur survenue
|
||||
*/
|
||||
@OnError
|
||||
public void onError(Session session, Throwable throwable) {
|
||||
String sessionId = session.getId();
|
||||
log.error("Erreur WebSocket sur la session {} : {}",
|
||||
sessionId, throwable.getMessage(), throwable);
|
||||
|
||||
closeSession(session, "Erreur interne");
|
||||
}
|
||||
|
||||
/**
|
||||
* Diffuse une notification à tous les clients connectés.
|
||||
*
|
||||
* @param notification Notification à diffuser
|
||||
*/
|
||||
public void broadcastToAdmins(NotificationDTO notification) {
|
||||
log.debug("Diffusion d'une notification à {} clients", sessions.size());
|
||||
|
||||
String message = notification.toJson();
|
||||
sessions.values().forEach(session -> {
|
||||
try {
|
||||
if (session.isOpen()) {
|
||||
session.getBasicRemote().sendText(message);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Erreur lors de l'envoi à la session {}",
|
||||
session.getId(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie une réponse d'erreur à un client.
|
||||
*/
|
||||
private void sendErrorResponse(Session session, String errorMessage) {
|
||||
try {
|
||||
String message = String.format(
|
||||
"{\"type\":\"error\",\"message\":\"%s\"}",
|
||||
errorMessage
|
||||
);
|
||||
session.getBasicRemote().sendText(message);
|
||||
} catch (Exception e) {
|
||||
log.error("Impossible d'envoyer la réponse d'erreur", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ferme une session WebSocket.
|
||||
*/
|
||||
private void closeSession(Session session, String reason) {
|
||||
try {
|
||||
session.close(new CloseReason(
|
||||
CloseReason.CloseCodes.NORMAL_CLOSURE,
|
||||
reason
|
||||
));
|
||||
} catch (Exception e) {
|
||||
log.warn("Erreur lors de la fermeture de la session", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoie les ressources d'une session.
|
||||
*/
|
||||
private void cleanupSession(Session session) {
|
||||
try {
|
||||
session.close();
|
||||
} catch (Exception e) {
|
||||
log.warn("Erreur lors du nettoyage de la session", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère le nombre de clients connectés.
|
||||
*/
|
||||
public int getConnectedClientsCount() {
|
||||
return sessions.size();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user