Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
"js-md5": "0.6.1",
"js-sha512": "0.8.0",
"jwt-decode": "2.2.0",
"lib-jitsi-meet": "https://github.com/internxt/lib-jitsi-meet/releases/download/v.0.0.20/lib-jitsi-meet-0.0.20.tgz",
"lib-jitsi-meet": "https://github.com/internxt/lib-jitsi-meet/releases/download/v.0.0.20-debug/lib-jitsi-meet-0.0.20-debug.tgz",
"lodash-es": "4.17.23",
"moment": "2.29.4",
"moment-duration-format": "2.2.2",
Expand Down
Original file line number Diff line number Diff line change
@@ -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";

/**
Expand All @@ -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);
};
Expand All @@ -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);
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { CONFERENCE_JOINED, CONFERENCE_WILL_LEAVE } from '../../../../conference
import { setLeaveConferenceManually } from '../../../general/utils/conferenceState';
import { CONNECTION_WILL_CONNECT } from '../../../../connection/actionTypes';
import MiddlewareRegistry from '../../../../redux/MiddlewareRegistry';
import { setupConferenceMediaListeners, setupXMPPConnectionListeners } from './listener-setup';
import {
removeConferenceMediaListeners,
removeXMPPConnectionListeners,
setupConferenceMediaListeners,
setupXMPPConnectionListeners
} from './listener-setup';
import { createConnectionState } from './state';

/**
Expand All @@ -24,6 +29,7 @@ MiddlewareRegistry.register(({ dispatch }: IStore) => {

switch (action.type) {
case CONNECTION_WILL_CONNECT: {
console.log("[CONNECTION_NOTIFICATIONS] CONNECTION_WILL_CONNECT - Setting up XMPP listeners");
setLeaveConferenceManually(false);
connectionState.hasConnectionListeners = false;

Expand All @@ -34,16 +40,19 @@ MiddlewareRegistry.register(({ dispatch }: IStore) => {
}

case CONFERENCE_JOINED: {
console.log("[CONNECTION_NOTIFICATIONS] CONFERENCE_JOINED - Setting up media listeners");
const { conference } = action;

setupConferenceMediaListeners(conference, dispatch, connectionState);
break;
}

case CONFERENCE_WILL_LEAVE: {
// User clicked hangup button - don't show reconnection notifications
console.log("[CONNECTION_NOTIFICATIONS] CONFERENCE_WILL_LEAVE - Cleaning up all listeners");
// User clicked hangup button - cleanup listeners to prevent memory leaks
removeConferenceMediaListeners(connectionState);
removeXMPPConnectionListeners(connectionState);
setLeaveConferenceManually(true);
connectionState.hasConferenceListeners = false;
connectionState.wasMediaConnectionInterrupted = false;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,65 @@ export const setupConferenceMediaListeners = (
state: ConnectionState
) => {
if (state.hasConferenceListeners || !conference) {
console.log("[LISTENER_SETUP] Skipping conference media listeners setup", {
alreadyHasListeners: state.hasConferenceListeners,
noConference: !conference
});
return;
}

conference.addEventListener(JitsiConferenceEvents.CONNECTION_INTERRUPTED, () =>
handleMediaConnectionInterrupted(dispatch, state)
);
console.log("[LISTENER_SETUP] Setting up conference media listeners (ICE events)");

conference.addEventListener(JitsiConferenceEvents.CONNECTION_RESTORED, () =>
handleMediaConnectionRestored(dispatch, state)
);
const interruptedHandler = () => handleMediaConnectionInterrupted(dispatch, state);
const restoredHandler = () => handleMediaConnectionRestored(dispatch, state);
const suspendHandler = () => handleDeviceSuspended(dispatch);

conference.addEventListener(JitsiConferenceEvents.SUSPEND_DETECTED, () => handleDeviceSuspended(dispatch));
conference.addEventListener(JitsiConferenceEvents.CONNECTION_INTERRUPTED, interruptedHandler);
conference.addEventListener(JitsiConferenceEvents.CONNECTION_RESTORED, restoredHandler);
conference.addEventListener(JitsiConferenceEvents.SUSPEND_DETECTED, suspendHandler);

state.conferenceHandlers = {
interruptedHandler,
restoredHandler,
suspendHandler
};
state.conferenceRef = conference;
state.hasConferenceListeners = true;
console.log("[LISTENER_SETUP] Conference media listeners registered successfully");
};

/**
* Removes event listeners for conference media connection events
*
* @param state - Connection state containing handler references
*/
export const removeConferenceMediaListeners = (state: ConnectionState) => {
if (!state.conferenceRef || !state.conferenceHandlers) {
console.log("[LISTENER_SETUP] Skipping conference media listeners removal - no refs");
return;
}

console.log("[LISTENER_SETUP] Removing conference media listeners");

const { conferenceRef, conferenceHandlers } = state;

conferenceRef.removeEventListener(
JitsiConferenceEvents.CONNECTION_INTERRUPTED,
conferenceHandlers.interruptedHandler
);
conferenceRef.removeEventListener(
JitsiConferenceEvents.CONNECTION_RESTORED,
conferenceHandlers.restoredHandler
);
conferenceRef.removeEventListener(
JitsiConferenceEvents.SUSPEND_DETECTED,
conferenceHandlers.suspendHandler
);

state.conferenceHandlers = undefined;
state.conferenceRef = undefined;
state.hasConferenceListeners = false;
console.log("[LISTENER_SETUP] Conference media listeners removed successfully");
};

