diff --git a/react/features/base/conference/actions.js b/react/features/base/conference/actions.js index 36662e3c8..512df6ff8 100644 --- a/react/features/base/conference/actions.js +++ b/react/features/base/conference/actions.js @@ -5,6 +5,9 @@ import { sendAnalytics } from '../../analytics'; import { getName } from '../../app'; +import { endpointMessageReceived } from '../../subtitles'; + +import { JITSI_CONNECTION_CONFERENCE_KEY } from '../connection'; import { JitsiConferenceEvents } from '../lib-jitsi-meet'; import { setAudioMuted, setVideoMuted } from '../media'; import { @@ -15,7 +18,6 @@ import { participantRoleChanged, participantUpdated } from '../participants'; -import { endpointMessageReceived } from '../../subtitles'; import { getLocalTracks, trackAdded, trackRemoved } from '../tracks'; import { getJitsiMeetGlobalNS } from '../util'; @@ -378,7 +380,10 @@ export function createConference() { getWiFiStatsMethod: getJitsiMeetGlobalNS().getWiFiStats }); + connection[JITSI_CONNECTION_CONFERENCE_KEY] = conference; + conference[JITSI_CONFERENCE_URL_KEY] = locationURL; + dispatch(_conferenceWillJoin(conference)); _addConferenceListeners(conference, dispatch); diff --git a/react/features/base/connection/actions.native.js b/react/features/base/connection/actions.native.js index f96cb8188..1d0e73e20 100644 --- a/react/features/base/connection/actions.native.js +++ b/react/features/base/connection/actions.native.js @@ -18,6 +18,7 @@ import { CONNECTION_WILL_CONNECT, SET_LOCATION_URL } from './actionTypes'; +import { JITSI_CONNECTION_URL_KEY } from './constants'; const logger = require('jitsi-meet-logger').getLogger(__filename); @@ -79,6 +80,7 @@ export function connect(id: ?string, password: ?string) { return (dispatch: Dispatch, getState: Function) => { const state = getState(); const options = _constructOptions(state); + const { locationURL } = state['features/base/connection']; const { issuer, jwt } = state['features/base/jwt']; const connection = new JitsiMeetJS.JitsiConnection( @@ -86,6 +88,8 @@ export function connect(id: ?string, password: ?string) { jwt && issuer && issuer !== 'anonymous' ? jwt : undefined, options); + connection[JITSI_CONNECTION_URL_KEY] = locationURL; + dispatch(_connectionWillConnect(connection)); connection.addEventListener( @@ -284,14 +288,13 @@ function _constructOptions(state) { let { bosh } = options; if (bosh) { + const { locationURL } = state['features/base/connection']; + if (bosh.startsWith('//')) { // By default our config.js doesn't include the protocol. - const { locationURL } = state['features/base/connection']; - bosh = `${locationURL.protocol}${bosh}`; } else if (bosh.startsWith('/')) { // Handle relative URLs, which won't work on mobile. - const { locationURL } = state['features/base/connection']; const { protocol, hostname, @@ -366,6 +369,11 @@ export function disconnect() { if (connection_) { promise = promise.then(() => connection_.disconnect()); + } else { + // FIXME: We have no connection! Fake a disconnect. Because of how the current disconnec is implemented + // (by doing the diconnect() in the Conference component unmount) we have lost the location URL already. + // Oh well, at least send the event. + promise.then(() => dispatch(_connectionDisconnected({}, ''))); } return promise; diff --git a/react/features/base/connection/constants.js b/react/features/base/connection/constants.js new file mode 100644 index 000000000..895406e23 --- /dev/null +++ b/react/features/base/connection/constants.js @@ -0,0 +1,19 @@ +// @flow + +/** + * The name of the {@code JitsiConnection} property which identifies the {@code JitsiConference} currently associated + * with it. + * + * FIXME: This is a hack. It was introduced to solve the following case: if a user presses hangup quickly, they may + * "leave the conference" before the actual conference was ever created. While we might have a connection in place, + * there is no conference which can be left, thus no CONFERENCE_LEFT action will ever be fired. + * + * This is problematic because the external API module used to send events to the native SDK won't know what to send. + * So, in order to detect this situation we are attaching the conference object to the connection which runs it. + */ +export const JITSI_CONNECTION_CONFERENCE_KEY = Symbol('conference'); + +/** + * The name of the {@code JitsiConnection} property which identifies the location URL where the connection will be made. + */ +export const JITSI_CONNECTION_URL_KEY = Symbol('url'); diff --git a/react/features/base/connection/index.js b/react/features/base/connection/index.js index 0b115a9d7..125852add 100644 --- a/react/features/base/connection/index.js +++ b/react/features/base/connection/index.js @@ -2,6 +2,7 @@ export * from './actions'; export * from './actionTypes'; +export * from './constants'; export * from './functions'; import './reducer'; diff --git a/react/features/conference/components/native/Conference.js b/react/features/conference/components/native/Conference.js index f06578267..ab1961d2a 100644 --- a/react/features/conference/components/native/Conference.js +++ b/react/features/conference/components/native/Conference.js @@ -199,7 +199,7 @@ class Conference extends AbstractConference { } = this.props; // If the location URL changes we need to reconnect. - oldLocationURL !== newLocationURL && this.props._onDisconnect(); + oldLocationURL !== newLocationURL && newRoom && this.props._onDisconnect(); // Start the connection process when there is a (valid) room. oldRoom !== newRoom && newRoom && this.props._onConnect(); diff --git a/react/features/mobile/external-api/middleware.js b/react/features/mobile/external-api/middleware.js index 95edd7877..46fd5f6ba 100644 --- a/react/features/mobile/external-api/middleware.js +++ b/react/features/mobile/external-api/middleware.js @@ -11,7 +11,12 @@ import { isRoomValid } from '../../base/conference'; import { LOAD_CONFIG_ERROR } from '../../base/config'; -import { CONNECTION_FAILED } from '../../base/connection'; +import { + CONNECTION_DISCONNECTED, + CONNECTION_FAILED, + JITSI_CONNECTION_CONFERENCE_KEY, + JITSI_CONNECTION_URL_KEY +} from '../../base/connection'; import { MiddlewareRegistry } from '../../base/redux'; import { toURLString } from '../../base/util'; import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture'; @@ -63,6 +68,27 @@ MiddlewareRegistry.register(store => next => action => { _sendConferenceEvent(store, action); break; + case CONNECTION_DISCONNECTED: { + // FIXME: This is a hack. See the description in the JITSI_CONNECTION_CONFERENCE_KEY constant definition. + // Check if this connection was attached to any conference. If it wasn't, fake a CONFERENCE_TERMINATED event. + const { connection } = action; + const conference = connection[JITSI_CONNECTION_CONFERENCE_KEY]; + + if (!conference) { + // This action will arrive late, so the locationURL stored on the state is no longer valid. + const locationURL = connection[JITSI_CONNECTION_URL_KEY]; + + sendEvent( + store, + CONFERENCE_TERMINATED, + /* data */ { + url: toURLString(locationURL) + }); + } + + break; + } + case CONNECTION_FAILED: !action.error.recoverable && _sendConferenceFailedOnConnectionError(store, action);