[RN] Automatically dispatch CONFERENCE_LEFT

This commit is contained in:
Lyubo Marinov 2018-03-04 19:25:23 -06:00
parent 8b35ea8ad5
commit a30412ba65
3 changed files with 144 additions and 5 deletions

View File

@ -20,6 +20,7 @@ import UIEvents from '../../../../service/UI/UIEvents';
import { TRACK_ADDED, TRACK_REMOVED } from '../tracks';
import {
conferenceLeft,
createConference,
setAudioOnly,
setLastN,
@ -32,8 +33,10 @@ import {
DATA_CHANNEL_OPENED,
SET_AUDIO_ONLY,
SET_LASTN,
SET_RECEIVE_VIDEO_QUALITY
SET_RECEIVE_VIDEO_QUALITY,
SET_ROOM
} from './actionTypes';
import { JITSI_CONFERENCE_URL_KEY } from './constants';
import {
_addLocalTracksToConference,
_handleParticipantError,
@ -77,6 +80,9 @@ MiddlewareRegistry.register(store => next => action => {
case SET_RECEIVE_VIDEO_QUALITY:
return _setReceiveVideoQuality(store, next, action);
case SET_ROOM:
return _setRoom(store, next, action);
case TRACK_ADDED:
case TRACK_REMOVED:
return _trackAddedOrRemoved(store, next, action);
@ -330,6 +336,62 @@ function _setReceiveVideoQuality({ dispatch, getState }, next, action) {
return next(action);
}
/**
* Notifies the feature {@code base/conference} that the redix action
* {@link SET_ROOM} is being dispatched within a specific redux store.
*
* @param {Store} store - The redux store in which the specified action is being
* dispatched.
* @param {Dispatch} next - The redux dispatch function to dispatch the
* specified action to the specified store.
* @param {Action} action - The redux action {@code SET_ROOM} which is being
* dispatched in the specified store.
* @private
* @returns {Object} The value returned by {@code next(action)}.
*/
function _setRoom({ dispatch, getState }, next, action) {
const result = next(action);
// By the time SET_ROOM is dispatched, base/connection's locationURL and
// base/conference's leaving should be the only conference-related sources
// of truth.
const state = getState();
const {
leaving,
...stateFeaturesBaseConference
} = state['features/base/conference'];
const { locationURL } = state['features/base/connection'];
const dispatchConferenceLeft = new Set();
// Figure out which of the JitsiConferences referenced by base/conference
// have not dispatched or are not likely to dispatch CONFERENCE_FAILED and
// CONFERENCE_LEFT.
// eslint-disable-next-line guard-for-in
for (const p in stateFeaturesBaseConference) {
const v = stateFeaturesBaseConference[p];
// Does the value of the base/conference's property look like a
// JitsiConference?
if (v && typeof v === 'object') {
const url = v[JITSI_CONFERENCE_URL_KEY];
if (url && v !== leaving && url !== locationURL) {
dispatchConferenceLeft.add(v);
}
}
}
// Dispatch CONFERENCE_LEFT for the JitsiConferences referenced by
// base/conference which have not dispatched or are not likely to dispatch
// CONFERENCE_FAILED or CONFERENCE_LEFT.
for (const conference of dispatchConferenceLeft) {
dispatch(conferenceLeft(conference));
}
return result;
}
/**
* Synchronizes local tracks from state with local tracks in JitsiConference
* instance.

View File

@ -3,7 +3,7 @@
import _ from 'lodash';
import type { Dispatch } from 'redux';
import { conferenceWillLeave } from '../conference';
import { conferenceLeft, conferenceWillLeave } from '../conference';
import JitsiMeetJS, { JitsiConnectionEvents } from '../lib-jitsi-meet';
import { parseStandardURIString } from '../util';
@ -281,7 +281,16 @@ export function disconnect() {
// intention to leave the conference.
dispatch(conferenceWillLeave(conference_));
promise = conference_.leave();
promise
= conference_.leave()
.catch(() => {
// The library lib-jitsi-meet failed to make the
// JitsiConference leave. Which may be because
// JitsiConference thinks it has already left.
// Regardless of the failure reason, continue in
// jitsi-meet as if the leave has succeeded.
dispatch(conferenceLeft(conference_));
});
} else {
promise = Promise.resolve();
}

View File

@ -125,11 +125,13 @@ function _getSymbolDescription(symbol: Symbol) {
*/
function _sendConferenceEvent(
store: Object,
{ conference, type, ...data }: {
action: {
conference: Object,
type: Symbol,
url: ?string
}) {
const { conference, type, ...data } = action;
// For these (redux) actions, conference identifies a JitsiConference
// instance. The external API cannot transport such an object so we have to
// transport an "equivalent".
@ -137,7 +139,8 @@ function _sendConferenceEvent(
data.url = toURLString(conference[JITSI_CONFERENCE_URL_KEY]);
}
_sendEvent(store, _getSymbolDescription(type), data);
_swallowEvent(store, action, data)
|| _sendEvent(store, _getSymbolDescription(type), data);
}
/**
@ -169,3 +172,68 @@ function _sendEvent(
}
}
}
/**
* Determines whether to not send a {@code CONFERENCE_LEFT} event to the native
* counterpart of the External API.
*
* @param {Object} store - The redux store.
* @param {Action} action - The redux action which is causing the sending of the
* event.
* @param {Object} data - The details/specifics of the event to send determined
* by/associated with the specified {@code action}.
* @returns {boolean} If the specified event is to not be sent, {@code true};
* otherwise, {@code false}.
*/
function _swallowConferenceLeft({ getState }, action, { url }) {
// XXX Internally, we work with JitsiConference instances. Externally
// though, we deal with URL strings. The relation between the two is many to
// one so it's technically and practically possible (by externally loading
// the same URL string multiple times) to try to send CONFERENCE_LEFT
// externally for a URL string which identifies a JitsiConference that the
// app is internally legitimately working with.
if (url) {
const stateFeaturesBaseConference
= getState()['features/base/conference'];
// eslint-disable-next-line guard-for-in
for (const p in stateFeaturesBaseConference) {
const v = stateFeaturesBaseConference[p];
// Does the value of the base/conference's property look like a
// JitsiConference?
if (v && typeof v === 'object') {
const vURL = v[JITSI_CONFERENCE_URL_KEY];
if (vURL && vURL.toString() === url) {
return true;
}
}
}
}
return false;
}
/**
* Determines whether to not send a specific event to the native counterpart of
* the External API.
*
* @param {Object} store - The redux store.
* @param {Action} action - The redux action which is causing the sending of the
* event.
* @param {Object} data - The details/specifics of the event to send determined
* by/associated with the specified {@code action}.
* @returns {boolean} If the specified event is to not be sent, {@code true};
* otherwise, {@code false}.
*/
function _swallowEvent(store, action, data) {
switch (action.type) {
case CONFERENCE_LEFT:
return _swallowConferenceLeft(store, action, data);
default:
return false;
}
}