/**
Expand All @@ -52,18 +97,63 @@ export const setupConferenceMediaListeners = (
*/
export const setupXMPPConnectionListeners = (connection: any, dispatch: IStore["dispatch"], state: ConnectionState) => {
if (!connection || state.hasConnectionListeners) {
console.log("[LISTENER_SETUP] Skipping XMPP listeners setup", {
noConnection: !connection,
alreadyHasListeners: state.hasConnectionListeners
});
return;
}

connection.addEventListener(JitsiConnectionEvents.CONNECTION_ESTABLISHED, () => handleXMPPConnected());
console.log("[LISTENER_SETUP] Setting up XMPP connection listeners");

connection.addEventListener(JitsiConnectionEvents.CONNECTION_DISCONNECTED, (message: string) =>
handleXMPPDisconnected(dispatch, message)
);
const connectedHandler = () => handleXMPPConnected();
const disconnectedHandler = (message: string) => handleXMPPDisconnected(dispatch, message);
const failedHandler = (error: any, message: string) => handleXMPPConnectionFailed(dispatch, error, message);

connection.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, (error: any, message: string) =>
handleXMPPConnectionFailed(dispatch, error, message)
);
connection.addEventListener(JitsiConnectionEvents.CONNECTION_ESTABLISHED, connectedHandler);
connection.addEventListener(JitsiConnectionEvents.CONNECTION_DISCONNECTED, disconnectedHandler);
connection.addEventListener(JitsiConnectionEvents.CONNECTION_FAILED, failedHandler);

state.connectionHandlers = {
connectedHandler,
disconnectedHandler,
failedHandler
};
state.connectionRef = connection;
state.hasConnectionListeners = true;
console.log("[LISTENER_SETUP] XMPP connection listeners registered successfully");
};

/**
* Removes event listeners for XMPP connection events
*
* @param state - Connection state containing handler references
*/
export const removeXMPPConnectionListeners = (state: ConnectionState) => {
if (!state.connectionRef || !state.connectionHandlers) {
console.log("[LISTENER_SETUP] Skipping XMPP listeners removal - no refs");
return;
}

console.log("[LISTENER_SETUP] Removing XMPP connection listeners");

const { connectionRef, connectionHandlers } = state;

connectionRef.removeEventListener(
JitsiConnectionEvents.CONNECTION_ESTABLISHED,
connectionHandlers.connectedHandler
);
connectionRef.removeEventListener(
JitsiConnectionEvents.CONNECTION_DISCONNECTED,
connectionHandlers.disconnectedHandler
);
connectionRef.removeEventListener(
JitsiConnectionEvents.CONNECTION_FAILED,
connectionHandlers.failedHandler
);

state.connectionHandlers = undefined;
state.connectionRef = undefined;
state.hasConnectionListeners = false;
console.log("[LISTENER_SETUP] XMPP connection listeners removed successfully");
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,34 @@ export interface ConnectionState {
* Used to only show "connection restored" notification if there was a previous interruption
*/
wasMediaConnectionInterrupted: boolean;

/**
* Stored handler references for conference media listeners
* Required for proper cleanup via removeEventListener
*/
conferenceHandlers?: {
interruptedHandler: () => void;
restoredHandler: () => void;
suspendHandler: () => void;
};

/**
* Stored handler references for XMPP connection listeners
* Required for proper cleanup via removeEventListener
*/
connectionHandlers?: {
connectedHandler: () => void;
disconnectedHandler: (message: string) => void;
failedHandler: (error: any, message: string) => void;
};

/**
* Reference to the conference object for listener removal
*/
conferenceRef?: any;

/**
* Reference to the connection object for listener removal
*/
connectionRef?: any;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import './connection-notifications';
import './middleware.datachannel';
import './middleware.error-handling';
import './middleware.poor-connection';
import './middleware.auto-reconnect';

export { };

Expand Down
Loading