209 lines
5.9 KiB
Java
209 lines
5.9 KiB
Java
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();
|
|
}
|
|
} |