Files
mic-after-work-server-impl-…/src/main/java/com/lions/dev/service/PresenceService.java
2026-01-31 16:54:46 +00:00

145 lines
4.5 KiB
Java

package com.lions.dev.service;
import com.lions.dev.dto.events.PresenceEvent;
import com.lions.dev.entity.users.Users;
import com.lions.dev.repository.UsersRepository;
import io.quarkus.logging.Log;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.control.ActivateRequestContext;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import org.eclipse.microprofile.reactive.messaging.Channel;
import org.eclipse.microprofile.reactive.messaging.Emitter;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
/**
* Service pour gérer la présence des utilisateurs (online/offline).
*
* Ce service gère:
* - Le marquage des utilisateurs comme en ligne/hors ligne
* - Le heartbeat pour maintenir le statut online
* - La diffusion de la présence aux amis via Kafka → WebSocket
*
* Architecture v2.0:
* PresenceService → Kafka Topic (presence.updates) → PresenceKafkaBridge → WebSocket → Client
*/
@ApplicationScoped
public class PresenceService {
@Inject
UsersRepository usersRepository;
@Inject
@Channel("presence")
Emitter<PresenceEvent> presenceEmitter; // v2.0 - Publie dans Kafka
/**
* Marque un utilisateur comme en ligne et broadcast sa présence.
*
* @param userId L'ID de l'utilisateur
*/
@Transactional
public void setUserOnline(UUID userId) {
Users user = usersRepository.findById(userId);
if (user != null) {
user.updatePresence();
usersRepository.persist(user);
// Broadcast présence aux autres utilisateurs
broadcastPresenceToAll(userId, true, user.getLastSeen());
Log.debug("[PRESENCE] Utilisateur " + userId + " marqué online");
}
}
/**
* Marque un utilisateur comme hors ligne.
*
* @param userId L'ID de l'utilisateur
*/
@Transactional
public void setUserOffline(UUID userId) {
Users user = usersRepository.findById(userId);
if (user != null) {
user.setOffline();
usersRepository.persist(user);
// Broadcast présence aux autres utilisateurs
broadcastPresenceToAll(userId, false, user.getLastSeen());
Log.debug("[PRESENCE] Utilisateur " + userId + " marqué offline");
}
}
/**
* Met à jour le heartbeat d'un utilisateur (keep-alive).
* Cette méthode est appelée depuis un thread worker, donc elle doit activer le contexte de requête.
*
* @param userId L'ID de l'utilisateur
*/
@ActivateRequestContext
@Transactional
public void heartbeat(UUID userId) {
Users user = usersRepository.findById(userId);
if (user != null) {
user.updatePresence();
usersRepository.persist(user);
Log.debug("[PRESENCE] Heartbeat reçu pour utilisateur " + userId);
}
}
/**
* Broadcast la présence d'un utilisateur via Kafka (v2.0).
* Le PresenceKafkaBridge consommera depuis Kafka et enverra via WebSocket.
*
* @param userId L'ID de l'utilisateur
* @param isOnline Le statut online
* @param lastSeen La dernière fois que l'utilisateur était en ligne
*/
private void broadcastPresenceToAll(UUID userId, boolean isOnline, LocalDateTime lastSeen) {
try {
// Convertir LocalDateTime en timestamp (milliseconds)
Long lastSeenTimestamp = lastSeen != null
? lastSeen.toInstant(ZoneOffset.UTC).toEpochMilli()
: null;
// Créer l'événement de présence
PresenceEvent presenceEvent = new PresenceEvent(
userId.toString(),
isOnline ? "online" : "offline",
lastSeenTimestamp
);
// Publier dans Kafka (le bridge s'occupera de l'envoi WebSocket)
presenceEmitter.send(presenceEvent);
Log.debug("[PRESENCE] Événement de présence publié dans Kafka: " + userId + " -> " +
(isOnline ? "online" : "offline"));
} catch (Exception e) {
Log.error("[PRESENCE] Erreur lors de la publication de présence dans Kafka", e);
}
}
/**
* Récupère le statut de présence d'un utilisateur.
*
* @param userId L'ID de l'utilisateur
* @return Map contenant isOnline et lastSeen
*/
public Map<String, Object> getUserPresence(UUID userId) {
Users user = usersRepository.findById(userId);
Map<String, Object> presence = new HashMap<>();
if (user != null) {
presence.put("userId", userId.toString());
presence.put("isOnline", user.isOnline());
presence.put("lastSeen", user.getLastSeen() != null ? user.getLastSeen().toString() : null);
}
return presence;
}
}