From 14698ebb05202892666e19a470deeb9a3faad7e1 Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Sat, 17 Jan 2026 13:42:58 +0000 Subject: [PATCH] fix room exit --- .../ws/services/excalidraw-collab.service.ts | 40 ++++++++++++++++++- apps/server/src/ws/ws.gateway.ts | 12 ++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/apps/server/src/ws/services/excalidraw-collab.service.ts b/apps/server/src/ws/services/excalidraw-collab.service.ts index 12924296..74252061 100644 --- a/apps/server/src/ws/services/excalidraw-collab.service.ts +++ b/apps/server/src/ws/services/excalidraw-collab.service.ts @@ -4,6 +4,10 @@ import { ExcalidrawFollowPayload } from '../types/excalidraw.types'; @Injectable() export class ExcalidrawCollabService { + // Track socket -> rooms mapping for disconnect handling + // (Socket.IO clears client.rooms before handleDisconnect runs) + private socketRooms = new Map>(); + async handleJoinRoom( client: Socket, server: Server, @@ -11,6 +15,12 @@ export class ExcalidrawCollabService { ): Promise { await client.join(roomId); + // Track room membership + if (!this.socketRooms.has(client.id)) { + this.socketRooms.set(client.id, new Set()); + } + this.socketRooms.get(client.id).add(roomId); + const sockets = await server.in(roomId).fetchSockets(); if (sockets.length <= 1) { @@ -25,6 +35,26 @@ export class ExcalidrawCollabService { ); } + async handleLeaveRoom( + client: Socket, + server: Server, + roomId: string, + ): Promise { + await client.leave(roomId); + + // Remove from tracking + this.socketRooms.get(client.id)?.delete(roomId); + + // Notify remaining users + const sockets = await server.in(roomId).fetchSockets(); + if (sockets.length > 0) { + server.in(roomId).emit( + 'room-user-change', + sockets.map((socket) => socket.id), + ); + } + } + handleServerBroadcast( client: Socket, roomId: string, @@ -68,7 +98,10 @@ export class ExcalidrawCollabService { } async handleDisconnecting(client: Socket, server: Server): Promise { - for (const roomId of Array.from(client.rooms)) { + // Use tracked rooms since client.rooms is empty by this point + const rooms = this.socketRooms.get(client.id) || new Set(); + + for (const roomId of rooms) { const otherClients = (await server.in(roomId).fetchSockets()).filter( (socket) => socket.id !== client.id, ); @@ -76,7 +109,7 @@ export class ExcalidrawCollabService { const isFollowRoom = roomId.startsWith('follow@'); if (!isFollowRoom && otherClients.length > 0) { - client.broadcast.to(roomId).emit( + server.to(roomId).emit( 'room-user-change', otherClients.map((socket) => socket.id), ); @@ -87,5 +120,8 @@ export class ExcalidrawCollabService { server.to(socketId).emit('broadcast-unfollow'); } } + + // Clean up tracking + this.socketRooms.delete(client.id); } } diff --git a/apps/server/src/ws/ws.gateway.ts b/apps/server/src/ws/ws.gateway.ts index 5456887a..6350720e 100644 --- a/apps/server/src/ws/ws.gateway.ts +++ b/apps/server/src/ws/ws.gateway.ts @@ -88,11 +88,15 @@ export class WsGateway } @SubscribeMessage('leave-room') - handleLeaveRoom( + async handleLeaveRoom( @ConnectedSocket() client: Socket, - @MessageBody() roomName: string, - ): void { - client.leave(roomName); + @MessageBody() roomId: string, + ): Promise { + await this.excalidrawCollabService.handleLeaveRoom( + client, + this.server, + roomId, + ); } @SubscribeMessage('server-broadcast')