feat: manage user online status and typing indicator in socket gateway
- Added tracking of online users with real-time status updates (online/offline). - Implemented `handleTyping` to broadcast user typing events to recipients. - Added `check_status` handler to query user online status. - Enhanced CORS configuration to support multi-domain deployments with credentials.
This commit is contained in:
@@ -17,8 +17,16 @@ import { JwtService } from "../crypto/services/jwt.service";
|
||||
|
||||
@WebSocketGateway({
|
||||
cors: {
|
||||
origin: "*",
|
||||
origin: (
|
||||
_origin: string,
|
||||
callback: (err: Error | null, allow?: boolean) => void,
|
||||
) => {
|
||||
// En production, on pourrait restreindre ici
|
||||
// Pour l'instant on autorise tout en mode credentials pour faciliter le déploiement multi-domaines
|
||||
callback(null, true);
|
||||
},
|
||||
credentials: true,
|
||||
methods: ["GET", "POST"],
|
||||
},
|
||||
})
|
||||
export class EventsGateway
|
||||
@@ -28,6 +36,7 @@ export class EventsGateway
|
||||
server!: Server;
|
||||
|
||||
private readonly logger = new Logger(EventsGateway.name);
|
||||
private readonly onlineUsers = new Map<string, Set<string>>(); // userId -> Set of socketIds
|
||||
|
||||
constructor(
|
||||
private readonly jwtService: JwtService,
|
||||
@@ -69,6 +78,13 @@ export class EventsGateway
|
||||
// Rejoindre une room personnelle pour les notifications
|
||||
client.join(`user:${payload.sub}`);
|
||||
|
||||
// Gérer le statut en ligne
|
||||
if (!this.onlineUsers.has(payload.sub)) {
|
||||
this.onlineUsers.set(payload.sub, new Set());
|
||||
this.server.emit("user_status", { userId: payload.sub, status: "online" });
|
||||
}
|
||||
this.onlineUsers.get(payload.sub)?.add(client.id);
|
||||
|
||||
this.logger.log(`Client connected: ${client.id} (User: ${payload.sub})`);
|
||||
} catch (error) {
|
||||
this.logger.error(`Connection error for client ${client.id}: ${error}`);
|
||||
@@ -77,6 +93,15 @@ export class EventsGateway
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket) {
|
||||
const userId = client.data.user?.sub;
|
||||
if (userId && this.onlineUsers.has(userId)) {
|
||||
const sockets = this.onlineUsers.get(userId);
|
||||
sockets?.delete(client.id);
|
||||
if (sockets?.size === 0) {
|
||||
this.onlineUsers.delete(userId);
|
||||
this.server.emit("user_status", { userId, status: "offline" });
|
||||
}
|
||||
}
|
||||
this.logger.log(`Client disconnected: ${client.id}`);
|
||||
}
|
||||
|
||||
@@ -98,6 +123,31 @@ export class EventsGateway
|
||||
this.logger.log(`Client ${client.id} left content room: ${contentId}`);
|
||||
}
|
||||
|
||||
@SubscribeMessage("typing")
|
||||
handleTyping(
|
||||
@ConnectedSocket() client: Socket,
|
||||
@MessageBody() data: { recipientId: string; isTyping: boolean },
|
||||
) {
|
||||
const userId = client.data.user?.sub;
|
||||
if (!userId) return;
|
||||
|
||||
this.server.to(`user:${data.recipientId}`).emit("user_typing", {
|
||||
userId,
|
||||
isTyping: data.isTyping,
|
||||
});
|
||||
}
|
||||
|
||||
@SubscribeMessage("check_status")
|
||||
handleCheckStatus(
|
||||
@ConnectedSocket() _client: Socket,
|
||||
@MessageBody() userId: string,
|
||||
) {
|
||||
return {
|
||||
userId,
|
||||
status: this.onlineUsers.has(userId) ? "online" : "offline",
|
||||
};
|
||||
}
|
||||
|
||||
// Méthode utilitaire pour envoyer des messages à un utilisateur spécifique
|
||||
sendToUser(userId: string, event: string, data: any) {
|
||||
this.server.to(`user:${userId}`).emit(event, data);
|
||||
|
||||
Reference in New Issue
Block a user