From 036e7036f8bd65f0fe18e01dd226395b1dec290f Mon Sep 17 00:00:00 2001 From: Maksim Sukharev Date: Fri, 3 Jul 2026 11:01:58 +0200 Subject: [PATCH] fix(signaling): rejoin with a fresh session on 'no_such_room' rejection - When client reconnect to HPB after a network change, both HPB and PHP sessions might be expired - HPB opens a new websocket gracefully, but nothing triggers PHP session to be established again - HPB then rejects the room join with a "no_such_room" error. - Handle by dispatching server request to join conversation similar to useActiveSession.js logic Assisted-by: ClaudeCode:claude-opus-4-8 Signed-off-by: Maksim Sukharev --- src/utils/signaling.js | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/utils/signaling.js b/src/utils/signaling.js index 24f518cd340..f01790ccb5f 100644 --- a/src/utils/signaling.js +++ b/src/utils/signaling.js @@ -820,6 +820,9 @@ Signaling.Standalone.prototype.connect = function() { case 'token_expired': this.processErrorTokenExpired() break + case 'no_such_room': + this.processErrorNoSuchRoom() + break default: console.error('Ignore unknown error: %s', JSON.stringify(data.error)) this._trigger('error', [data.error]) @@ -1284,6 +1287,13 @@ Signaling.Standalone.prototype.joinCall = function(token, flags, silent, recordi Signaling.Standalone.prototype.joinResponseReceived = function(data, token) { console.debug('Joined', data, token) + + if (data.type === 'error' && data.error.code === 'no_such_room') { + // Handled in processErrorNoSuchRoom + return + } + + this._rejoinRoomAfterInvalidSession = null this.signalingRoomJoined = token if (this.pendingJoinCall && token === this.pendingJoinCall.token) { const pendingJoinCallResolve = this.pendingJoinCall.resolve @@ -1545,6 +1555,30 @@ Signaling.Standalone.prototype.processRoomParticipantsEvent = function(data) { } } +Signaling.Standalone.prototype.processErrorNoSuchRoom = function() { + // HPB rejected the room join because the PHP session is no longer valid, + // e.g. session was cleaned up as a stale during client being offline + // => ws has reconnected to the room with a stale session id. + const token = this.currentRoomToken + if (!token) { + return + } + + if (this._rejoinRoomAfterInvalidSession === token) { + // prevent re-join loop + console.error('Rejoining room with a new session failed, giving up', token) + return + } + + console.warn('Room join was rejected as the session is no longer valid, rejoining with a new session', token) + this._rejoinRoomAfterInvalidSession = token + this.resumeId = null + this.signalingRoomJoined = null + store.dispatch('joinConversation', { token }).catch((error) => { + console.error('Failed to rejoin conversation with a new session', token, error) + }) +} + Signaling.Standalone.prototype.processErrorTokenExpired = function() { console.info('The signaling token is expired, need to update settings')