From 8005dddaebc8fc8c7673909b3d89b07358a16760 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 12:42:43 +0100 Subject: [PATCH 01/20] hang up before connect --- .../middleware.auto-reconnect.ts | 87 +++++++------------ 1 file changed, 32 insertions(+), 55 deletions(-) diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 8f4bd01c70bf..02a12311b77d 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -5,7 +5,7 @@ import { hideNotification } from "../../../../notifications/actions"; import { CONFERENCE_WILL_LEAVE } from "../../../conference/actionTypes"; import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; import { CONNECTION_DISCONNECTED, CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; -import { connect } from "../../../connection/actions.web"; +import { connect, hangup } from "../../../connection/actions.web"; import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; import { trackRemoved } from "../../../tracks/actions.any"; @@ -14,13 +14,12 @@ import { hideLoader, showLoader } from "../../loader"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; const RECONNECTION_LOADER_ID = "auto-reconnect"; const RECONNECTION_WAIT_TIME_MS = 15000; -const MAX_RECONNECTION_ATTEMPTS = 2; const RECONNECTION_DELAY_MS = 3000; const JWT_EXPIRED_ERROR = "connection.passwordRequired"; let reconnectionTimer: number | null = null; let isReconnecting = false; -let reconnectionAttempts = 0; +let hasReconnected = false; export const isAutoReconnecting = () => isReconnecting; @@ -28,20 +27,10 @@ const hideReconnectionNotification = (store: IStore) => { store.dispatch(hideNotification(RECONNECTION_NOTIFICATION_ID)); }; -const showReconnectionLoader = (store: IStore, attempt: number) => { - const textKey = attempt <= MAX_RECONNECTION_ATTEMPTS ? "loader.reconnecting" : "loader.reloading"; - - store.dispatch(showLoader(undefined, textKey, RECONNECTION_LOADER_ID)); -}; - const hideReconnectionLoader = (store: IStore) => { store.dispatch(hideLoader(RECONNECTION_LOADER_ID)); }; -const reloadPage = () => { - window.location.reload(); -}; - const clearExpiredJWT = (store: IStore) => { store.dispatch(setJWT(undefined)); }; @@ -57,49 +46,38 @@ const clearRemoteTracks = (store: IStore) => { }); }; -const triggerReconnection = (store: IStore) => { - store.dispatch(connect()); -}; +const leaveAndRejoinConference = async (store: IStore) => { + if (isLeavingConferenceManually() || hasReconnected) return; -const scheduleRetry = (store: IStore) => { - reconnectionTimer = window.setTimeout(() => { - if (!isLeavingConferenceManually() && isReconnecting) { - attemptReconnection(store); - } - }, RECONNECTION_DELAY_MS); -}; - -const handleMaxAttemptsReached = (store: IStore) => { + hasReconnected = true; isReconnecting = true; - showReconnectionLoader(store, reconnectionAttempts + 1); - reconnectionTimer = window.setTimeout(reloadPage, 2000); -}; + store.dispatch(showLoader(undefined, "loader.reconnecting", RECONNECTION_LOADER_ID)); -/** - * Attempts to reconnect by clearing JWT and connecting to conference again. - * If max attempts reached, reloads the page. - */ -const attemptReconnection = async (store: IStore) => { - if (isLeavingConferenceManually()) return; + try { + const state = store.getState(); + const roomId = state["features/base/conference"]?.room; - if (reconnectionAttempts >= MAX_RECONNECTION_ATTEMPTS) { - handleMaxAttemptsReached(store); - return; - } + if (!roomId) { + console.error("[AUTO_RECONNECT] No roomId found, cannot leave conference"); + return; + } - reconnectionAttempts++; - isReconnecting = true; - showReconnectionLoader(store, reconnectionAttempts); + console.log("[AUTO_RECONNECT] Leaving conference for reconnection..."); + await store.dispatch(hangup(false, roomId, undefined, false)); + + await new Promise((resolve) => setTimeout(resolve, RECONNECTION_DELAY_MS)); - try { clearRemoteTracks(store); clearExpiredJWT(store); - await new Promise((resolve) => setTimeout(resolve, 100)); - triggerReconnection(store); - scheduleRetry(store); + + console.log("[AUTO_RECONNECT] Rejoining conference..."); + store.dispatch(connect()); + } catch (error) { - console.error("[AUTO_RECONNECT] Reconnection error:", error); - scheduleRetry(store); + console.error("[AUTO_RECONNECT] Leave and rejoin error:", error); + hasReconnected = false; + isReconnecting = false; + hideReconnectionLoader(store); } }; @@ -112,7 +90,7 @@ const clearTimer = () => { const resetReconnectionState = () => { clearTimer(); - reconnectionAttempts = 0; + hasReconnected = false; isReconnecting = false; }; @@ -132,15 +110,14 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA } case CONNECTION_DISCONNECTED: { - if (isLeavingConferenceManually()) break; + if (isLeavingConferenceManually() || hasReconnected) break; clearTimer(); - reconnectionAttempts = 0; isReconnecting = true; reconnectionTimer = window.setTimeout(() => { - if (!isLeavingConferenceManually() && isReconnecting) { - attemptReconnection(store); + if (!isLeavingConferenceManually() && isReconnecting && !hasReconnected) { + leaveAndRejoinConference(store); } }, RECONNECTION_WAIT_TIME_MS); @@ -161,8 +138,8 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA case CONNECTION_FAILED: { const { error } = action; console.log("[AUTO_RECONNECT] Connection failed with error:", error); - if (error?.name === JWT_EXPIRED_ERROR && !isLeavingConferenceManually() && !isReconnecting) { - attemptReconnection(store); + if (error?.name === JWT_EXPIRED_ERROR && !isLeavingConferenceManually() && !isReconnecting && !hasReconnected) { + leaveAndRejoinConference(store); } break; @@ -172,4 +149,4 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA return result; }); -export default {}; +export default {}; \ No newline at end of file From c185f88dc233f12af05342127a082e8fabe7a170 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 13:05:17 +0100 Subject: [PATCH 02/20] re-join the conference --- .../middleware.auto-reconnect.ts | 67 ++++++++++++++----- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 02a12311b77d..2d4980fa945e 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -2,10 +2,12 @@ import { batch } from "react-redux"; import { AnyAction } from "redux"; import { IStore } from "../../../../app/types"; import { hideNotification } from "../../../../notifications/actions"; -import { CONFERENCE_WILL_LEAVE } from "../../../conference/actionTypes"; +import { CONFERENCE_WILL_LEAVE, CONFERENCE_LEFT } from "../../../conference/actionTypes"; +import { createConference } from "../../../conference/actions.any"; import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; import { CONNECTION_DISCONNECTED, CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; -import { connect, hangup } from "../../../connection/actions.web"; +import { disconnect } from "../../../connection/actions.any"; +import { connect } from "../../../connection/actions.web"; import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; import { trackRemoved } from "../../../tracks/actions.any"; @@ -20,6 +22,7 @@ const JWT_EXPIRED_ERROR = "connection.passwordRequired"; let reconnectionTimer: number | null = null; let isReconnecting = false; let hasReconnected = false; +let savedRoomInfo: { room: string; conference: any } | null = null; export const isAutoReconnecting = () => isReconnecting; @@ -27,6 +30,10 @@ const hideReconnectionNotification = (store: IStore) => { store.dispatch(hideNotification(RECONNECTION_NOTIFICATION_ID)); }; +const showReconnectionLoader = (store: IStore) => { + store.dispatch(showLoader(undefined, "loader.reconnecting", RECONNECTION_LOADER_ID)); +}; + const hideReconnectionLoader = (store: IStore) => { store.dispatch(hideLoader(RECONNECTION_LOADER_ID)); }; @@ -46,38 +53,58 @@ const clearRemoteTracks = (store: IStore) => { }); }; +const saveRoomInfo = (store: IStore) => { + const state = store.getState(); + const { room, conference } = state["features/base/conference"]; + + if (room) { + savedRoomInfo = { room, conference }; + console.log("[AUTO_RECONNECT] Saved room info:", room); + } +}; + const leaveAndRejoinConference = async (store: IStore) => { if (isLeavingConferenceManually() || hasReconnected) return; hasReconnected = true; isReconnecting = true; - store.dispatch(showLoader(undefined, "loader.reconnecting", RECONNECTION_LOADER_ID)); + showReconnectionLoader(store); try { - const state = store.getState(); - const roomId = state["features/base/conference"]?.room; + saveRoomInfo(store); - if (!roomId) { - console.error("[AUTO_RECONNECT] No roomId found, cannot leave conference"); + if (!savedRoomInfo?.room) { + console.error("[AUTO_RECONNECT] No room info saved, cannot rejoin"); + hasReconnected = false; + isReconnecting = false; + hideReconnectionLoader(store); return; } - console.log("[AUTO_RECONNECT] Leaving conference for reconnection..."); - await store.dispatch(hangup(false, roomId, undefined, false)); + console.log("[AUTO_RECONNECT] Disconnecting from conference..."); + + await store.dispatch(disconnect()); await new Promise((resolve) => setTimeout(resolve, RECONNECTION_DELAY_MS)); clearRemoteTracks(store); clearExpiredJWT(store); - console.log("[AUTO_RECONNECT] Rejoining conference..."); - store.dispatch(connect()); + console.log("[AUTO_RECONNECT] Reconnecting and rejoining room:", savedRoomInfo.room); + + await store.dispatch(connect()); + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + console.log("[AUTO_RECONNECT] Creating conference for room:", savedRoomInfo.room); + await store.dispatch(createConference()); } catch (error) { console.error("[AUTO_RECONNECT] Leave and rejoin error:", error); hasReconnected = false; isReconnecting = false; hideReconnectionLoader(store); + savedRoomInfo = null; } }; @@ -92,6 +119,7 @@ const resetReconnectionState = () => { clearTimer(); hasReconnected = false; isReconnecting = false; + savedRoomInfo = null; }; /** @@ -102,10 +130,19 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA switch (action.type) { case CONFERENCE_WILL_LEAVE: { - setLeaveConferenceManually(true); - resetReconnectionState(); - hideReconnectionNotification(store); - hideReconnectionLoader(store); + if (!isReconnecting) { + setLeaveConferenceManually(true); + resetReconnectionState(); + hideReconnectionNotification(store); + hideReconnectionLoader(store); + } + break; + } + + case CONFERENCE_LEFT: { + if (!isReconnecting) { + resetReconnectionState(); + } break; } From a132360d62a4597cbb940b93ecb203d99dc94a3c Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 13:46:02 +0100 Subject: [PATCH 03/20] another attempt --- .../middleware.auto-reconnect.ts | 70 ++++++------------- 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 2d4980fa945e..36d83e8d2a34 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -2,8 +2,7 @@ import { batch } from "react-redux"; import { AnyAction } from "redux"; import { IStore } from "../../../../app/types"; import { hideNotification } from "../../../../notifications/actions"; -import { CONFERENCE_WILL_LEAVE, CONFERENCE_LEFT } from "../../../conference/actionTypes"; -import { createConference } from "../../../conference/actions.any"; +import { CONFERENCE_WILL_LEAVE, CONFERENCE_JOINED } from "../../../conference/actionTypes"; import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; import { CONNECTION_DISCONNECTED, CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; import { disconnect } from "../../../connection/actions.any"; @@ -16,13 +15,11 @@ import { hideLoader, showLoader } from "../../loader"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; const RECONNECTION_LOADER_ID = "auto-reconnect"; const RECONNECTION_WAIT_TIME_MS = 15000; -const RECONNECTION_DELAY_MS = 3000; const JWT_EXPIRED_ERROR = "connection.passwordRequired"; let reconnectionTimer: number | null = null; let isReconnecting = false; let hasReconnected = false; -let savedRoomInfo: { room: string; conference: any } | null = null; export const isAutoReconnecting = () => isReconnecting; @@ -53,17 +50,12 @@ const clearRemoteTracks = (store: IStore) => { }); }; -const saveRoomInfo = (store: IStore) => { - const state = store.getState(); - const { room, conference } = state["features/base/conference"]; - - if (room) { - savedRoomInfo = { room, conference }; - console.log("[AUTO_RECONNECT] Saved room info:", room); - } -}; - +/** + * Leaves the conference at the Jitsi library level and rejoins. + * This is done ONCE per disconnection. + */ const leaveAndRejoinConference = async (store: IStore) => { + console.log("[AUTO_RECONNECT] Starting leave and rejoin..."); if (isLeavingConferenceManually() || hasReconnected) return; hasReconnected = true; @@ -71,40 +63,22 @@ const leaveAndRejoinConference = async (store: IStore) => { showReconnectionLoader(store); try { - saveRoomInfo(store); - - if (!savedRoomInfo?.room) { - console.error("[AUTO_RECONNECT] No room info saved, cannot rejoin"); - hasReconnected = false; - isReconnecting = false; - hideReconnectionLoader(store); - return; - } - - console.log("[AUTO_RECONNECT] Disconnecting from conference..."); + console.log("[AUTO_RECONNECT] Leaving conference via disconnect()..."); + + await store.dispatch(disconnect(true)); - await store.dispatch(disconnect()); - - await new Promise((resolve) => setTimeout(resolve, RECONNECTION_DELAY_MS)); - clearRemoteTracks(store); clearExpiredJWT(store); - - console.log("[AUTO_RECONNECT] Reconnecting and rejoining room:", savedRoomInfo.room); + + console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); await store.dispatch(connect()); - - await new Promise((resolve) => setTimeout(resolve, 1000)); - - console.log("[AUTO_RECONNECT] Creating conference for room:", savedRoomInfo.room); - await store.dispatch(createConference()); - + } catch (error) { console.error("[AUTO_RECONNECT] Leave and rejoin error:", error); hasReconnected = false; isReconnecting = false; hideReconnectionLoader(store); - savedRoomInfo = null; } }; @@ -119,7 +93,6 @@ const resetReconnectionState = () => { clearTimer(); hasReconnected = false; isReconnecting = false; - savedRoomInfo = null; }; /** @@ -139,10 +112,14 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA break; } - case CONFERENCE_LEFT: { - if (!isReconnecting) { - resetReconnectionState(); + case CONFERENCE_JOINED: { + if (isReconnecting) { + console.log("[AUTO_RECONNECT] Successfully rejoined conference"); + hideReconnectionNotification(store); + hideReconnectionLoader(store); + setLeaveConferenceManually(false); } + resetReconnectionState(); break; } @@ -162,13 +139,10 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA } case CONNECTION_ESTABLISHED: { - if (isReconnecting) { - hideReconnectionNotification(store); - hideReconnectionLoader(store); + if (!isReconnecting) { + resetReconnectionState(); + setLeaveConferenceManually(false); } - - resetReconnectionState(); - setLeaveConferenceManually(false); break; } From 46b3f0796cbf5fee0af6e196d7d350ae3b6556aa Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 14:50:26 +0100 Subject: [PATCH 04/20] add more logs and local tracks clean up --- react/features/base/connection/actions.any.ts | 3 +++ .../connection-stability/middleware.auto-reconnect.ts | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/react/features/base/connection/actions.any.ts b/react/features/base/connection/actions.any.ts index 9f3c63a68792..ceabc8aa560b 100644 --- a/react/features/base/connection/actions.any.ts +++ b/react/features/base/connection/actions.any.ts @@ -457,6 +457,7 @@ export function disconnect(isRedirect?: boolean, shouldLeave = true) { // Leave the conference. if (conference_) { + console.log("[AUTO_RECONNECT] sending conferenceWillLeave()..."); // In a fashion similar to JitsiConference's CONFERENCE_LEFT event // (and the respective Redux action) which is fired after the // conference has been left, notify the application about the @@ -464,10 +465,12 @@ export function disconnect(isRedirect?: boolean, shouldLeave = true) { dispatch(conferenceWillLeave(conference_, isRedirect)); if (!shouldLeave) { + console.log("[AUTO_RECONNECT] skipping JitsiConference.leave()..."); // we are skipping JitsiConference.leave(), but will still dispatch the normal leave flow events dispatch(conferenceLeft(conference_)); promise = Promise.resolve(); } else { + console.log("[AUTO_RECONNECT] calling JitsiConference.leave()..."); promise = conference_.leave() .catch((error: Error) => { diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 36d83e8d2a34..0e0173b813eb 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -9,7 +9,7 @@ import { disconnect } from "../../../connection/actions.any"; import { connect } from "../../../connection/actions.web"; import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; -import { trackRemoved } from "../../../tracks/actions.any"; +import { trackRemoved, destroyLocalTracks } from "../../../tracks/actions.any"; import { hideLoader, showLoader } from "../../loader"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; @@ -50,6 +50,10 @@ const clearRemoteTracks = (store: IStore) => { }); }; +const clarLocalTracks = (store: IStore) => { + store.dispatch(destroyLocalTracks()); +}; + /** * Leaves the conference at the Jitsi library level and rejoins. * This is done ONCE per disconnection. @@ -69,6 +73,7 @@ const leaveAndRejoinConference = async (store: IStore) => { clearRemoteTracks(store); clearExpiredJWT(store); + clarLocalTracks(store); console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); From 3f031aa90ee6cc9dae11ed7e5b4821938e5d2dcd Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 15:11:04 +0100 Subject: [PATCH 05/20] add logs and direct leave --- .../connection-stability/middleware.auto-reconnect.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 0e0173b813eb..034a42e57294 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -5,7 +5,6 @@ import { hideNotification } from "../../../../notifications/actions"; import { CONFERENCE_WILL_LEAVE, CONFERENCE_JOINED } from "../../../conference/actionTypes"; import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; import { CONNECTION_DISCONNECTED, CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; -import { disconnect } from "../../../connection/actions.any"; import { connect } from "../../../connection/actions.web"; import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; @@ -67,9 +66,15 @@ const leaveAndRejoinConference = async (store: IStore) => { showReconnectionLoader(store); try { - console.log("[AUTO_RECONNECT] Leaving conference via disconnect()..."); + console.log("[AUTO_RECONNECT] Leaving conference via leave()..."); - await store.dispatch(disconnect(true)); + const state = store.getState(); + const { conference } = state['features/base/conference']; + if (!conference) { + console.error("[AUTO_RECONNECT] ERRROR!!!!! No conference found in state, skipping leave.", state); + return; + } + conference.leave(); clearRemoteTracks(store); clearExpiredJWT(store); From e009f1ffba19e98a391e71df51b8fd5ec2738eb1 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 15:30:17 +0100 Subject: [PATCH 06/20] reconnect only in case of failure --- .../middleware.auto-reconnect.ts | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 034a42e57294..fa05fd78cd94 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -66,20 +66,6 @@ const leaveAndRejoinConference = async (store: IStore) => { showReconnectionLoader(store); try { - console.log("[AUTO_RECONNECT] Leaving conference via leave()..."); - - const state = store.getState(); - const { conference } = state['features/base/conference']; - if (!conference) { - console.error("[AUTO_RECONNECT] ERRROR!!!!! No conference found in state, skipping leave.", state); - return; - } - conference.leave(); - - clearRemoteTracks(store); - clearExpiredJWT(store); - clarLocalTracks(store); - console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); await store.dispatch(connect()); @@ -133,21 +119,6 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA break; } - case CONNECTION_DISCONNECTED: { - if (isLeavingConferenceManually() || hasReconnected) break; - - clearTimer(); - isReconnecting = true; - - reconnectionTimer = window.setTimeout(() => { - if (!isLeavingConferenceManually() && isReconnecting && !hasReconnected) { - leaveAndRejoinConference(store); - } - }, RECONNECTION_WAIT_TIME_MS); - - break; - } - case CONNECTION_ESTABLISHED: { if (!isReconnecting) { resetReconnectionState(); From 41426386cb6f0d1c5557ccd88800ce39eb463564 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 15:52:38 +0100 Subject: [PATCH 07/20] try with disconnect --- .../base/connection/middleware.web.ts | 14 ------------ .../middleware.auto-reconnect.ts | 22 +++++++++++++++---- react/features/prejoin/middleware.web.ts | 1 - 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/react/features/base/connection/middleware.web.ts b/react/features/base/connection/middleware.web.ts index a7189a5e0270..47f6db3e3743 100644 --- a/react/features/base/connection/middleware.web.ts +++ b/react/features/base/connection/middleware.web.ts @@ -33,20 +33,6 @@ MiddlewareRegistry.register(({ getState, dispatch }) => (next) => (action) => { setLeaveConferenceManually(true); break; } - - case CONNECTION_DISCONNECTED: { - if (isLeavingConferenceManually()) { - setLeaveConferenceManually(false); - - setTimeout(() => { - dispatch(redirectToStaticPage("/")); - }, 2000); - } else { - console.warn("Connection disconnected unexpectedly - waiting for reconnection"); - } - - break; - } } return next(action); diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index fa05fd78cd94..58796285d71b 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -10,10 +10,10 @@ import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; import { trackRemoved, destroyLocalTracks } from "../../../tracks/actions.any"; import { hideLoader, showLoader } from "../../loader"; +import { disconnect } from "../../../connection/actions.web"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; const RECONNECTION_LOADER_ID = "auto-reconnect"; -const RECONNECTION_WAIT_TIME_MS = 15000; const JWT_EXPIRED_ERROR = "connection.passwordRequired"; let reconnectionTimer: number | null = null; @@ -65,9 +65,23 @@ const leaveAndRejoinConference = async (store: IStore) => { isReconnecting = true; showReconnectionLoader(store); - try { - console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); + try { + const state = store.getState(); + const { conference } = state['features/base/conference']; + if (conference) { + console.log("[AUTO_RECONNECT] Found conference, leaving it."); + await conference.leave(); + clearRemoteTracks(store); + clearExpiredJWT(store); + clarLocalTracks(store); + } else { + console.log("[AUTO_RECONNECT] No conference found in state, skipping leave.", state); + } + + console.log("[AUTO_RECONNECT] Disconnecting via disconnect()..."); + await store.dispatch(disconnect()); + console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); await store.dispatch(connect()); } catch (error) { @@ -126,7 +140,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA } break; } - + case CONNECTION_DISCONNECTED: case CONNECTION_FAILED: { const { error } = action; console.log("[AUTO_RECONNECT] Connection failed with error:", error); diff --git a/react/features/prejoin/middleware.web.ts b/react/features/prejoin/middleware.web.ts index 8f7cfb948b60..89bf729d1cf0 100644 --- a/react/features/prejoin/middleware.web.ts +++ b/react/features/prejoin/middleware.web.ts @@ -69,7 +69,6 @@ MiddlewareRegistry.register(store => next => action => { } case CONFERENCE_FAILED: case CONNECTION_FAILED: - store.dispatch(setJoiningInProgress(false)); break; case CONFERENCE_JOINED: return _conferenceJoined(store, next, action); From af70a647663f380027d548a0adcf753fc342088f Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 16:07:54 +0100 Subject: [PATCH 08/20] remove reconnect on disconnect --- react/features/base/connection/middleware.web.ts | 14 ++++++++++++++ .../middleware.auto-reconnect.ts | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/react/features/base/connection/middleware.web.ts b/react/features/base/connection/middleware.web.ts index 47f6db3e3743..a7189a5e0270 100644 --- a/react/features/base/connection/middleware.web.ts +++ b/react/features/base/connection/middleware.web.ts @@ -33,6 +33,20 @@ MiddlewareRegistry.register(({ getState, dispatch }) => (next) => (action) => { setLeaveConferenceManually(true); break; } + + case CONNECTION_DISCONNECTED: { + if (isLeavingConferenceManually()) { + setLeaveConferenceManually(false); + + setTimeout(() => { + dispatch(redirectToStaticPage("/")); + }, 2000); + } else { + console.warn("Connection disconnected unexpectedly - waiting for reconnection"); + } + + break; + } } return next(action); diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 58796285d71b..44725efb0487 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -140,7 +140,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA } break; } - case CONNECTION_DISCONNECTED: + case CONNECTION_FAILED: { const { error } = action; console.log("[AUTO_RECONNECT] Connection failed with error:", error); From 4d2af5e425df2c31f2b28496220b57417068f36d Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 16:25:22 +0100 Subject: [PATCH 09/20] try to disconnect from connection --- .../middleware.auto-reconnect.ts | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 44725efb0487..f2616008ae95 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -4,13 +4,12 @@ import { IStore } from "../../../../app/types"; import { hideNotification } from "../../../../notifications/actions"; import { CONFERENCE_WILL_LEAVE, CONFERENCE_JOINED } from "../../../conference/actionTypes"; import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; -import { CONNECTION_DISCONNECTED, CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; +import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; import { connect } from "../../../connection/actions.web"; import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; import { trackRemoved, destroyLocalTracks } from "../../../tracks/actions.any"; import { hideLoader, showLoader } from "../../loader"; -import { disconnect } from "../../../connection/actions.web"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; const RECONNECTION_LOADER_ID = "auto-reconnect"; @@ -18,7 +17,6 @@ const JWT_EXPIRED_ERROR = "connection.passwordRequired"; let reconnectionTimer: number | null = null; let isReconnecting = false; -let hasReconnected = false; export const isAutoReconnecting = () => isReconnecting; @@ -59,34 +57,27 @@ const clarLocalTracks = (store: IStore) => { */ const leaveAndRejoinConference = async (store: IStore) => { console.log("[AUTO_RECONNECT] Starting leave and rejoin..."); - if (isLeavingConferenceManually() || hasReconnected) return; + if (isLeavingConferenceManually()) return; - hasReconnected = true; isReconnecting = true; showReconnectionLoader(store); try { const state = store.getState(); - const { conference } = state['features/base/conference']; - if (conference) { - console.log("[AUTO_RECONNECT] Found conference, leaving it."); - await conference.leave(); - clearRemoteTracks(store); - clearExpiredJWT(store); - clarLocalTracks(store); + const connection = state['features/base/connection'].connection; // this exists even if conference is gone + if (connection) { + console.log("[AUTO_RECONNECT] Found connection, leaving it."); + await connection.disconnect(); } else { - console.log("[AUTO_RECONNECT] No conference found in state, skipping leave.", state); + console.log("[AUTO_RECONNECT] No connection found in state, skipping leave.", state); } - - console.log("[AUTO_RECONNECT] Disconnecting via disconnect()..."); - await store.dispatch(disconnect()); + console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); await store.dispatch(connect()); } catch (error) { console.error("[AUTO_RECONNECT] Leave and rejoin error:", error); - hasReconnected = false; isReconnecting = false; hideReconnectionLoader(store); } @@ -101,7 +92,6 @@ const clearTimer = () => { const resetReconnectionState = () => { clearTimer(); - hasReconnected = false; isReconnecting = false; }; @@ -144,7 +134,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA case CONNECTION_FAILED: { const { error } = action; console.log("[AUTO_RECONNECT] Connection failed with error:", error); - if (error?.name === JWT_EXPIRED_ERROR && !isLeavingConferenceManually() && !isReconnecting && !hasReconnected) { + if (error?.name === JWT_EXPIRED_ERROR && !isLeavingConferenceManually() && !isReconnecting) { leaveAndRejoinConference(store); } From 07fbbf10dc8d8d231e5c43789c9c50afa253bc14 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 16:47:12 +0100 Subject: [PATCH 10/20] remove reloadNow --- react/features/app/middleware.ts | 4 +-- .../middleware.auto-reconnect.ts | 25 ++----------------- 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/react/features/app/middleware.ts b/react/features/app/middleware.ts index f2917e4255eb..66ddbbfa7331 100644 --- a/react/features/app/middleware.ts +++ b/react/features/app/middleware.ts @@ -89,11 +89,11 @@ function _connectionEstablished(store: IStore, next: Function, action: AnyAction function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { // In the case of a split-brain error, reload early and prevent further // handling of the action. - if (_isMaybeSplitBrainError(getState, action)) { + /*if (_isMaybeSplitBrainError(getState, action)) { dispatch(reloadNow()); return; - } + }*/ return next(action); } diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index f2616008ae95..f83cd7725291 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -32,25 +32,6 @@ const hideReconnectionLoader = (store: IStore) => { store.dispatch(hideLoader(RECONNECTION_LOADER_ID)); }; -const clearExpiredJWT = (store: IStore) => { - store.dispatch(setJWT(undefined)); -}; - -const clearRemoteTracks = (store: IStore) => { - const state = store.getState(); - const remoteTracks = state["features/base/tracks"].filter((t) => !t.local); - - batch(() => { - for (const track of remoteTracks) { - store.dispatch(trackRemoved(track.jitsiTrack)); - } - }); -}; - -const clarLocalTracks = (store: IStore) => { - store.dispatch(destroyLocalTracks()); -}; - /** * Leaves the conference at the Jitsi library level and rejoins. * This is done ONCE per disconnection. @@ -124,10 +105,8 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA } case CONNECTION_ESTABLISHED: { - if (!isReconnecting) { - resetReconnectionState(); - setLeaveConferenceManually(false); - } + resetReconnectionState(); + setLeaveConferenceManually(false); break; } From ccccb8cb48c61c4360c3e7e3a490c743d5466374 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 16:53:48 +0100 Subject: [PATCH 11/20] add more logs --- react/features/app/middleware.ts | 6 ++++-- react/features/base/conference/middleware.any.ts | 1 + react/features/base/connection/reducer.ts | 1 + react/features/visitors/middleware.ts | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/react/features/app/middleware.ts b/react/features/app/middleware.ts index 66ddbbfa7331..5913de2790e8 100644 --- a/react/features/app/middleware.ts +++ b/react/features/app/middleware.ts @@ -87,13 +87,15 @@ function _connectionEstablished(store: IStore, next: Function, action: AnyAction * @private */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { + console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action:", action); // In the case of a split-brain error, reload early and prevent further // handling of the action. - /*if (_isMaybeSplitBrainError(getState, action)) { + if (_isMaybeSplitBrainError(getState, action)) { + console.log("[AUTO_RECONNECT] ERRROR, calling reloadNow() due to suspected split brain error"); dispatch(reloadNow()); return; - }*/ + } return next(action); } diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index b9df6a6a16ce..49c5c1adc6e0 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -443,6 +443,7 @@ function _logJwtErrors(message: string, errors: string) { * @returns {Object} The value returned by {@code next(action)}. */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { + console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action:", action); const { connection, error } = action; const { jwt } = getState()['features/base/jwt']; diff --git a/react/features/base/connection/reducer.ts b/react/features/base/connection/reducer.ts index bae27ce9e16e..1918881f14f2 100644 --- a/react/features/base/connection/reducer.ts +++ b/react/features/base/connection/reducer.ts @@ -141,6 +141,7 @@ function _connectionFailed( connection: Object; error: ConnectionFailedError; }) { + console.log("[AUTO_RECONNECT] ERRROR Reducing connection failed with error:"); const connection_ = _getCurrentConnection(state); if (connection_ && connection_ !== connection) { diff --git a/react/features/visitors/middleware.ts b/react/features/visitors/middleware.ts index 9cf33d04f32f..4164afaccd66 100644 --- a/react/features/visitors/middleware.ts +++ b/react/features/visitors/middleware.ts @@ -163,6 +163,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { break; } case CONNECTION_FAILED: { + console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action:", action); const { error } = action; if (error?.name !== JitsiConnectionErrors.NOT_LIVE_ERROR) { From 4213a24966f71f640be5aaa3953f780a0a9219cf Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 17:04:38 +0100 Subject: [PATCH 12/20] fix logs --- react/features/app/middleware.ts | 2 +- react/features/base/conference/middleware.any.ts | 2 +- .../connection-stability/middleware.auto-reconnect.ts | 3 --- react/features/visitors/middleware.ts | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/react/features/app/middleware.ts b/react/features/app/middleware.ts index 5913de2790e8..b7ec9f35f294 100644 --- a/react/features/app/middleware.ts +++ b/react/features/app/middleware.ts @@ -87,7 +87,7 @@ function _connectionEstablished(store: IStore, next: Function, action: AnyAction * @private */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { - console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action:", action); + console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action react/features/app/middleware.ts"); // In the case of a split-brain error, reload early and prevent further // handling of the action. if (_isMaybeSplitBrainError(getState, action)) { diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index 49c5c1adc6e0..f743cc069374 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -443,7 +443,7 @@ function _logJwtErrors(message: string, errors: string) { * @returns {Object} The value returned by {@code next(action)}. */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { - console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action:", action); + console.log("[AUTO_RECONNECT] ERRROR, went to react/features/base/conference/middleware.any.ts"); const { connection, error } = action; const { jwt } = getState()['features/base/jwt']; diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index f83cd7725291..8dce0be62949 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -1,4 +1,3 @@ -import { batch } from "react-redux"; import { AnyAction } from "redux"; import { IStore } from "../../../../app/types"; import { hideNotification } from "../../../../notifications/actions"; @@ -6,9 +5,7 @@ import { CONFERENCE_WILL_LEAVE, CONFERENCE_JOINED } from "../../../conference/ac import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; import { connect } from "../../../connection/actions.web"; -import { setJWT } from "../../../jwt/actions"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; -import { trackRemoved, destroyLocalTracks } from "../../../tracks/actions.any"; import { hideLoader, showLoader } from "../../loader"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; diff --git a/react/features/visitors/middleware.ts b/react/features/visitors/middleware.ts index 4164afaccd66..0b27c280c563 100644 --- a/react/features/visitors/middleware.ts +++ b/react/features/visitors/middleware.ts @@ -163,7 +163,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { break; } case CONNECTION_FAILED: { - console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action:", action); + console.log("[AUTO_RECONNECT] ERRROR, went to react/features/visitors/middleware.ts"); const { error } = action; if (error?.name !== JitsiConnectionErrors.NOT_LIVE_ERROR) { From 3b2e02e3e88d7c6291594baa83cf8efcd18f24ca Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 17:36:12 +0100 Subject: [PATCH 13/20] leave on first middleware --- react/features/app/middleware.ts | 44 ++++++++---- .../event-handlers.connection.ts | 6 +- .../middleware.auto-reconnect.ts | 14 ++-- react/features/visitors/middleware.ts | 70 ------------------- 4 files changed, 45 insertions(+), 89 deletions(-) diff --git a/react/features/app/middleware.ts b/react/features/app/middleware.ts index b7ec9f35f294..a7aa1e87c6ac 100644 --- a/react/features/app/middleware.ts +++ b/react/features/app/middleware.ts @@ -8,8 +8,8 @@ import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection/ac import { getURLWithoutParams } from '../base/connection/utils'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { isEmbedded } from '../base/util/embedUtils'; +import { connect } from "../base/connection/actions.web"; -import { reloadNow } from './actions'; import { _getRouteToRender } from './getRouteToRender'; import { IStore } from './types'; @@ -87,17 +87,37 @@ function _connectionEstablished(store: IStore, next: Function, action: AnyAction * @private */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { - console.log("[AUTO_RECONNECT] ERRROR, went to Received connection failed action react/features/app/middleware.ts"); - // In the case of a split-brain error, reload early and prevent further - // handling of the action. - if (_isMaybeSplitBrainError(getState, action)) { - console.log("[AUTO_RECONNECT] ERRROR, calling reloadNow() due to suspected split brain error"); - dispatch(reloadNow()); - - return; - } - - return next(action); + console.log("[AUTO_RECONNECT] ERRROR, went to connection failed react/features/app/middleware.ts"); + + const state = getState(); + + // FIX: Capture connection/conference BEFORE calling next() + const connection = state['features/base/connection'].connection; + const conference = state['features/base/conference'].conference; + + // FIX: Auto-reconnect on ANY connection failure + (async () => { + try { + if (conference) { + console.log("[AUTO_RECONNECT] Leaving conference"); + await conference.leave(); + } + if (connection) { + console.log("[AUTO_RECONNECT] Disconnecting connection"); + await connection.disconnect(); + } + + next(action); + + console.log("[AUTO_RECONNECT] Reconnecting"); + await dispatch(connect()); + } catch (err) { + console.error("[AUTO_RECONNECT] Reconnect failed:", err); + next(action); + } + })(); + + return; } /** diff --git a/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts b/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts index 7bff10440763..429617d1b129 100644 --- a/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts +++ b/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts @@ -1,6 +1,6 @@ import { IStore } from '../../../../../app/types'; import { isLeavingConferenceManually } from "../../../general/utils/conferenceState"; -import { isAutoReconnecting } from "../middleware.auto-reconnect"; +//import { isAutoReconnecting } from "../middleware.auto-reconnect"; import { showConnectionFailedNotification, showConnectionLostNotification } from "./notification-helpers"; /** @@ -22,7 +22,7 @@ export const handleXMPPDisconnected = (dispatch: IStore["dispatch"], message: st console.log("[CONNECTION_NOTIFICATIONS] XMPP disconnected:", message); if (isLeavingConferenceManually()) return; - if (isAutoReconnecting()) return; + //if (isAutoReconnecting()) return; showConnectionLostNotification(dispatch); }; @@ -37,7 +37,7 @@ export const handleXMPPDisconnected = (dispatch: IStore["dispatch"], message: st */ export const handleXMPPConnectionFailed = (dispatch: IStore["dispatch"], error: any, message: string) => { console.error("[CONNECTION_NOTIFICATIONS] XMPP connection failed:", error, message); - if (isAutoReconnecting()) return; + //if (isAutoReconnecting()) return; showConnectionFailedNotification(dispatch, message); }; diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 8dce0be62949..74a1d6227886 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -42,12 +42,18 @@ const leaveAndRejoinConference = async (store: IStore) => { try { const state = store.getState(); - const connection = state['features/base/connection'].connection; // this exists even if conference is gone + + const conference = state['features/base/conference'].conference; + const connection = state['features/base/connection'].connection; + + if (conference) { + console.log("[AUTO_RECONNECT] Found conference, leaving it."); + await conference.leave(); + } + if (connection) { - console.log("[AUTO_RECONNECT] Found connection, leaving it."); + console.log("[AUTO_RECONNECT] Found connection, disconnecting it."); await connection.disconnect(); - } else { - console.log("[AUTO_RECONNECT] No connection found in state, skipping leave.", state); } diff --git a/react/features/visitors/middleware.ts b/react/features/visitors/middleware.ts index 0b27c280c563..106c5cd4029d 100644 --- a/react/features/visitors/middleware.ts +++ b/react/features/visitors/middleware.ts @@ -162,76 +162,6 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { } break; } - case CONNECTION_FAILED: { - console.log("[AUTO_RECONNECT] ERRROR, went to react/features/visitors/middleware.ts"); - const { error } = action; - - if (error?.name !== JitsiConnectionErrors.NOT_LIVE_ERROR) { - break; - } - - const { hosts, visitors: visitorsConfig } = getState()['features/base/config']; - const { locationURL } = getState()['features/base/connection']; - - if (!visitorsConfig?.queueService || !locationURL) { - break; - } - - // let's subscribe for visitor waiting queue - const { room } = getState()['features/base/conference']; - const { disableBeforeUnloadHandlers = false } = getState()['features/base/config']; - const conferenceJid = `${room}@${hosts?.muc}`; - const beforeUnloadHandler = () => { - WebsocketClient.getInstance().disconnect(); - }; - - WebsocketClient.getInstance() - .connect(`wss://${visitorsConfig?.queueService}/visitor/websocket`, - `/secured/conference/visitor/topic.${conferenceJid}`, - msg => { - if ('status' in msg && msg.status === 'live') { - logger.info('The conference is now live!'); - - - WebsocketClient.getInstance().disconnect() - .then(() => { - window.removeEventListener( - disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', - beforeUnloadHandler); - let delay = 0; - - // now let's connect to meeting - if ('randomDelayMs' in msg) { - delay = msg.randomDelayMs; - } - - if (WebsocketClient.getInstance().connectCount > 3) { - // if we keep connecting/disconnecting, let's slow it down - delay = 30 * 1000; - } - - setTimeout(() => { - logger.info('Dispatching joinConference on conference live event.'); - dispatch(joinConference()); - dispatch(setInVisitorsQueue(false)); - }, Math.random() * delay); - }); - } - }, - - getState()['features/base/jwt'].jwt, - () => { - dispatch(setInVisitorsQueue(true)); - }); - - /** - * Disconnecting the WebSocket client when the user closes the page. - */ - window.addEventListener(disableBeforeUnloadHandlers ? 'unload' : 'beforeunload', beforeUnloadHandler); - - - break; - } case PARTICIPANT_UPDATED: { const { metadata } = getState()['features/base/conference']; From 0910da6bf4a17c28a78c39be5ee2326184bae72d Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 17:48:47 +0100 Subject: [PATCH 14/20] keep middleware --- react/features/app/middleware.ts | 9 +--- .../event-handlers.connection.ts | 6 +-- .../middleware.auto-reconnect.ts | 46 +------------------ 3 files changed, 7 insertions(+), 54 deletions(-) diff --git a/react/features/app/middleware.ts b/react/features/app/middleware.ts index a7aa1e87c6ac..d80a7e713c2c 100644 --- a/react/features/app/middleware.ts +++ b/react/features/app/middleware.ts @@ -8,7 +8,6 @@ import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from '../base/connection/ac import { getURLWithoutParams } from '../base/connection/utils'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { isEmbedded } from '../base/util/embedUtils'; -import { connect } from "../base/connection/actions.web"; import { _getRouteToRender } from './getRouteToRender'; import { IStore } from './types'; @@ -90,12 +89,10 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio console.log("[AUTO_RECONNECT] ERRROR, went to connection failed react/features/app/middleware.ts"); const state = getState(); - - // FIX: Capture connection/conference BEFORE calling next() + const connection = state['features/base/connection'].connection; const conference = state['features/base/conference'].conference; - // FIX: Auto-reconnect on ANY connection failure (async () => { try { if (conference) { @@ -109,10 +106,8 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio next(action); - console.log("[AUTO_RECONNECT] Reconnecting"); - await dispatch(connect()); } catch (err) { - console.error("[AUTO_RECONNECT] Reconnect failed:", err); + console.error("[AUTO_RECONNECT] _connectionFailed failed:", err); next(action); } })(); diff --git a/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts b/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts index 429617d1b129..7bff10440763 100644 --- a/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts +++ b/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts @@ -1,6 +1,6 @@ import { IStore } from '../../../../../app/types'; import { isLeavingConferenceManually } from "../../../general/utils/conferenceState"; -//import { isAutoReconnecting } from "../middleware.auto-reconnect"; +import { isAutoReconnecting } from "../middleware.auto-reconnect"; import { showConnectionFailedNotification, showConnectionLostNotification } from "./notification-helpers"; /** @@ -22,7 +22,7 @@ export const handleXMPPDisconnected = (dispatch: IStore["dispatch"], message: st console.log("[CONNECTION_NOTIFICATIONS] XMPP disconnected:", message); if (isLeavingConferenceManually()) return; - //if (isAutoReconnecting()) return; + if (isAutoReconnecting()) return; showConnectionLostNotification(dispatch); }; @@ -37,7 +37,7 @@ export const handleXMPPDisconnected = (dispatch: IStore["dispatch"], message: st */ export const handleXMPPConnectionFailed = (dispatch: IStore["dispatch"], error: any, message: string) => { console.error("[CONNECTION_NOTIFICATIONS] XMPP connection failed:", error, message); - //if (isAutoReconnecting()) return; + if (isAutoReconnecting()) return; showConnectionFailedNotification(dispatch, message); }; diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts index 74a1d6227886..b24f30e7179f 100644 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts @@ -6,7 +6,7 @@ import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../g import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; import { connect } from "../../../connection/actions.web"; import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; -import { hideLoader, showLoader } from "../../loader"; +import { hideLoader } from "../../loader"; const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; const RECONNECTION_LOADER_ID = "auto-reconnect"; @@ -21,52 +21,10 @@ const hideReconnectionNotification = (store: IStore) => { store.dispatch(hideNotification(RECONNECTION_NOTIFICATION_ID)); }; -const showReconnectionLoader = (store: IStore) => { - store.dispatch(showLoader(undefined, "loader.reconnecting", RECONNECTION_LOADER_ID)); -}; - const hideReconnectionLoader = (store: IStore) => { store.dispatch(hideLoader(RECONNECTION_LOADER_ID)); }; -/** - * Leaves the conference at the Jitsi library level and rejoins. - * This is done ONCE per disconnection. - */ -const leaveAndRejoinConference = async (store: IStore) => { - console.log("[AUTO_RECONNECT] Starting leave and rejoin..."); - if (isLeavingConferenceManually()) return; - - isReconnecting = true; - showReconnectionLoader(store); - - try { - const state = store.getState(); - - const conference = state['features/base/conference'].conference; - const connection = state['features/base/connection'].connection; - - if (conference) { - console.log("[AUTO_RECONNECT] Found conference, leaving it."); - await conference.leave(); - } - - if (connection) { - console.log("[AUTO_RECONNECT] Found connection, disconnecting it."); - await connection.disconnect(); - } - - - console.log("[AUTO_RECONNECT] Rejoining conference via connect()..."); - await store.dispatch(connect()); - - } catch (error) { - console.error("[AUTO_RECONNECT] Leave and rejoin error:", error); - isReconnecting = false; - hideReconnectionLoader(store); - } -}; - const clearTimer = () => { if (reconnectionTimer !== null) { clearTimeout(reconnectionTimer); @@ -117,7 +75,7 @@ MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyA const { error } = action; console.log("[AUTO_RECONNECT] Connection failed with error:", error); if (error?.name === JWT_EXPIRED_ERROR && !isLeavingConferenceManually() && !isReconnecting) { - leaveAndRejoinConference(store); + store.dispatch(connect()); } break; From da8693d4b16fe1066053e676d43bcfe0a3e61fd5 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 17:51:32 +0100 Subject: [PATCH 15/20] revert some files --- react/features/base/connection/actions.any.ts | 3 --- react/features/base/connection/reducer.ts | 1 - react/features/prejoin/middleware.web.ts | 1 + 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/react/features/base/connection/actions.any.ts b/react/features/base/connection/actions.any.ts index ceabc8aa560b..9f3c63a68792 100644 --- a/react/features/base/connection/actions.any.ts +++ b/react/features/base/connection/actions.any.ts @@ -457,7 +457,6 @@ export function disconnect(isRedirect?: boolean, shouldLeave = true) { // Leave the conference. if (conference_) { - console.log("[AUTO_RECONNECT] sending conferenceWillLeave()..."); // In a fashion similar to JitsiConference's CONFERENCE_LEFT event // (and the respective Redux action) which is fired after the // conference has been left, notify the application about the @@ -465,12 +464,10 @@ export function disconnect(isRedirect?: boolean, shouldLeave = true) { dispatch(conferenceWillLeave(conference_, isRedirect)); if (!shouldLeave) { - console.log("[AUTO_RECONNECT] skipping JitsiConference.leave()..."); // we are skipping JitsiConference.leave(), but will still dispatch the normal leave flow events dispatch(conferenceLeft(conference_)); promise = Promise.resolve(); } else { - console.log("[AUTO_RECONNECT] calling JitsiConference.leave()..."); promise = conference_.leave() .catch((error: Error) => { diff --git a/react/features/base/connection/reducer.ts b/react/features/base/connection/reducer.ts index 1918881f14f2..bae27ce9e16e 100644 --- a/react/features/base/connection/reducer.ts +++ b/react/features/base/connection/reducer.ts @@ -141,7 +141,6 @@ function _connectionFailed( connection: Object; error: ConnectionFailedError; }) { - console.log("[AUTO_RECONNECT] ERRROR Reducing connection failed with error:"); const connection_ = _getCurrentConnection(state); if (connection_ && connection_ !== connection) { diff --git a/react/features/prejoin/middleware.web.ts b/react/features/prejoin/middleware.web.ts index 89bf729d1cf0..8f7cfb948b60 100644 --- a/react/features/prejoin/middleware.web.ts +++ b/react/features/prejoin/middleware.web.ts @@ -69,6 +69,7 @@ MiddlewareRegistry.register(store => next => action => { } case CONFERENCE_FAILED: case CONNECTION_FAILED: + store.dispatch(setJoiningInProgress(false)); break; case CONFERENCE_JOINED: return _conferenceJoined(store, next, action); From cd0856dc1dac5f072d2016a1b7b800d247368af6 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 18:07:51 +0100 Subject: [PATCH 16/20] put cleanup in another middleware --- react/features/app/middleware.ts | 35 ++----- .../base/conference/middleware.any.ts | 98 ++++--------------- 2 files changed, 30 insertions(+), 103 deletions(-) diff --git a/react/features/app/middleware.ts b/react/features/app/middleware.ts index d80a7e713c2c..f2917e4255eb 100644 --- a/react/features/app/middleware.ts +++ b/react/features/app/middleware.ts @@ -9,6 +9,7 @@ import { getURLWithoutParams } from '../base/connection/utils'; import MiddlewareRegistry from '../base/redux/MiddlewareRegistry'; import { isEmbedded } from '../base/util/embedUtils'; +import { reloadNow } from './actions'; import { _getRouteToRender } from './getRouteToRender'; import { IStore } from './types'; @@ -86,33 +87,15 @@ function _connectionEstablished(store: IStore, next: Function, action: AnyAction * @private */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { - console.log("[AUTO_RECONNECT] ERRROR, went to connection failed react/features/app/middleware.ts"); - - const state = getState(); + // In the case of a split-brain error, reload early and prevent further + // handling of the action. + if (_isMaybeSplitBrainError(getState, action)) { + dispatch(reloadNow()); - const connection = state['features/base/connection'].connection; - const conference = state['features/base/conference'].conference; - - (async () => { - try { - if (conference) { - console.log("[AUTO_RECONNECT] Leaving conference"); - await conference.leave(); - } - if (connection) { - console.log("[AUTO_RECONNECT] Disconnecting connection"); - await connection.disconnect(); - } - - next(action); - - } catch (err) { - console.error("[AUTO_RECONNECT] _connectionFailed failed:", err); - next(action); - } - })(); - - return; + return; + } + + return next(action); } /** diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index f743cc069374..2cdd5fda4b79 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -443,85 +443,29 @@ function _logJwtErrors(message: string, errors: string) { * @returns {Object} The value returned by {@code next(action)}. */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { - console.log("[AUTO_RECONNECT] ERRROR, went to react/features/base/conference/middleware.any.ts"); - const { connection, error } = action; - const { jwt } = getState()['features/base/jwt']; - - if (jwt) { - const errors: string = validateJwt(jwt).map((err: any) => - i18n.t(`dialog.tokenAuthFailedReason.${err.key}`, err.args)) - .join(' '); - - _logJwtErrors(error.message, errors); - - // do not show the notification when we will prompt the user - // for username and password - if (error.name === JitsiConnectionErrors.PASSWORD_REQUIRED) { - dispatch(showErrorNotification({ - descriptionKey: errors ? 'dialog.tokenAuthFailedWithReasons' : 'dialog.tokenAuthFailed', - descriptionArguments: { reason: errors }, - titleKey: 'dialog.tokenAuthFailedTitle' - })); - } - } - - if (error.name === JitsiConnectionErrors.CONFERENCE_REQUEST_FAILED) { - let notificationAction: Function = showNotification; - const notificationProps = { - customActionNameKey: [ 'dialog.rejoinNow' ], - customActionHandler: [ () => dispatch(reloadNow()) ], - descriptionKey: 'notify.connectionFailed' - } as INotificationProps; - - const { locationURL = { href: '' } as URL } = getState()['features/base/connection']; - const { tenant = '' } = parseURIString(locationURL.href) || {}; - - if (tenant.startsWith('-') || tenant.endsWith('-')) { - notificationProps.descriptionKey = 'notify.invalidTenantHyphenDescription'; - notificationProps.titleKey = 'notify.invalidTenant'; - notificationAction = showErrorNotification; - } else if (tenant.length > 63) { - notificationProps.descriptionKey = 'notify.invalidTenantLengthDescription'; - notificationProps.titleKey = 'notify.invalidTenant'; - notificationAction = showErrorNotification; - } - - dispatch(notificationAction(notificationProps, NOTIFICATION_TIMEOUT_TYPE.STICKY)); - } - - const result = next(action); - - _removeUnloadHandler(getState); - - forEachConference(getState, conference => { - // TODO: revisit this - // It feels that it would make things easier if JitsiConference - // in lib-jitsi-meet would monitor it's connection and emit - // CONFERENCE_FAILED when it's dropped. It has more knowledge on - // whether it can recover or not. But because the reload screen - // and the retry logic is implemented in the app maybe it can be - // left this way for now. - if (conference.getConnection() === connection) { - // XXX Note that on mobile the error type passed to - // connectionFailed is always an object with .name property. - // This fact needs to be checked prior to enabling this logic on - // web. - const conferenceAction = conferenceFailed(conference, error.name); - - // Copy the recoverable flag if set on the CONNECTION_FAILED - // action to not emit recoverable action caused by - // a non-recoverable one. - if (typeof error.recoverable !== 'undefined') { - conferenceAction.error.recoverable = error.recoverable; + const state = getState(); + + const connection = state['features/base/connection'].connection; + const conference = state['features/base/conference'].conference; + + (async () => { + try { + if (conference) { + console.log("[AUTO_RECONNECT] Leaving conference"); + await conference.leave(); } - - dispatch(conferenceAction); + if (connection) { + console.log("[AUTO_RECONNECT] Disconnecting connection"); + await connection.disconnect(); + } + + + } catch (err) { + console.error("[AUTO_RECONNECT] _connectionFailed failed:", err); + } - - return true; - }); - - return result; + })(); + return next(action); } /** From bc2ec00d53b2edecb51cac48e11892cd03171d41 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 18:26:36 +0100 Subject: [PATCH 17/20] remove middleware --- react/features/authentication/middleware.ts | 18 ---- .../base/conference/middleware.any.ts | 5 +- .../event-handlers.connection.ts | 3 - .../middlewares/connection-stability/index.ts | 1 - .../middleware.auto-reconnect.ts | 88 ------------------- 5 files changed, 3 insertions(+), 112 deletions(-) delete mode 100644 react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts diff --git a/react/features/authentication/middleware.ts b/react/features/authentication/middleware.ts index b4ca7f310609..ccbec0c35317 100644 --- a/react/features/authentication/middleware.ts +++ b/react/features/authentication/middleware.ts @@ -157,24 +157,6 @@ MiddlewareRegistry.register(store => next => action => { store.dispatch(hideLoginDialog()); break; - case CONNECTION_FAILED: { - const { error } = action; - const { getState } = store; - const state = getState(); - const { jwt } = state['features/base/jwt']; - - if (error - && error.name === JitsiConnectionErrors.PASSWORD_REQUIRED - && typeof error.recoverable === 'undefined' - && !jwt) { - error.recoverable = true; - - _handleLogin(store); - } - - break; - } - case LOGIN: { _handleLogin(store); diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index 2cdd5fda4b79..91e2aa66a89a 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -443,7 +443,8 @@ function _logJwtErrors(message: string, errors: string) { * @returns {Object} The value returned by {@code next(action)}. */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { - const state = getState(); + console.log("[AUTO_RECONNECT] entered _connectionFailed middleware"); + const state = getState(); const connection = state['features/base/connection'].connection; const conference = state['features/base/conference'].conference; @@ -458,7 +459,7 @@ function _connectionFailed({ dispatch, getState }: IStore, next: Function, actio console.log("[AUTO_RECONNECT] Disconnecting connection"); await connection.disconnect(); } - + dispatch(connect()); } catch (err) { console.error("[AUTO_RECONNECT] _connectionFailed failed:", err); diff --git a/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts b/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts index 7bff10440763..16110c011ce5 100644 --- a/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts +++ b/react/features/base/meet/middlewares/connection-stability/connection-notifications/event-handlers.connection.ts @@ -1,6 +1,5 @@ import { IStore } from '../../../../../app/types'; import { isLeavingConferenceManually } from "../../../general/utils/conferenceState"; -import { isAutoReconnecting } from "../middleware.auto-reconnect"; import { showConnectionFailedNotification, showConnectionLostNotification } from "./notification-helpers"; /** @@ -22,7 +21,6 @@ export const handleXMPPDisconnected = (dispatch: IStore["dispatch"], message: st console.log("[CONNECTION_NOTIFICATIONS] XMPP disconnected:", message); if (isLeavingConferenceManually()) return; - if (isAutoReconnecting()) return; showConnectionLostNotification(dispatch); }; @@ -37,7 +35,6 @@ export const handleXMPPDisconnected = (dispatch: IStore["dispatch"], message: st */ export const handleXMPPConnectionFailed = (dispatch: IStore["dispatch"], error: any, message: string) => { console.error("[CONNECTION_NOTIFICATIONS] XMPP connection failed:", error, message); - if (isAutoReconnecting()) return; showConnectionFailedNotification(dispatch, message); }; diff --git a/react/features/base/meet/middlewares/connection-stability/index.ts b/react/features/base/meet/middlewares/connection-stability/index.ts index bacad5c7140c..c260460526a7 100644 --- a/react/features/base/meet/middlewares/connection-stability/index.ts +++ b/react/features/base/meet/middlewares/connection-stability/index.ts @@ -13,7 +13,6 @@ import './connection-notifications'; import './middleware.datachannel'; import './middleware.error-handling'; import './middleware.poor-connection'; -import './middleware.auto-reconnect'; export { }; diff --git a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts b/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts deleted file mode 100644 index b24f30e7179f..000000000000 --- a/react/features/base/meet/middlewares/connection-stability/middleware.auto-reconnect.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { AnyAction } from "redux"; -import { IStore } from "../../../../app/types"; -import { hideNotification } from "../../../../notifications/actions"; -import { CONFERENCE_WILL_LEAVE, CONFERENCE_JOINED } from "../../../conference/actionTypes"; -import { isLeavingConferenceManually, setLeaveConferenceManually } from "../../general/utils/conferenceState"; -import { CONNECTION_ESTABLISHED, CONNECTION_FAILED } from "../../../connection/actionTypes"; -import { connect } from "../../../connection/actions.web"; -import MiddlewareRegistry from "../../../redux/MiddlewareRegistry"; -import { hideLoader } from "../../loader"; - -const RECONNECTION_NOTIFICATION_ID = "connection.reconnecting"; -const RECONNECTION_LOADER_ID = "auto-reconnect"; -const JWT_EXPIRED_ERROR = "connection.passwordRequired"; - -let reconnectionTimer: number | null = null; -let isReconnecting = false; - -export const isAutoReconnecting = () => isReconnecting; - -const hideReconnectionNotification = (store: IStore) => { - store.dispatch(hideNotification(RECONNECTION_NOTIFICATION_ID)); -}; - -const hideReconnectionLoader = (store: IStore) => { - store.dispatch(hideLoader(RECONNECTION_LOADER_ID)); -}; - -const clearTimer = () => { - if (reconnectionTimer !== null) { - clearTimeout(reconnectionTimer); - reconnectionTimer = null; - } -}; - -const resetReconnectionState = () => { - clearTimer(); - isReconnecting = false; -}; - -/** - * Middleware that handles automatic reconnection when JWT expires or connection is lost. - */ -MiddlewareRegistry.register((store: IStore) => (next: Function) => (action: AnyAction) => { - const result = next(action); - - switch (action.type) { - case CONFERENCE_WILL_LEAVE: { - if (!isReconnecting) { - setLeaveConferenceManually(true); - resetReconnectionState(); - hideReconnectionNotification(store); - hideReconnectionLoader(store); - } - break; - } - - case CONFERENCE_JOINED: { - if (isReconnecting) { - console.log("[AUTO_RECONNECT] Successfully rejoined conference"); - hideReconnectionNotification(store); - hideReconnectionLoader(store); - setLeaveConferenceManually(false); - } - resetReconnectionState(); - break; - } - - case CONNECTION_ESTABLISHED: { - resetReconnectionState(); - setLeaveConferenceManually(false); - break; - } - - case CONNECTION_FAILED: { - const { error } = action; - console.log("[AUTO_RECONNECT] Connection failed with error:", error); - if (error?.name === JWT_EXPIRED_ERROR && !isLeavingConferenceManually() && !isReconnecting) { - store.dispatch(connect()); - } - - break; - } - } - - return result; -}); - -export default {}; \ No newline at end of file From a142db19b198cb32e7c88206a50d8db150fba9b5 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 18:49:37 +0100 Subject: [PATCH 18/20] disconnect first --- .../base/conference/middleware.any.ts | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index 91e2aa66a89a..0e43193b0eca 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -443,30 +443,25 @@ function _logJwtErrors(message: string, errors: string) { * @returns {Object} The value returned by {@code next(action)}. */ function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { + console.log("[AUTO_RECONNECT] entered _connectionFailed middleware"); - const state = getState(); - - const connection = state['features/base/connection'].connection; - const conference = state['features/base/conference'].conference; - + const { conference } = getState()['features/base/conference']; (async () => { try { if (conference) { - console.log("[AUTO_RECONNECT] Leaving conference"); - await conference.leave(); - } - if (connection) { - console.log("[AUTO_RECONNECT] Disconnecting connection"); - await connection.disconnect(); + conference.leave() + .then(() => dispatch(disconnect())); } - dispatch(connect()); + + next(action); + + return dispatch(connect()); } catch (err) { console.error("[AUTO_RECONNECT] _connectionFailed failed:", err); } })(); - return next(action); } /** From 862e98683ef61d427f37f10244755f82e27c9e1c Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Fri, 6 Feb 2026 18:51:51 +0100 Subject: [PATCH 19/20] use connection --- react/features/base/conference/middleware.any.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/react/features/base/conference/middleware.any.ts b/react/features/base/conference/middleware.any.ts index 0e43193b0eca..d2d0db80c9ed 100644 --- a/react/features/base/conference/middleware.any.ts +++ b/react/features/base/conference/middleware.any.ts @@ -445,16 +445,24 @@ function _logJwtErrors(message: string, errors: string) { function _connectionFailed({ dispatch, getState }: IStore, next: Function, action: AnyAction) { console.log("[AUTO_RECONNECT] entered _connectionFailed middleware"); - const { conference } = getState()['features/base/conference']; + const { connection } = action; + const state = getState(); + const conference = state['features/base/conference'].conference; (async () => { try { if (conference) { - conference.leave() - .then(() => dispatch(disconnect())); + console.log("[AUTO_RECONNECT] Leaving conference"); + dispatch(conferenceWillLeave(conference)); + await conference.leave(); + } + + if (connection) { + console.log("[AUTO_RECONNECT] Disconnecting connection"); + await connection.disconnect(); } next(action); - + console.log("[AUTO_RECONNECT] Start new connection"); return dispatch(connect()); } catch (err) { From af1d277694b3fa3b7b63cd32258ee01897541ef7 Mon Sep 17 00:00:00 2001 From: tamarafinogina Date: Mon, 9 Feb 2026 09:47:24 +0100 Subject: [PATCH 20/20] disactivate decoder --- .../base/meet/views/Conference/components/VideoParticipant.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/features/base/meet/views/Conference/components/VideoParticipant.tsx b/react/features/base/meet/views/Conference/components/VideoParticipant.tsx index 207c79325663..f66794c611ca 100644 --- a/react/features/base/meet/views/Conference/components/VideoParticipant.tsx +++ b/react/features/base/meet/views/Conference/components/VideoParticipant.tsx @@ -49,7 +49,7 @@ const VideoParticipant = ({ )} key={`video-${id}`} // Set to false due to decoding issues and video lag - encodeVideo={true} + encodeVideo={false} /> ) : (