Merge pull request #1440 from jitsi/iframe_api_race_condition

Fix executeCommand race condition
This commit is contained in:
Saúl Ibarra Corretgé 2017-03-31 16:48:50 +01:00 committed by GitHub
commit a10f040df6
8 changed files with 112 additions and 115 deletions

View File

@ -32,12 +32,10 @@ import {
isFatalJitsiConnectionError
} from './react/features/base/lib-jitsi-meet';
import {
changeParticipantAvatarID,
changeParticipantAvatarURL,
changeParticipantEmail,
participantJoined,
participantLeft,
participantRoleChanged
participantRoleChanged,
participantUpdated
} from './react/features/base/participants';
import {
showDesktopPicker
@ -174,6 +172,10 @@ function createInitialLocalTracksAndConnect(roomName) {
* @param {string} value new value
*/
function sendData (command, value) {
if(!room) {
return;
}
room.removeCommand(command);
room.sendCommand(command, {value: value});
}
@ -361,23 +363,6 @@ function createLocalTracks (options, checkForPermissionPrompt) {
});
}
/**
* Changes the display name for the local user
* @param nickname {string} the new display name
*/
function changeLocalDisplayName(nickname = '') {
const formattedNickname
= nickname.trim().substr(0, MAX_DISPLAY_NAME_LENGTH);
if (formattedNickname === APP.settings.getDisplayName()) {
return;
}
APP.settings.setDisplayName(formattedNickname);
room.setDisplayName(formattedNickname);
APP.UI.changeDisplayName(APP.conference.getMyUserId(), formattedNickname);
}
class ConferenceConnector {
constructor(resolve, reject, invite) {
this._resolve = resolve;
@ -1499,7 +1484,10 @@ export default {
APP.UI.addListener(UIEvents.EMAIL_CHANGED, this.changeLocalEmail);
room.addCommandListener(this.commands.defaults.EMAIL, (data, from) => {
APP.store.dispatch(changeParticipantEmail(from, data.value));
APP.store.dispatch(participantUpdated({
id: from,
email: data.value
}));
APP.UI.setUserEmail(from, data.value);
});
@ -1507,18 +1495,25 @@ export default {
this.commands.defaults.AVATAR_URL,
(data, from) => {
APP.store.dispatch(
changeParticipantAvatarURL(from, data.value));
participantUpdated({
id: from,
avatarURL: data.value
}));
APP.UI.setUserAvatarUrl(from, data.value);
});
room.addCommandListener(this.commands.defaults.AVATAR_ID,
(data, from) => {
APP.store.dispatch(
changeParticipantAvatarID(from, data.value));
participantUpdated({
id: from,
avatarID: data.value
}));
APP.UI.setUserAvatarID(from, data.value);
});
APP.UI.addListener(UIEvents.NICKNAME_CHANGED, changeLocalDisplayName);
APP.UI.addListener(UIEvents.NICKNAME_CHANGED,
this.changeLocalDisplayName.bind(this));
APP.UI.addListener(UIEvents.START_MUTED_CHANGED,
(startAudioMuted, startVideoMuted) => {
@ -1925,10 +1920,17 @@ export default {
if (email === APP.settings.getEmail()) {
return;
}
APP.store.dispatch(changeParticipantEmail(room.myUserId(), email));
const localId = room ? room.myUserId() : undefined;
APP.store.dispatch(participantUpdated({
id: localId,
local: true,
email
}));
APP.settings.setEmail(email);
APP.UI.setUserEmail(room.myUserId(), email);
APP.UI.setUserEmail(localId, email);
sendData(commands.EMAIL, email);
},
@ -1942,10 +1944,17 @@ export default {
if (url === APP.settings.getAvatarUrl()) {
return;
}
APP.store.dispatch(changeParticipantAvatarURL(room.myUserId(), url));
const localId = room ? room.myUserId() : undefined;
APP.store.dispatch(participantUpdated({
id: localId,
local: true,
avatarURL: url
}));
APP.settings.setAvatarUrl(url);
APP.UI.setUserAvatarUrl(room.myUserId(), url);
APP.UI.setUserAvatarUrl(localId, url);
sendData(commands.AVATAR_URL, url);
},
@ -1991,5 +2000,22 @@ export default {
*/
isInLastN (participantId) {
return room.isInLastN(participantId);
},
/**
* Changes the display name for the local user
* @param nickname {string} the new display name
*/
changeLocalDisplayName(nickname = '') {
const formattedNickname
= nickname.trim().substr(0, MAX_DISPLAY_NAME_LENGTH);
if (formattedNickname === APP.settings.getDisplayName()) {
return;
}
APP.settings.setDisplayName(formattedNickname);
room.setDisplayName(formattedNickname);
APP.UI.changeDisplayName(this.getMyUserId(),
formattedNickname);
}
};

View File

@ -45,7 +45,8 @@ let enabled = false;
function initCommands() {
commands = {
"display-name": APP.UI.inputDisplayNameHandler,
"display-name":
APP.conference.changeLocalDisplayName.bind(APP.conference),
"toggle-audio": APP.conference.toggleAudioMuted.bind(APP.conference),
"toggle-video": APP.conference.toggleVideoMuted.bind(APP.conference),
"toggle-film-strip": APP.UI.toggleFilmStrip,

View File

@ -762,6 +762,9 @@ UI.setUserEmail = function (id, email) {
Avatar.setUserEmail(id, email);
changeAvatar(id, Avatar.getAvatarUrl(id));
if (APP.conference.isLocalId(id)) {
Profile.changeEmail(email);
}
};
/**

View File

@ -30,7 +30,7 @@ let users = {};
export default {
/**
* Sets prop in users object.
* @param id {string} user id
* @param id {string} user id or undefined for the local user.
* @param prop {string} name of the prop
* @param val {string} value to be set
*/
@ -38,7 +38,7 @@ export default {
// FIXME: Fixes the issue with not be able to return avatar for the
// local user when the conference has been left. Maybe there is beter
// way to solve it.
if(APP.conference.isLocalId(id)) {
if(!id || APP.conference.isLocalId(id)) {
id = "local";
}
if(!val || (users[id] && users[id][prop] === val))

View File

@ -15,10 +15,10 @@ const htmlStr = `
</div>
<div class="sideToolbarBlock">
<label data-i18n="profile.setEmailLabel"></label>
<input id="setEmail" type="text" class="input-control"
<input id="setEmail" type="text" class="input-control"
data-i18n="[placeholder]profile.setEmailInput">
</div>
<div id="profile_auth_container"
<div id="profile_auth_container"
class="sideToolbarBlock auth_container">
<p data-i18n="toolbar.authenticate"></p>
<ul>
@ -122,6 +122,14 @@ export default {
$('#avatar').attr('src', avatarUrl);
},
/**
* Change the value of the field for the user email.
* @param {string} email the new value that will be displayed in the field.
*/
changeEmail (email) {
$('#setEmail').val(email);
},
/**
* Shows or hides authentication related buttons
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide

View File

@ -1,13 +1,11 @@
import { JitsiConferenceEvents } from '../lib-jitsi-meet';
import {
changeParticipantAvatarID,
changeParticipantAvatarURL,
changeParticipantEmail,
dominantSpeakerChanged,
getLocalParticipant,
participantJoined,
participantLeft,
participantRoleChanged
participantRoleChanged,
participantUpdated
} from '../participants';
import { trackAdded, trackRemoved } from '../tracks';
@ -81,13 +79,22 @@ function _addConferenceListeners(conference, dispatch) {
conference.addCommandListener(
AVATAR_ID_COMMAND,
(data, id) => dispatch(changeParticipantAvatarID(id, data.value)));
(data, id) => dispatch(participantUpdated({
id,
avatarID: data.value
})));
conference.addCommandListener(
AVATAR_URL_COMMAND,
(data, id) => dispatch(changeParticipantAvatarURL(id, data.value)));
(data, id) => dispatch(participantUpdated({
id,
avatarURL: data.value
})));
conference.addCommandListener(
EMAIL_COMMAND,
(data, id) => dispatch(changeParticipantEmail(id, data.value)));
(data, id) => dispatch(participantUpdated({
id,
email: data.value
})));
}
/**

View File

@ -8,75 +8,6 @@ import {
} from './actionTypes';
import { getLocalParticipant } from './functions';
/**
* Action to update a participant's avatar ID.
*
* @param {string} id - Participant's ID.
* @param {string} avatarID - Participant's avatar ID.
* @returns {{
* type: PARTICIPANT_UPDATED,
* participant: {
* id: string,
* avatarID: string,
* }
* }}
*/
export function changeParticipantAvatarID(id, avatarID) {
return {
type: PARTICIPANT_UPDATED,
participant: {
id,
avatarID
}
};
}
/**
* Action to update a participant's avatar URL.
*
* @param {string} id - Participant's ID.
* @param {string} avatarURL - Participant's avatar URL.
* @returns {{
* type: PARTICIPANT_UPDATED,
* participant: {
* id: string,
* avatarURL: string,
* }
* }}
*/
export function changeParticipantAvatarURL(id, avatarURL) {
return {
type: PARTICIPANT_UPDATED,
participant: {
id,
avatarURL
}
};
}
/**
* Action to update a participant's email.
*
* @param {string} id - Participant's ID.
* @param {string} email - Participant's email.
* @returns {{
* type: PARTICIPANT_UPDATED,
* participant: {
* id: string,
* email: string
* }
* }}
*/
export function changeParticipantEmail(id, email) {
return {
type: PARTICIPANT_UPDATED,
participant: {
id,
email
}
};
}
/**
* Create an action for when dominant speaker changes.
*
@ -203,12 +134,28 @@ export function participantLeft(id) {
* }}
*/
export function participantRoleChanged(id, role) {
return participantUpdated({
id,
role
});
}
/**
* Action to signal that some of participant properties has been changed.
*
* @param {Participant} participant={} - Information about participant. To
* identify the participant the object should contain either property id with
* value the id of the participant or property local with value true (if the
* local participant hasn't joined the conference yet).
* @returns {{
* type: PARTICIPANT_UPDATED,
* participant: Participant
* }}
*/
export function participantUpdated(participant = {}) {
return {
type: PARTICIPANT_UPDATED,
participant: {
id,
role
}
participant
};
}

View File

@ -112,7 +112,12 @@ function _participant(state, action) {
case PARTICIPANT_UPDATED: {
const participant = action.participant; // eslint-disable-line no-shadow
const { id } = participant;
const { local } = participant;
let { id } = participant;
if (!id && local) {
id = LOCAL_PARTICIPANT_DEFAULT_ID;
}
if (state.id === id) {
const newState = { ...state };