Skip to content

Commit faca443

Browse files
committed
fix: guard disconnect cleanup without user id
Signed-off-by: Hoang Pham <hoangmaths96@gmail.com>
1 parent 8022746 commit faca443

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

tests/integration/multinode-redis.spec.mjs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,43 @@ describe('Multi node websocket cluster with redis streams', () => {
518518
await restartServerA()
519519
})
520520

521+
it('ignores missing disconnect metadata while another user is presenting', async () => {
522+
const roomID = 'room-missing-disconnect-meta'
523+
const presenterToken = buildToken(roomID, { id: 'presenter', name: 'Presenter', displayName: 'Presenter' })
524+
const viewerToken = buildToken(roomID, { id: 'viewer', name: 'Viewer', displayName: 'Viewer' })
525+
526+
const presenterSocket = createSocket(serverBUrl, presenterToken)
527+
await waitFor(presenterSocket, 'connect')
528+
presenterSocket.emit('join-room', roomID)
529+
await waitFor(presenterSocket, 'sync-designate')
530+
531+
presenterSocket.emit('presentation-start', { fileId: roomID, userId: 'presenter' })
532+
await waitFor(presenterSocket, 'presentation-started')
533+
534+
const viewerSocket = createSocket(serverAUrl, viewerToken)
535+
await waitFor(viewerSocket, 'connect')
536+
viewerSocket.emit('join-room', roomID)
537+
await waitFor(viewerSocket, 'sync-designate')
538+
await waitFor(viewerSocket, 'user-started-presenting')
539+
540+
const serverSideViewer = serverA.socketService.io.sockets.sockets.get(viewerSocket.id)
541+
expect(serverSideViewer).toBeDefined()
542+
543+
await serverA.socketService.sessionStore.clearSocketMeta(viewerSocket.id)
544+
545+
const roomChangeNotice = waitFor(presenterSocket, 'room-user-change')
546+
await expect(
547+
serverA.socketService.roomLifecycleController.onDisconnecting(serverSideViewer, [roomID]),
548+
).resolves.toBeUndefined()
549+
550+
const roomUsers = await roomChangeNotice
551+
expect(roomUsers).toHaveLength(1)
552+
expect(roomUsers[0].userId).toBe('presenter')
553+
554+
const presentationSession = await serverB.socketService.getPresentationSession(roomID)
555+
expect(presentationSession?.presenterId).toBe('presenter')
556+
})
557+
521558
it('cleans stale recording entries from dead nodes before notifying joiners', async () => {
522559
const roomID = 'room-stale-recording'
523560

websocket_server/Services/RoomLifecycleService.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,12 +194,12 @@ export default class RoomLifecycleService {
194194

195195
const presentationSession = await this.presentationState.getPresentationSession(roomID)
196196
if (presentationSession) {
197-
const isPublicSharingUser = userId.startsWith('shared_')
197+
const isPublicSharingUser = typeof userId === 'string' && userId.startsWith('shared_')
198198
let shouldEndPresentation = false
199199

200200
if (presentationSession.presenterId === userId) {
201201
shouldEndPresentation = true
202-
} else if (isPublicSharingUser) {
202+
} else if (isPublicSharingUser && typeof presentationSession.presenterId === 'string') {
203203
const userTokenPart = userId.split('_')[1]
204204
const presenterTokenPart = presentationSession.presenterId.split('_')[1]
205205
if (userTokenPart === presenterTokenPart) {

0 commit comments

Comments
 (0)