fix: leaking listeners while waiting on auth dialog (#11288)
* fix: Drop duplicate call of wait for owner. * fix: Fixes leaking listeners while waiting for host to join. While waiting for the host to join on the dialog we attempt to join over and over again till we are admitted to enter the meeting. While doing that authRequired flag is on, and we were adding listeners on and on. * feat: Introduces conference join in progress action. This event is coming from lib-jitsi-meet and is fired when we receive the first presence of series when joining. It is always fired before joined event. * fix: Moves testing middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves follow-me middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves some polls logic to middleware and use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves reactions middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves recordings middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves shared-video middleware to use CONFERENCE_JOIN_IN_PROGRESS. * fix: Moves videosipgw middleware to use CONFERENCE_JOIN_IN_PROGRESS. * squash: Fix comments. * fix: Fixes join in progress on web. * fix: Moves variable extraction inside handlers. * fix: Moves variable extraction inside handlers again. * fix: Moves etherpad middleware to use CONFERENCE_JOIN_IN_PROGRESS.
This commit is contained in:
parent
33db511d93
commit
a99532b0d8
|
@ -37,6 +37,7 @@ import {
|
|||
commonUserLeftHandling,
|
||||
conferenceFailed,
|
||||
conferenceJoined,
|
||||
conferenceJoinInProgress,
|
||||
conferenceLeft,
|
||||
conferenceSubjectChanged,
|
||||
conferenceTimestampChanged,
|
||||
|
@ -142,8 +143,7 @@ import {
|
|||
initPrejoin,
|
||||
isPrejoinPageVisible,
|
||||
makePrecallTest,
|
||||
setJoiningInProgress,
|
||||
setPrejoinPageVisibility
|
||||
setJoiningInProgress
|
||||
} from './react/features/prejoin';
|
||||
import { disableReceiver, stopReceiver } from './react/features/remote-control';
|
||||
import { setScreenAudioShareState, isScreenAudioShared } from './react/features/screen-share/';
|
||||
|
@ -2068,9 +2068,9 @@ export default {
|
|||
room.on(JitsiConferenceEvents.CONFERENCE_JOINED, () => {
|
||||
this._onConferenceJoined();
|
||||
});
|
||||
room.on(JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS, () => {
|
||||
APP.store.dispatch(setPrejoinPageVisibility(false));
|
||||
});
|
||||
room.on(
|
||||
JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS,
|
||||
() => APP.store.dispatch(conferenceJoinInProgress(room)));
|
||||
|
||||
room.on(
|
||||
JitsiConferenceEvents.CONFERENCE_LEFT,
|
||||
|
|
|
@ -6,7 +6,10 @@ import { openConnection } from '../../../connection';
|
|||
import {
|
||||
openAuthDialog,
|
||||
openLoginDialog } from '../../../react/features/authentication/actions.web';
|
||||
import { WaitForOwnerDialog } from '../../../react/features/authentication/components';
|
||||
import {
|
||||
LoginDialog,
|
||||
WaitForOwnerDialog
|
||||
} from '../../../react/features/authentication/components';
|
||||
import {
|
||||
isTokenAuthEnabled,
|
||||
getTokenAuthUrl
|
||||
|
@ -16,7 +19,7 @@ import { isDialogOpen } from '../../../react/features/base/dialog';
|
|||
import { setJWT } from '../../../react/features/base/jwt';
|
||||
import UIUtil from '../util/UIUtil';
|
||||
|
||||
import LoginDialog from './LoginDialog';
|
||||
import ExternalLoginDialog from './LoginDialog';
|
||||
|
||||
|
||||
let externalAuthWindow;
|
||||
|
@ -51,7 +54,7 @@ function doExternalAuth(room, lockPassword) {
|
|||
getUrl = room.getExternalAuthUrl(true);
|
||||
}
|
||||
getUrl.then(url => {
|
||||
externalAuthWindow = LoginDialog.showExternalAuthDialog(
|
||||
externalAuthWindow = ExternalLoginDialog.showExternalAuthDialog(
|
||||
url,
|
||||
() => {
|
||||
externalAuthWindow = null;
|
||||
|
@ -187,7 +190,7 @@ function authenticate(room: Object, lockPassword: string) {
|
|||
* @param {string} [lockPassword] password to use if the conference is locked
|
||||
*/
|
||||
function requireAuth(room: Object, lockPassword: string) {
|
||||
if (!isDialogOpen(APP.store, WaitForOwnerDialog)) {
|
||||
if (isDialogOpen(APP.store, WaitForOwnerDialog) || isDialogOpen(APP.store, LoginDialog)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ import '../lobby/middleware';
|
|||
import '../notifications/middleware';
|
||||
import '../overlay/middleware';
|
||||
import '../polls/middleware';
|
||||
import '../polls/subscriber';
|
||||
import '../reactions/middleware';
|
||||
import '../recent-list/middleware';
|
||||
import '../recording/middleware';
|
||||
|
|
|
@ -22,8 +22,7 @@ import {
|
|||
import {
|
||||
hideLoginDialog,
|
||||
openWaitForOwnerDialog,
|
||||
stopWaitForOwner,
|
||||
waitForOwner
|
||||
stopWaitForOwner
|
||||
} from './actions.web';
|
||||
import { LoginDialog, WaitForOwnerDialog } from './components';
|
||||
|
||||
|
@ -72,7 +71,11 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
recoverable = error.recoverable;
|
||||
}
|
||||
if (recoverable) {
|
||||
store.dispatch(waitForOwner());
|
||||
// we haven't migrated all the code from AuthHandler, and we need for now conference.js to trigger
|
||||
// the dialog to pass all required parameters to WaitForOwnerDialog
|
||||
// keep it commented, so we do not trigger sending iqs to jicofo twice
|
||||
// and showing the broken dialog with no handler
|
||||
// store.dispatch(waitForOwner());
|
||||
} else {
|
||||
store.dispatch(stopWaitForOwner());
|
||||
}
|
||||
|
|
|
@ -32,6 +32,17 @@ export const CONFERENCE_FAILED = 'CONFERENCE_FAILED';
|
|||
*/
|
||||
export const CONFERENCE_JOINED = 'CONFERENCE_JOINED';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that a specific conference joining is in progress.
|
||||
* A CONFERENCE_JOINED is guaranteed to follow.
|
||||
*
|
||||
* {
|
||||
* type: CONFERENCE_JOIN_IN_PROGRESS,
|
||||
* conference: JitsiConference
|
||||
* }
|
||||
*/
|
||||
export const CONFERENCE_JOIN_IN_PROGRESS = 'CONFERENCE_JOIN_IN_PROGRESS';
|
||||
|
||||
/**
|
||||
* The type of (redux) action which signals that a specific conference was left.
|
||||
*
|
||||
|
|
|
@ -39,6 +39,7 @@ import { getBackendSafeRoomName } from '../util';
|
|||
import {
|
||||
AUTH_STATUS_CHANGED,
|
||||
CONFERENCE_FAILED,
|
||||
CONFERENCE_JOIN_IN_PROGRESS,
|
||||
CONFERENCE_JOINED,
|
||||
CONFERENCE_LEFT,
|
||||
CONFERENCE_LOCAL_SUBJECT_CHANGED,
|
||||
|
@ -105,6 +106,9 @@ function _addConferenceListeners(conference, dispatch, state) {
|
|||
conference.on(
|
||||
JitsiConferenceEvents.CONFERENCE_JOINED,
|
||||
(...args) => dispatch(conferenceJoined(conference, ...args)));
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONFERENCE_JOIN_IN_PROGRESS,
|
||||
(...args) => dispatch(conferenceJoinInProgress(conference, ...args)));
|
||||
conference.on(
|
||||
JitsiConferenceEvents.CONFERENCE_LEFT,
|
||||
(...args) => {
|
||||
|
@ -350,6 +354,23 @@ export function conferenceJoined(conference: Object) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that a specific conference join is in progress.
|
||||
*
|
||||
* @param {JitsiConference} conference - The JitsiConference instance for which join by the local participant
|
||||
* is in progress.
|
||||
* @returns {{
|
||||
* type: CONFERENCE_JOIN_IN_PROGRESS,
|
||||
* conference: JitsiConference
|
||||
* }}
|
||||
*/
|
||||
export function conferenceJoinInProgress(conference: Object) {
|
||||
return {
|
||||
type: CONFERENCE_JOIN_IN_PROGRESS,
|
||||
conference
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals that a specific conference has been left.
|
||||
*
|
||||
|
|
|
@ -2,7 +2,10 @@
|
|||
|
||||
import { AUDIO_ONLY_SCREEN_SHARE_NO_TRACK } from '../../../../modules/UI/UIErrors';
|
||||
import { showNotification, NOTIFICATION_TIMEOUT_TYPE } from '../../notifications';
|
||||
import { setSkipPrejoinOnReload } from '../../prejoin';
|
||||
import {
|
||||
setPrejoinPageVisibility,
|
||||
setSkipPrejoinOnReload
|
||||
} from '../../prejoin';
|
||||
import { setScreenAudioShareState, setScreenshareAudioTrack } from '../../screen-share';
|
||||
import { AudioMixerEffect } from '../../stream-effects/audio-mixer/AudioMixerEffect';
|
||||
import { setAudioOnly } from '../audio-only';
|
||||
|
@ -19,7 +22,7 @@ import {
|
|||
TOGGLE_SCREENSHARING
|
||||
} from '../tracks';
|
||||
|
||||
import { CONFERENCE_FAILED, CONFERENCE_JOINED } from './actionTypes';
|
||||
import { CONFERENCE_FAILED, CONFERENCE_JOIN_IN_PROGRESS, CONFERENCE_JOINED } from './actionTypes';
|
||||
import { getCurrentConference } from './functions';
|
||||
import './middleware.any';
|
||||
|
||||
|
@ -28,6 +31,11 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
const { enableForcedReload } = getState()['features/base/config'];
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
dispatch(setPrejoinPageVisibility(false));
|
||||
|
||||
break;
|
||||
}
|
||||
case CONFERENCE_JOINED: {
|
||||
if (enableForcedReload) {
|
||||
dispatch(setSkipPrejoinOnReload(false));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { CONFERENCE_WILL_JOIN } from '../conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../conference/actionTypes';
|
||||
import { SET_CONFIG } from '../config';
|
||||
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
|
||||
import { MiddlewareRegistry } from '../redux';
|
||||
|
@ -24,7 +24,7 @@ import logger from './logger';
|
|||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_WILL_JOIN:
|
||||
case CONFERENCE_JOIN_IN_PROGRESS:
|
||||
_bindConferenceConnectionListener(action.conference, store);
|
||||
break;
|
||||
case SET_CONFIG: {
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import UIEvents from '../../../service/UI/UIEvents';
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
|
||||
import { TOGGLE_DOCUMENT_EDITING } from './actionTypes';
|
||||
|
@ -21,6 +22,23 @@ const ETHERPAD_COMMAND = 'etherpad';
|
|||
// eslint-disable-next-line no-unused-vars
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.addCommandListener(ETHERPAD_COMMAND,
|
||||
({ value }) => {
|
||||
let url;
|
||||
const { etherpad_base: etherpadBase } = getState()['features/base/config'];
|
||||
|
||||
if (etherpadBase) {
|
||||
url = new URL(value, etherpadBase).toString();
|
||||
}
|
||||
|
||||
dispatch(setDocumentUrl(url));
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case TOGGLE_DOCUMENT_EDITING: {
|
||||
if (typeof APP !== 'undefined') {
|
||||
APP.UI.emitEvent(UIEvents.ETHERPAD_CLICKED);
|
||||
|
@ -39,24 +57,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch, getState }, previousConference) => {
|
||||
if (conference) {
|
||||
conference.addCommandListener(ETHERPAD_COMMAND,
|
||||
({ value }) => {
|
||||
let url;
|
||||
const { etherpad_base: etherpadBase } = getState()['features/base/config'];
|
||||
|
||||
if (etherpadBase) {
|
||||
const u = new URL(value, etherpadBase);
|
||||
|
||||
url = u.toString();
|
||||
}
|
||||
|
||||
dispatch(setDocumentUrl(url));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
(conference, { dispatch }, previousConference) => {
|
||||
if (previousConference) {
|
||||
dispatch(setDocumentUrl(undefined));
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import _ from 'lodash';
|
||||
|
||||
import { CONFERENCE_WILL_JOIN } from '../base/conference/actionTypes';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import {
|
||||
getParticipantById,
|
||||
getPinnedParticipant,
|
||||
|
@ -61,7 +61,7 @@ let nextOnStageTimer = 0;
|
|||
*/
|
||||
MiddlewareRegistry.register(store => next => action => {
|
||||
switch (action.type) {
|
||||
case CONFERENCE_WILL_JOIN: {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.addCommandListener(
|
||||
|
|
|
@ -1,16 +1,95 @@
|
|||
// @flow
|
||||
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import { playSound } from '../base/sounds';
|
||||
import { INCOMING_MSG_SOUND_ID } from '../chat/constants';
|
||||
import {
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
NOTIFICATION_TYPE,
|
||||
showNotification
|
||||
} from '../notifications';
|
||||
|
||||
import { RECEIVE_POLL } from './actionTypes';
|
||||
import { clearPolls, receiveAnswer, receivePoll } from './actions';
|
||||
import {
|
||||
COMMAND_ANSWER_POLL,
|
||||
COMMAND_NEW_POLL,
|
||||
COMMAND_OLD_POLLS
|
||||
} from './constants';
|
||||
import type { Answer, Poll } from './types';
|
||||
|
||||
/**
|
||||
* Set up state change listener to perform maintenance tasks when the conference
|
||||
* is left or failed, e.g. Clear messages or close the chat modal if it's left
|
||||
* open.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, { dispatch }, previousConference) => {
|
||||
if (conference !== previousConference) {
|
||||
// conference changed, left or failed...
|
||||
// clean old polls
|
||||
dispatch(clearPolls());
|
||||
}
|
||||
});
|
||||
|
||||
const parsePollData = (pollData): Poll | null => {
|
||||
if (typeof pollData !== 'object' || pollData === null) {
|
||||
return null;
|
||||
}
|
||||
const { id, senderId, senderName, question, answers } = pollData;
|
||||
|
||||
if (typeof id !== 'string' || typeof senderId !== 'string' || typeof senderName !== 'string'
|
||||
|| typeof question !== 'string' || !(answers instanceof Array)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const answersParsed = [];
|
||||
|
||||
for (const answer of answers) {
|
||||
const voters = new Map();
|
||||
|
||||
for (const [ voterId, voter ] of Object.entries(answer.voters)) {
|
||||
if (typeof voter !== 'string') {
|
||||
return null;
|
||||
}
|
||||
voters.set(voterId, voter);
|
||||
}
|
||||
|
||||
answersParsed.push({
|
||||
name: answer.name,
|
||||
voters
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
changingVote: false,
|
||||
senderId,
|
||||
senderName,
|
||||
question,
|
||||
showResults: true,
|
||||
lastVote: null,
|
||||
answers: answersParsed
|
||||
};
|
||||
};
|
||||
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(_, data) => _handleReceivePollsMessage(data, dispatch));
|
||||
conference.on(JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED,
|
||||
(_, data) => _handleReceivePollsMessage(data, dispatch));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Middleware triggered when a poll is received
|
||||
case RECEIVE_POLL: {
|
||||
|
@ -30,3 +109,73 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
|
||||
return result;
|
||||
});
|
||||
|
||||
/**
|
||||
* Handles receiving of polls message command.
|
||||
*
|
||||
* @param {Object} data - The json data carried by the polls message.
|
||||
* @param {Function} dispatch - The dispatch function.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
function _handleReceivePollsMessage(data, dispatch) {
|
||||
switch (data.type) {
|
||||
case COMMAND_NEW_POLL: {
|
||||
const { question, answers, pollId, senderId, senderName } = data;
|
||||
|
||||
const poll = {
|
||||
changingVote: false,
|
||||
senderId,
|
||||
senderName,
|
||||
showResults: false,
|
||||
lastVote: null,
|
||||
question,
|
||||
answers: answers.map(answer => {
|
||||
return {
|
||||
name: answer,
|
||||
voters: new Map()
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
dispatch(receivePoll(pollId, poll, true));
|
||||
dispatch(showNotification({
|
||||
appearance: NOTIFICATION_TYPE.NORMAL,
|
||||
titleKey: 'polls.notification.title',
|
||||
descriptionKey: 'polls.notification.description'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case COMMAND_ANSWER_POLL: {
|
||||
const { pollId, answers, voterId, voterName } = data;
|
||||
|
||||
const receivedAnswer: Answer = {
|
||||
voterId,
|
||||
voterName,
|
||||
pollId,
|
||||
answers
|
||||
};
|
||||
|
||||
dispatch(receiveAnswer(pollId, receivedAnswer));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case COMMAND_OLD_POLLS: {
|
||||
const { polls } = data;
|
||||
|
||||
for (const pollData of polls) {
|
||||
const poll = parsePollData(pollData);
|
||||
|
||||
if (poll === null) {
|
||||
console.warn('[features/polls] Invalid old poll data');
|
||||
} else {
|
||||
dispatch(receivePoll(pollData.id, poll, false));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
// @flow
|
||||
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { JitsiConferenceEvents } from '../base/lib-jitsi-meet';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import {
|
||||
NOTIFICATION_TIMEOUT_TYPE,
|
||||
NOTIFICATION_TYPE,
|
||||
showNotification
|
||||
} from '../notifications';
|
||||
|
||||
import { clearPolls, receiveAnswer, receivePoll } from './actions';
|
||||
import { COMMAND_NEW_POLL, COMMAND_ANSWER_POLL, COMMAND_OLD_POLLS } from './constants';
|
||||
import type { Answer, Poll } from './types';
|
||||
|
||||
|
||||
const parsePollData = (pollData): Poll | null => {
|
||||
if (typeof pollData !== 'object' || pollData === null) {
|
||||
return null;
|
||||
}
|
||||
const { id, senderId, senderName, question, answers } = pollData;
|
||||
|
||||
if (typeof id !== 'string' || typeof senderId !== 'string' || typeof senderName !== 'string'
|
||||
|| typeof question !== 'string' || !(answers instanceof Array)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const answersParsed = [];
|
||||
|
||||
for (const answer of answers) {
|
||||
const voters = new Map();
|
||||
|
||||
for (const [ voterId, voter ] of Object.entries(answer.voters)) {
|
||||
if (typeof voter !== 'string') {
|
||||
return null;
|
||||
}
|
||||
voters.set(voterId, voter);
|
||||
}
|
||||
|
||||
answersParsed.push({
|
||||
name: answer.name,
|
||||
voters
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
changingVote: false,
|
||||
senderId,
|
||||
senderName,
|
||||
question,
|
||||
showResults: true,
|
||||
lastVote: null,
|
||||
answers: answersParsed
|
||||
};
|
||||
};
|
||||
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, store, previousConference) => {
|
||||
if (conference && conference !== previousConference) {
|
||||
const receiveMessage = (_, data) => {
|
||||
switch (data.type) {
|
||||
case COMMAND_NEW_POLL: {
|
||||
const { question, answers, pollId, senderId, senderName } = data;
|
||||
|
||||
const poll = {
|
||||
changingVote: false,
|
||||
senderId,
|
||||
senderName,
|
||||
showResults: false,
|
||||
lastVote: null,
|
||||
question,
|
||||
answers: answers.map(answer => {
|
||||
return {
|
||||
name: answer,
|
||||
voters: new Map()
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
store.dispatch(receivePoll(pollId, poll, true));
|
||||
store.dispatch(showNotification({
|
||||
appearance: NOTIFICATION_TYPE.NORMAL,
|
||||
titleKey: 'polls.notification.title',
|
||||
descriptionKey: 'polls.notification.description'
|
||||
}, NOTIFICATION_TIMEOUT_TYPE.MEDIUM));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case COMMAND_ANSWER_POLL: {
|
||||
const { pollId, answers, voterId, voterName } = data;
|
||||
|
||||
const receivedAnswer: Answer = {
|
||||
voterId,
|
||||
voterName,
|
||||
pollId,
|
||||
answers
|
||||
};
|
||||
|
||||
store.dispatch(receiveAnswer(pollId, receivedAnswer));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
case COMMAND_OLD_POLLS: {
|
||||
const { polls } = data;
|
||||
|
||||
for (const pollData of polls) {
|
||||
const poll = parsePollData(pollData);
|
||||
|
||||
if (poll === null) {
|
||||
console.warn('[features/polls] Invalid old poll data');
|
||||
} else {
|
||||
store.dispatch(receivePoll(pollData.id, poll, false));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
conference.on(JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED, receiveMessage);
|
||||
conference.on(JitsiConferenceEvents.NON_PARTICIPANT_MESSAGE_RECEIVED, receiveMessage);
|
||||
|
||||
// clean old polls
|
||||
store.dispatch(clearPolls());
|
||||
}
|
||||
}
|
||||
);
|
|
@ -5,7 +5,7 @@ import { batch } from 'react-redux';
|
|||
import { createReactionSoundsDisabledEvent, sendAnalytics } from '../analytics';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import {
|
||||
CONFERENCE_WILL_JOIN,
|
||||
CONFERENCE_JOIN_IN_PROGRESS,
|
||||
SET_START_REACTIONS_MUTED,
|
||||
setStartReactionsMuted
|
||||
} from '../base/conference';
|
||||
|
@ -104,7 +104,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
|
||||
break;
|
||||
}
|
||||
case CONFERENCE_WILL_JOIN: {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.addCommandListener(
|
||||
|
|
|
@ -6,7 +6,7 @@ import {
|
|||
sendAnalytics
|
||||
} from '../analytics';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import { CONFERENCE_WILL_JOIN, getCurrentConference } from '../base/conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS, getCurrentConference } from '../base/conference';
|
||||
import JitsiMeetJS, {
|
||||
JitsiConferenceEvents,
|
||||
JitsiRecordingConstants
|
||||
|
@ -106,21 +106,15 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
|
||||
break;
|
||||
|
||||
case CONFERENCE_WILL_JOIN: {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.RECORDER_STATE_CHANGED,
|
||||
recorderSession => {
|
||||
|
||||
if (recorderSession) {
|
||||
recorderSession.getID()
|
||||
&& dispatch(
|
||||
updateRecordingSessionData(recorderSession));
|
||||
|
||||
recorderSession.getError()
|
||||
&& _showRecordingErrorNotification(
|
||||
recorderSession, dispatch);
|
||||
recorderSession.getID() && dispatch(updateRecordingSessionData(recorderSession));
|
||||
recorderSession.getError() && _showRecordingErrorNotification(recorderSession, dispatch);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { CONFERENCE_LEFT, getCurrentConference } from '../base/conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS, CONFERENCE_LEFT } from '../base/conference/actionTypes';
|
||||
import { getCurrentConference } from '../base/conference/functions';
|
||||
import {
|
||||
PARTICIPANT_LEFT,
|
||||
getLocalParticipant,
|
||||
|
@ -10,7 +11,7 @@ import {
|
|||
participantLeft,
|
||||
pinParticipant
|
||||
} from '../base/participants';
|
||||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import { SET_SHARED_VIDEO_STATUS, RESET_SHARED_VIDEO_STATUS } from './actionTypes';
|
||||
import {
|
||||
|
@ -30,16 +31,37 @@ import { isSharingStatus } from './functions';
|
|||
MiddlewareRegistry.register(store => next => action => {
|
||||
const { dispatch, getState } = store;
|
||||
const state = getState();
|
||||
const conference = getCurrentConference(state);
|
||||
const localParticipantId = getLocalParticipant(state)?.id;
|
||||
const { videoUrl, status, ownerId, time, muted, volume } = action;
|
||||
const { ownerId: stateOwnerId, videoUrl: statevideoUrl } = state['features/shared-video'];
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
const localParticipantId = getLocalParticipant(state)?.id;
|
||||
|
||||
conference.addCommandListener(SHARED_VIDEO,
|
||||
({ value, attributes }) => {
|
||||
|
||||
const { from } = attributes;
|
||||
const sharedVideoStatus = attributes.state;
|
||||
|
||||
if (isSharingStatus(sharedVideoStatus)) {
|
||||
handleSharingVideoStatus(store, value, attributes, conference);
|
||||
} else if (sharedVideoStatus === 'stop') {
|
||||
dispatch(participantLeft(value, conference));
|
||||
if (localParticipantId !== from) {
|
||||
dispatch(resetSharedVideoStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
case CONFERENCE_LEFT:
|
||||
dispatch(resetSharedVideoStatus());
|
||||
break;
|
||||
case PARTICIPANT_LEFT:
|
||||
case PARTICIPANT_LEFT: {
|
||||
const conference = getCurrentConference(state);
|
||||
const { ownerId: stateOwnerId, videoUrl: statevideoUrl } = state['features/shared-video'];
|
||||
|
||||
if (action.participant.id === stateOwnerId) {
|
||||
batch(() => {
|
||||
dispatch(resetSharedVideoStatus());
|
||||
|
@ -47,7 +69,12 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
});
|
||||
}
|
||||
break;
|
||||
case SET_SHARED_VIDEO_STATUS:
|
||||
}
|
||||
case SET_SHARED_VIDEO_STATUS: {
|
||||
const conference = getCurrentConference(state);
|
||||
const localParticipantId = getLocalParticipant(state)?.id;
|
||||
const { videoUrl, status, ownerId, time, muted, volume } = action;
|
||||
|
||||
if (localParticipantId === ownerId) {
|
||||
sendShareVideoCommand({
|
||||
conference,
|
||||
|
@ -60,8 +87,14 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
});
|
||||
}
|
||||
break;
|
||||
case RESET_SHARED_VIDEO_STATUS:
|
||||
}
|
||||
case RESET_SHARED_VIDEO_STATUS: {
|
||||
const localParticipantId = getLocalParticipant(state)?.id;
|
||||
const { ownerId: stateOwnerId, videoUrl: statevideoUrl } = state['features/shared-video'];
|
||||
|
||||
if (localParticipantId === stateOwnerId) {
|
||||
const conference = getCurrentConference(state);
|
||||
|
||||
sendShareVideoCommand({
|
||||
conference,
|
||||
id: statevideoUrl,
|
||||
|
@ -74,41 +107,11 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up state change listener to perform maintenance tasks when the conference
|
||||
* is left or failed, e.g. Clear messages or close the chat modal if it's left
|
||||
* open.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, store, previousConference) => {
|
||||
if (conference && conference !== previousConference) {
|
||||
conference.addCommandListener(SHARED_VIDEO,
|
||||
({ value, attributes }) => {
|
||||
|
||||
const { dispatch, getState } = store;
|
||||
const { from } = attributes;
|
||||
const localParticipantId = getLocalParticipant(getState()).id;
|
||||
const status = attributes.state;
|
||||
|
||||
if (isSharingStatus(status)) {
|
||||
handleSharingVideoStatus(store, value, attributes, conference);
|
||||
} else if (status === 'stop') {
|
||||
dispatch(participantLeft(value, conference));
|
||||
if (localParticipantId !== from) {
|
||||
dispatch(resetSharedVideoStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Handles the playing, pause and start statuses for the shared video.
|
||||
* Dispatches participantJoined event and, if necessary, pins it.
|
||||
|
|
|
@ -1,38 +1,37 @@
|
|||
// @flow
|
||||
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
import { StateListenerRegistry } from '../base/redux';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
|
||||
import { setDisableButton } from './actions.web';
|
||||
import { SHARED_VIDEO } from './constants';
|
||||
|
||||
import './middleware.any';
|
||||
|
||||
/**
|
||||
* Set up state change listener to disable or enable the share video button in
|
||||
* the toolbar menu.
|
||||
*/
|
||||
StateListenerRegistry.register(
|
||||
state => getCurrentConference(state),
|
||||
(conference, store, previousConference) => {
|
||||
if (conference && conference !== previousConference) {
|
||||
conference.addCommandListener(SHARED_VIDEO,
|
||||
({ attributes }) => {
|
||||
const { dispatch, getState } = store;
|
||||
const { from } = attributes;
|
||||
const localParticipantId = getLocalParticipant(getState()).id;
|
||||
const status = attributes.state;
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const state = getState();
|
||||
const localParticipantId = getLocalParticipant(state)?.id;
|
||||
|
||||
if (status === 'playing') {
|
||||
if (localParticipantId !== from) {
|
||||
dispatch(setDisableButton(true));
|
||||
}
|
||||
} else if (status === 'stop') {
|
||||
dispatch(setDisableButton(false));
|
||||
}
|
||||
switch (action.type) {
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.addCommandListener(SHARED_VIDEO, ({ attributes }) => {
|
||||
const { from } = attributes;
|
||||
const status = attributes.state;
|
||||
|
||||
if (status === 'playing') {
|
||||
if (localParticipantId !== from) {
|
||||
dispatch(setDisableButton(true));
|
||||
}
|
||||
);
|
||||
}
|
||||
} else if (status === 'stop') {
|
||||
dispatch(setDisableButton(false));
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return next(action);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { CONFERENCE_WILL_JOIN } from '../base/conference';
|
||||
import { CONFERENCE_JOIN_IN_PROGRESS } from '../base/conference/actionTypes';
|
||||
import {
|
||||
JitsiConferenceEvents,
|
||||
JitsiSIPVideoGWStatus
|
||||
|
@ -29,12 +29,12 @@ import logger from './logger';
|
|||
* @param {Store} store - The redux store.
|
||||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
MiddlewareRegistry.register(({ dispatch }) => next => action => {
|
||||
const result = next(action);
|
||||
|
||||
switch (action.type) {
|
||||
case CONFERENCE_WILL_JOIN: {
|
||||
const conference = getState()['features/base/conference'].joining;
|
||||
case CONFERENCE_JOIN_IN_PROGRESS: {
|
||||
const { conference } = action;
|
||||
|
||||
conference.on(
|
||||
JitsiConferenceEvents.VIDEO_SIP_GW_AVAILABILITY_CHANGED,
|
||||
|
|
Loading…
Reference in New Issue