From 0dff35c0db2a6585722dc9a68c47e41435502866 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 17 Apr 2017 10:52:31 -0500 Subject: [PATCH 1/8] feat(transport): Implement transport module The transport module will be handling all external app communication. --- .jshintignore | 2 + app.js | 2 +- modules/API/API.js | 172 +++++-------- modules/API/constants.js | 7 + modules/API/index.js | 2 + modules/transport/.eslintrc.js | 3 + .../transport/PostMessageTransportBackend.js | 141 ++++++++++ modules/transport/Transport.js | 243 ++++++++++++++++++ modules/transport/constants.js | 20 ++ modules/transport/index.js | 31 +++ modules/util/helpers.js | 15 ++ react/index.web.js | 3 + 12 files changed, 532 insertions(+), 109 deletions(-) create mode 100644 modules/API/constants.js create mode 100644 modules/API/index.js create mode 100644 modules/transport/.eslintrc.js create mode 100644 modules/transport/PostMessageTransportBackend.js create mode 100644 modules/transport/Transport.js create mode 100644 modules/transport/constants.js create mode 100644 modules/transport/index.js diff --git a/.jshintignore b/.jshintignore index 6240b0092..f37de4d03 100644 --- a/.jshintignore +++ b/.jshintignore @@ -9,6 +9,8 @@ node_modules/ # supersedes JSHint. flow-typed/ react/ +modules/API/ +modules/transport/ # The following are checked by ESLint with the minimum configuration which does # not supersede JSHint but take advantage of advanced language features such as diff --git a/app.js b/app.js index 0f65aaf25..0d82d480c 100644 --- a/app.js +++ b/app.js @@ -18,7 +18,7 @@ window.toastr = require("toastr"); import UI from "./modules/UI/UI"; import settings from "./modules/settings/Settings"; import conference from './conference'; -import API from './modules/API/API'; +import API from './modules/API'; import translation from "./modules/translation/translation"; import remoteControl from "./modules/remotecontrol/RemoteControl"; diff --git a/modules/API/API.js b/modules/API/API.js index 436435734..f0111c325 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -1,8 +1,9 @@ -/* global APP, getConfigParamsFromUrl */ - -import postisInit from 'postis'; - import * as JitsiMeetConferenceEvents from '../../ConferenceEvents'; +import { transport } from '../transport'; + +import { API_ID } from './constants'; + +declare var APP: Object; /** * List of the available commands. @@ -17,23 +18,6 @@ let commands = {}; */ let initialScreenSharingState = false; -/** - * JitsiMeetExternalAPI id - unique for a webpage. - */ -const jitsiMeetExternalApiId - = getConfigParamsFromUrl().jitsi_meet_external_api_id; - -/** - * Postis instance. Used to communicate with the external application. If - * undefined, then API is disabled. - */ -let postis; - -/** - * Object that will execute sendMessage. - */ -const target = window.opener || window.parent; - /** * Initializes supported commands. * @@ -55,8 +39,17 @@ function initCommands() { 'remote-control-event': event => APP.remoteControl.onRemoteControlAPIEvent(event) }; - Object.keys(commands).forEach( - key => postis.listen(key, args => commands[key](...args))); + transport.on('event', event => { + const { name, data } = event; + + if (name && commands[name]) { + commands[name](...data); + + return true; + } + + return false; + }); } /** @@ -72,25 +65,13 @@ function onDesktopSharingEnabledChanged(enabled = false) { } } -/** - * Sends message to the external application. - * - * @param {Object} message - The message to be sent. - * @returns {void} - */ -function sendMessage(message) { - if (postis) { - postis.send(message); - } -} - /** * Check whether the API should be enabled or not. * * @returns {boolean} */ function shouldBeEnabled() { - return typeof jitsiMeetExternalApiId === 'number'; + return typeof API_ID === 'number'; } /** @@ -106,21 +87,6 @@ function toggleScreenSharing() { } } -/** - * Sends event object to the external application that has been subscribed for - * that event. - * - * @param {string} name - The name event. - * @param {Object} object - Data associated with the event. - * @returns {void} - */ -function triggerEvent(name, object) { - sendMessage({ - method: name, - params: object - }); -} - /** * Implements API class that communicates with external API class and provides * interface to access Jitsi Meet features by external applications that embed @@ -142,42 +108,42 @@ class API { return; } - if (!postis) { - APP.conference.addListener( - JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, - onDesktopSharingEnabledChanged); - this._initPostis(); - } + /** + * Current status (enabled/disabled) of API. + */ + this.enabled = true; + + APP.conference.addListener( + JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, + onDesktopSharingEnabledChanged); + + initCommands(); } /** - * Initializes postis library. + * Sends message to the external application. * + * @param {string} name - The name of the event. + * @param {Object} data - The data to be sent. * @returns {void} - * - * @private */ - _initPostis() { - const postisOptions = { - window: target - }; - - if (typeof jitsiMeetExternalApiId === 'number') { - postisOptions.scope - = `jitsi_meet_external_api_${jitsiMeetExternalApiId}`; + _sendEvent(name, data = {}) { + if (this.enabled) { + transport.sendEvent({ + name, + data + }); } - postis = postisInit(postisOptions); - initCommands(); } /** * Notify external application (if API is enabled) that message was sent. * - * @param {string} body - Message body. + * @param {string} message - Message body. * @returns {void} */ - notifySendingChatMessage(body) { - triggerEvent('outgoing-message', { 'message': body }); + notifySendingChatMessage(message) { + this._sendEvent('outgoing-message', { message }); } /** @@ -194,14 +160,12 @@ class API { return; } - triggerEvent( - 'incoming-message', - { - 'from': id, - 'message': body, - 'nick': nick, - 'stamp': ts - }); + this._sendEvent('incoming-message', { + from: id, + nick, + message: body, + stamp: ts + }); } /** @@ -212,7 +176,7 @@ class API { * @returns {void} */ notifyUserJoined(id) { - triggerEvent('participant-joined', { id }); + this._sendEvent('participant-joined', { id }); } /** @@ -223,7 +187,7 @@ class API { * @returns {void} */ notifyUserLeft(id) { - triggerEvent('participant-left', { id }); + this._sendEvent('participant-left', { id }); } /** @@ -231,39 +195,36 @@ class API { * nickname. * * @param {string} id - User id. - * @param {string} displayName - User nickname. + * @param {string} displayname - User nickname. * @returns {void} */ - notifyDisplayNameChanged(id, displayName) { - triggerEvent( - 'display-name-change', - { - displayname: displayName, - id - }); + notifyDisplayNameChanged(id, displayname) { + this._sendEvent('display-name-change', { + id, + displayname + }); } /** * Notify external application (if API is enabled) that the conference has * been joined. * - * @param {string} room - The room name. + * @param {string} roomName - The room name. * @returns {void} */ - notifyConferenceJoined(room) { - triggerEvent('video-conference-joined', { roomName: room }); + notifyConferenceJoined(roomName) { + this._sendEvent('video-conference-joined', { roomName }); } /** * Notify external application (if API is enabled) that user changed their * nickname. * - * @param {string} room - User id. - * @param {string} displayName - User nickname. + * @param {string} roomName - User id. * @returns {void} */ - notifyConferenceLeft(room) { - triggerEvent('video-conference-left', { roomName: room }); + notifyConferenceLeft(roomName) { + this._sendEvent('video-conference-left', { roomName }); } /** @@ -273,7 +234,7 @@ class API { * @returns {void} */ notifyReadyToClose() { - triggerEvent('video-ready-to-close', {}); + this._sendEvent('video-ready-to-close', {}); } /** @@ -283,22 +244,17 @@ class API { * @returns {void} */ sendRemoteControlEvent(event) { - sendMessage({ - method: 'remote-control-event', - params: event - }); + this._sendEvent('remote-control-event', event); } /** - * Removes the listeners. + * Disposes the allocated resources. * * @returns {void} */ dispose() { - if (postis) { - postis.destroy(); - postis = undefined; - + if (this.enabled) { + this.enabled = false; APP.conference.removeListener( JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, onDesktopSharingEnabledChanged); diff --git a/modules/API/constants.js b/modules/API/constants.js new file mode 100644 index 000000000..8ecb608bd --- /dev/null +++ b/modules/API/constants.js @@ -0,0 +1,7 @@ +declare var getConfigParamsFromUrl: Function; + +/** + * JitsiMeetExternalAPI id - unique for a webpage. + */ +export const API_ID + = getConfigParamsFromUrl().jitsi_meet_external_api_id; diff --git a/modules/API/index.js b/modules/API/index.js new file mode 100644 index 000000000..198a53aca --- /dev/null +++ b/modules/API/index.js @@ -0,0 +1,2 @@ +export default from './API'; +export * from './constants'; diff --git a/modules/transport/.eslintrc.js b/modules/transport/.eslintrc.js new file mode 100644 index 000000000..28bcd9f77 --- /dev/null +++ b/modules/transport/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + 'extends': '../../react/.eslintrc.js' +}; diff --git a/modules/transport/PostMessageTransportBackend.js b/modules/transport/PostMessageTransportBackend.js new file mode 100644 index 000000000..906d7e34e --- /dev/null +++ b/modules/transport/PostMessageTransportBackend.js @@ -0,0 +1,141 @@ +import Postis from 'postis'; + +/** + * The list of methods of incomming postis messages that we have to support for + * backward compatability for the users that are directly sending messages to + * Jitsi Meet (without using external_api.js) + * + * @type {string[]} + */ +const legacyIncomingMethods = [ 'display-name', 'toggle-audio', 'toggle-video', + 'toggle-film-strip', 'toggle-chat', 'toggle-contact-list', + 'toggle-share-screen', 'video-hangup', 'email', 'avatar-url' ]; + +/** + * The list of methods of outgoing postis messages that we have to support for + * backward compatability for the users that are directly listening to the + * postis messages send by Jitsi Meet(without using external_api.js). + * + * @type {string[]} + */ +const legacyOutgoingMethods = [ 'display-name-change', 'incoming-message', + 'outgoing-message', 'participant-joined', 'participant-left', + 'video-ready-to-close', 'video-conference-joined', + 'video-conference-left' ]; + +/** + * The postis method used for all messages. + * + * @type {string} + */ +const POSTIS_METHOD_NAME = 'data'; + +/** + * The default options for postis. + * + * @type {Object} + */ +const defaultPostisOptions = { + window: window.opener || window.parent +}; + +/** + * Implements message transport using the postMessage API. + */ +export default class PostMessageTransportBackend { + /** + * Creates new PostMessageTransportBackend instance. + * + * @param {Object} options - Optional parameters for configuration of the + * transport. + */ + constructor(options = {}) { + const postisOptions = Object.assign({}, defaultPostisOptions, options); + + this.postis = Postis(postisOptions); + + // backward compatability + legacyIncomingMethods.forEach(method => + this.postis.listen(method, + params => this._onPostisDataReceived(method, params))); + + this.postis.listen(POSTIS_METHOD_NAME, data => + this._dataReceivedCallBack(data)); + + this._dataReceivedCallBack = () => { + // do nothing until real callback is set; + }; + } + + /** + * Handles incomming legacy postis data. + * + * @param {string} method - The method property from postis data object. + * @param {Any} params - The params property from postis data object. + * @returns {void} + */ + _onPostisDataReceived(method, params = {}) { + const newData = { + data: { + name: method, + data: params + } + }; + + this._dataReceivedCallBack(newData); + } + + /** + * Sends the passed data via postis using the old format. + * + * @param {Object} data - The data to be sent. + * @returns {void} + */ + _sendLegacyData(data) { + const method = data.name; + + if (method && legacyOutgoingMethods.indexOf(method) !== -1) { + this.postis.send({ + method, + params: data.data + }); + } + } + + /** + * Disposes the allocated resources. + * + * @returns {void} + */ + dispose() { + this.postis.destroy(); + } + + /** + * Sends the passed data. + * + * @param {Object} data - The data to be sent. + * @returns {void} + */ + send(data) { + this.postis.send({ + method: POSTIS_METHOD_NAME, + params: data + }); + + // For the legacy use case we don't need any new fields defined in + // Transport class. That's why we are passing only the original object + // passed by the consumer of the Transport class which is data.data. + this._sendLegacyData(data.data); + } + + /** + * Sets the callback for receiving data. + * + * @param {Function} callback - The new callback. + * @returns {void} + */ + setDataReceivedCallback(callback) { + this._dataReceivedCallBack = callback; + } +} diff --git a/modules/transport/Transport.js b/modules/transport/Transport.js new file mode 100644 index 000000000..2fa0ae3d9 --- /dev/null +++ b/modules/transport/Transport.js @@ -0,0 +1,243 @@ +import { + MESSAGE_TYPE_EVENT, + MESSAGE_TYPE_RESPONSE, + MESSAGE_TYPE_REQUEST +} from './constants'; + +/** + * Stores the currnet transport that have to be used. + */ +export default class Transport { + /** + * Creates new instance. + * + * @param {Object} options - Optional parameters for configuration of the + * transport. + */ + constructor(options = {}) { + const { transport } = options; + + this._requestID = 0; + + this._responseHandlers = new Map(); + + this._listeners = new Map(); + + this._unprocessedMessages = new Set(); + + this.addListener = this.on; + + if (transport) { + this.setTransport(transport); + } + } + + /** + * Disposes the current transport. + * + * @returns {void} + */ + _disposeTransport() { + if (this._transport) { + this._transport.dispose(); + this._transport = null; + } + } + + /** + * Handles incomming data from the transport. + * + * @param {Object} data - The data. + * @returns {void} + */ + _onDataReceived(data) { + if (data.type === MESSAGE_TYPE_RESPONSE) { + const handler = this._responseHandlers.get(data.id); + + if (handler) { + handler(data); + this._responseHandlers.delete(data.id); + } + + return; + } + + if (data.type === MESSAGE_TYPE_REQUEST) { + this.emit('request', data.data, (result, error) => { + this._transport.send({ + type: MESSAGE_TYPE_RESPONSE, + result, + error, + id: data.id + }); + }); + } else { + this.emit('event', data.data); + } + } + + /** + * Disposes the allocated resources. + * + * @returns {void} + */ + dispose() { + this._responseHandlers.clear(); + this._unprocessedMessages.clear(); + this.removeAllListeners(); + this._disposeTransport(); + } + + /** + * Calls each of the listeners registered for the event named eventName, in + * the order they were registered, passing the supplied arguments to each. + * + * @param {string} eventName - The name of the event. + * @returns {boolean} True if the event had listeners, false otherwise. + */ + emit(eventName, ...args) { + const listenersForEvent = this._listeners.get(eventName); + + if (!listenersForEvent || listenersForEvent.size === 0) { + this._unprocessedMessages.add(args); + + return false; + } + + let isProcessed = false; + + listenersForEvent.forEach(listener => { + isProcessed = listener(...args) || isProcessed; + }); + + if (!isProcessed) { + this._unprocessedMessages.add(args); + } + } + + /** + * Adds the listener function to the listeners collection for the event + * named eventName. + * + * @param {string} eventName - The name of the event. + * @param {Function} listener - The listener that will be added. + * @returns {Transport} References to the instance of Transport class, so + * that calls can be chained. + */ + on(eventName, listener) { + let listenersForEvent = this._listeners.get(eventName); + + if (!listenersForEvent) { + listenersForEvent = new Set(); + this._listeners.set(eventName, listenersForEvent); + } + + listenersForEvent.add(listener); + + this._unprocessedMessages.forEach(args => { + if (listener(...args)) { + this._unprocessedMessages.delete(args); + } + }); + + return this; + } + + /** + * Removes all listeners, or those of the specified eventName. + * + * @param {string} [eventName] - The name of the event. + * @returns {Transport} References to the instance of Transport class, so + * that calls can be chained. + */ + removeAllListeners(eventName) { + if (eventName) { + this._listeners.delete(eventName); + } else { + this._listeners.clear(); + } + + return this; + } + + /** + * Removes the listener function from the listeners collection for the event + * named eventName. + * + * @param {string} eventName - The name of the event. + * @param {Function} listener - The listener that will be removed. + * @returns {Transport} References to the instance of Transport class, so + * that calls can be chained. + */ + removeListener(eventName, listener) { + const listenersForEvent = this._listeners.get(eventName); + + if (listenersForEvent) { + listenersForEvent.delete(listener); + } + + return this; + } + + /** + * Sends the passed data. + * + * @param {Object} data - The data to be sent. + * @returns {void} + */ + sendEvent(data = {}) { + if (this._transport) { + this._transport.send({ + type: MESSAGE_TYPE_EVENT, + data + }); + } + } + + /** + * Sending request. + * + * @param {Object} data - The data for the request. + * @returns {Promise} + */ + sendRequest(data) { + if (!this._transport) { + return Promise.reject(new Error('No transport defined!')); + } + this._requestID++; + const id = this._requestID; + + return new Promise((resolve, reject) => { + this._responseHandlers.set(this._requestID, response => { + const { result, error } = response; + + if (result) { + resolve(result); + } else if (error) { + reject(error); + } else { // no response + reject(new Error('Unexpected response format!')); + } + }); + + this._transport.send({ + id, + type: MESSAGE_TYPE_REQUEST, + data + }); + }); + } + + /** + * Changes the current transport. + * + * @param {Object} transport - The new transport that will be used. + * @returns {void} + */ + setTransport(transport) { + this._disposeTransport(); + this._transport = transport; + this._transport.setDataReceivedCallback( + this._onDataReceived.bind(this)); + } +} diff --git a/modules/transport/constants.js b/modules/transport/constants.js new file mode 100644 index 000000000..02a125a26 --- /dev/null +++ b/modules/transport/constants.js @@ -0,0 +1,20 @@ +/** + * The message type for events. + * + * @type {string} + */ +export const MESSAGE_TYPE_EVENT = 'event'; + +/** + * The message type for responses. + * + * @type {string} + */ +export const MESSAGE_TYPE_RESPONSE = 'response'; + +/** + * The message type for requests. + * + * @type {string} + */ +export const MESSAGE_TYPE_REQUEST = 'request'; diff --git a/modules/transport/index.js b/modules/transport/index.js new file mode 100644 index 000000000..cb7ae6e14 --- /dev/null +++ b/modules/transport/index.js @@ -0,0 +1,31 @@ +import { API_ID } from '../API'; +import { getJitsiMeetGlobalNS } from '../util/helpers'; + +import Transport from './Transport'; +import PostMessageTransportBackend from './PostMessageTransportBackend'; + +/** + * Option for the default low level transport. + * + * @type {Object} + */ +const postMessageOptions = {}; + +if (typeof API_ID === 'number') { + postMessageOptions.scope + = `jitsi_meet_external_api_${API_ID}`; +} + +export const transport = new Transport({ + transport: new PostMessageTransportBackend(postMessageOptions) +}); + +/** + * Sets the transport to passed transport. + * + * @param {Object} newTransport - The new transport. + * @returns {void} + */ +getJitsiMeetGlobalNS().useNewExternalTransport = function(newTransport) { + transport.setTransport(newTransport); +}; diff --git a/modules/util/helpers.js b/modules/util/helpers.js index 55408151a..9c333d6fa 100644 --- a/modules/util/helpers.js +++ b/modules/util/helpers.js @@ -74,3 +74,18 @@ export function debounce(fn, wait = 0, options = {}) { } }; } + +/** + * Returns the namespace for all global variables, functions, etc that we need. + * + * @returns {Object} the namespace. + * + * NOTE: After reactifying everything this should be the only place where + * we store everything that needs to be global (for some reason). + */ +export function getJitsiMeetGlobalNS() { + if(!window.JitsiMeetGlobalNS) { + window.JitsiMeetGlobalNS = { }; + } + return window.JitsiMeetGlobalNS; +} diff --git a/react/index.web.js b/react/index.web.js index 785afb653..d8ef1424e 100644 --- a/react/index.web.js +++ b/react/index.web.js @@ -3,6 +3,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import { transport } from '../modules/transport'; + import config from './config'; import { App } from './features/app'; @@ -34,4 +36,5 @@ window.addEventListener('beforeunload', () => { APP.logCollectorStarted = false; } APP.API.dispose(); + transport.dispose(); }); From 54388b6a0acb60ce58c9c07d89fb8b192f026209 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 17 Apr 2017 14:59:24 -0500 Subject: [PATCH 2/8] ref(remotecontrol): To use transport module instead of API --- conference.js | 2 +- modules/API/API.js | 14 +---- modules/remotecontrol/Receiver.js | 76 ++++++++++++++++++++++---- modules/remotecontrol/RemoteControl.js | 56 +++---------------- 4 files changed, 76 insertions(+), 72 deletions(-) diff --git a/conference.js b/conference.js index 53d6fd7bb..eddcfb32d 100644 --- a/conference.js +++ b/conference.js @@ -603,8 +603,8 @@ export default { APP.store.dispatch(showDesktopSharingButton()); - APP.remoteControl.init(); this._createRoom(tracks); + APP.remoteControl.init(); if (UIUtil.isButtonEnabled('contacts') && !interfaceConfig.filmStripOnly) { diff --git a/modules/API/API.js b/modules/API/API.js index f0111c325..0c1edd2bc 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -35,9 +35,7 @@ function initCommands() { 'toggle-share-screen': toggleScreenSharing, 'video-hangup': () => APP.conference.hangup(), 'email': APP.conference.changeLocalEmail, - 'avatar-url': APP.conference.changeLocalAvatarUrl, - 'remote-control-event': - event => APP.remoteControl.onRemoteControlAPIEvent(event) + 'avatar-url': APP.conference.changeLocalAvatarUrl }; transport.on('event', event => { const { name, data } = event; @@ -237,16 +235,6 @@ class API { this._sendEvent('video-ready-to-close', {}); } - /** - * Sends remote control event. - * - * @param {RemoteControlEvent} event - The remote control event. - * @returns {void} - */ - sendRemoteControlEvent(event) { - this._sendEvent('remote-control-event', event); - } - /** * Disposes the allocated resources. * diff --git a/modules/remotecontrol/Receiver.js b/modules/remotecontrol/Receiver.js index cf6063617..5339158da 100644 --- a/modules/remotecontrol/Receiver.js +++ b/modules/remotecontrol/Receiver.js @@ -1,10 +1,16 @@ -/* global APP, JitsiMeetJS, interfaceConfig */ -const logger = require("jitsi-meet-logger").getLogger(__filename); -import {DISCO_REMOTE_CONTROL_FEATURE, REMOTE_CONTROL_EVENT_TYPE, EVENT_TYPES, - PERMISSIONS_ACTIONS} from "../../service/remotecontrol/Constants"; -import RemoteControlParticipant from "./RemoteControlParticipant"; +/* global APP, JitsiMeetJS, interfaceConfig, config */ import * as JitsiMeetConferenceEvents from '../../ConferenceEvents'; +import { + DISCO_REMOTE_CONTROL_FEATURE, + EVENT_TYPES, + PERMISSIONS_ACTIONS, + REMOTE_CONTROL_EVENT_TYPE +} from "../../service/remotecontrol/Constants"; +import { transport } from '../transport'; +import RemoteControlParticipant from "./RemoteControlParticipant"; + +const logger = require("jitsi-meet-logger").getLogger(__filename); const ConferenceEvents = JitsiMeetJS.events.conference; /** @@ -25,13 +31,24 @@ export default class Receiver extends RemoteControlParticipant { = this._onRemoteControlEvent.bind(this); this._userLeftListener = this._onUserLeft.bind(this); this._hangupListener = this._onHangup.bind(this); + // We expect here that even if we receive the supported event earlier + // it will be cached and we'll receive it. + transport.on('event', data => { + if(data.name === REMOTE_CONTROL_EVENT_TYPE) { + this._onRemoteControlAPIEvent(data.event); + + return true; + } + + return false; + }); } /** * Enables / Disables the remote control * @param {boolean} enabled the new state. */ - enable(enabled) { + _enable(enabled) { if(this.enabled === enabled) { return; } @@ -73,8 +90,11 @@ export default class Receiver extends RemoteControlParticipant { this.controller = null; APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT, this._userLeftListener); - APP.API.sendRemoteControlEvent({ - type: EVENT_TYPES.stop + transport.sendEvent({ + name: REMOTE_CONTROL_EVENT_TYPE, + event: { + type: EVENT_TYPES.stop + } }); if(!dontShowDialog) { APP.UI.messageHandler.openMessageDialog( @@ -113,6 +133,7 @@ export default class Receiver extends RemoteControlParticipant { if(this.controller === null && remoteControlEvent.type === EVENT_TYPES.permissions && remoteControlEvent.action === PERMISSIONS_ACTIONS.request) { + // FIXME: Maybe use transport.sendRequest in this case??? remoteControlEvent.userId = participant.getId(); remoteControlEvent.userJID = participant.getJid(); remoteControlEvent.displayName = participant.getDisplayName() @@ -125,7 +146,10 @@ export default class Receiver extends RemoteControlParticipant { this._stop(); return; } - APP.API.sendRemoteControlEvent(remoteControlEvent); + transport.sendEvent({ + name: REMOTE_CONTROL_EVENT_TYPE, + event: remoteControlEvent + }); } else if(event.type === REMOTE_CONTROL_EVENT_TYPE) { logger.log("Remote control event is ignored because remote " + "control is disabled", event); @@ -133,7 +157,7 @@ export default class Receiver extends RemoteControlParticipant { } /** - * Handles remote control permission events received from the API module. + * Handles remote control permission events. * @param {String} userId the user id of the participant related to the * event. * @param {PERMISSIONS_ACTIONS} action the action related to the event. @@ -173,6 +197,36 @@ export default class Receiver extends RemoteControlParticipant { }); } + /** + * Handles remote control events from the external app. Currently only + * events with type = EVENT_TYPES.supported or EVENT_TYPES.permissions + * @param {RemoteControlEvent} event the remote control event. + */ + _onRemoteControlAPIEvent(event) { + switch(event.type) { + case EVENT_TYPES.supported: + this._onRemoteControlSupported(); + break; + case EVENT_TYPES.permissions: + this._onRemoteControlPermissionsEvent( + event.userId, event.action); + break; + } + } + + /** + * Handles events for support for executing remote control events into + * the wrapper application. + */ + _onRemoteControlSupported() { + logger.log("Remote Control supported."); + if(!config.disableRemoteControl) { + this._enable(true); + } else { + logger.log("Remote Control disabled."); + } + } + /** * Calls the stop method if the other side have left. * @param {string} id - the user id for the participant that have left @@ -187,6 +241,6 @@ export default class Receiver extends RemoteControlParticipant { * Handles hangup events. Disables the receiver. */ _onHangup() { - this.enable(false); + this._enable(false); } } diff --git a/modules/remotecontrol/RemoteControl.js b/modules/remotecontrol/RemoteControl.js index 86f1f51e5..4208b2603 100644 --- a/modules/remotecontrol/RemoteControl.js +++ b/modules/remotecontrol/RemoteControl.js @@ -1,9 +1,11 @@ /* global APP, config */ -const logger = require("jitsi-meet-logger").getLogger(__filename); -import Controller from "./Controller"; -import Receiver from "./Receiver"; -import {EVENT_TYPES, DISCO_REMOTE_CONTROL_FEATURE} - from "../../service/remotecontrol/Constants"; +import { DISCO_REMOTE_CONTROL_FEATURE } + from '../../service/remotecontrol/Constants'; + +import Controller from './Controller'; +import Receiver from './Receiver'; + +const logger = require('jitsi-meet-logger').getLogger(__filename); /** * Implements the remote control functionality. @@ -15,14 +17,12 @@ class RemoteControl { */ constructor() { this.controller = new Controller(); - this.receiver = new Receiver(); - this.enabled = false; this.initialized = false; } /** * Initializes the remote control - checks if the remote control should be - * enabled or not, initializes the API module. + * enabled or not. */ init() { if(config.disableRemoteControl || this.initialized @@ -31,46 +31,8 @@ class RemoteControl { } logger.log("Initializing remote control."); this.initialized = true; - APP.API.init({ - forceEnable: true, - }); this.controller.enable(true); - if(this.enabled) { // supported message came before init. - this._onRemoteControlSupported(); - } - } - - /** - * Handles remote control events from the API module. Currently only events - * with type = EVENT_TYPES.supported or EVENT_TYPES.permissions - * @param {RemoteControlEvent} event the remote control event. - */ - onRemoteControlAPIEvent(event) { - switch(event.type) { - case EVENT_TYPES.supported: - this._onRemoteControlSupported(); - break; - case EVENT_TYPES.permissions: - this.receiver._onRemoteControlPermissionsEvent( - event.userId, event.action); - break; - } - } - - /** - * Handles API event for support for executing remote control events into - * the wrapper application. - */ - _onRemoteControlSupported() { - logger.log("Remote Control supported."); - if(!config.disableRemoteControl) { - this.enabled = true; - if(this.initialized) { - this.receiver.enable(true); - } - } else { - logger.log("Remote Control disabled."); - } + this.receiver = new Receiver(); } /** From 3e055c120129a3a1359454cd4dfded58cd34f817 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 17 Apr 2017 22:17:23 -0500 Subject: [PATCH 3/8] ref(external_api): To use transport module --- modules/API/external/external_api.js | 78 ++++++++++--------- .../transport/PostMessageTransportBackend.js | 26 ++++--- modules/transport/index.js | 9 ++- 3 files changed, 66 insertions(+), 47 deletions(-) diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 6ea00f672..23e1ac13d 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -1,5 +1,8 @@ import EventEmitter from 'events'; -import postisInit from 'postis'; + +import PostMessageTransportBackend + from '../../transport/PostMessageTransportBackend'; +import Transport from '../../transport/Transport'; const logger = require('jitsi-meet-logger').getLogger(__filename); @@ -25,14 +28,14 @@ const commands = { * events expected by jitsi-meet */ const events = { - displayNameChange: 'display-name-change', - incomingMessage: 'incoming-message', - outgoingMessage: 'outgoing-message', - participantJoined: 'participant-joined', - participantLeft: 'participant-left', - readyToClose: 'video-ready-to-close', - videoConferenceJoined: 'video-conference-joined', - videoConferenceLeft: 'video-conference-left' + 'display-name-change': 'displayNameChange', + 'incoming-message': 'incomingMessage', + 'outgoing-message': 'outgoingMessage', + 'participant-joined': 'participantJoined', + 'participant-left': 'participantLeft', + 'video-ready-to-close': 'readyToClose', + 'video-conference-joined': 'videoConferenceJoined', + 'video-conference-left': 'videoConferenceLeft' }; /** @@ -180,9 +183,13 @@ class JitsiMeetExternalAPI extends EventEmitter { }); this._createIFrame(Math.max(height, MIN_HEIGHT), Math.max(width, MIN_WIDTH)); - this.postis = postisInit({ - scope: `jitsi_meet_external_api_${id}`, - window: this.frame.contentWindow + this._transport = new Transport({ + transport: new PostMessageTransportBackend({ + postisOptions: { + scope: `jitsi_meet_external_api_${id}`, + window: this.frame.contentWindow + } + }) }); this.numberOfParticipants = 1; this._setupListeners(); @@ -225,17 +232,28 @@ class JitsiMeetExternalAPI extends EventEmitter { * @private */ _setupListeners() { - this.postis.listen('participant-joined', - changeParticipantNumber.bind(null, this, 1)); - this.postis.listen('participant-left', - changeParticipantNumber.bind(null, this, -1)); - for (const eventName in events) { // eslint-disable-line guard-for-in - const postisMethod = events[eventName]; + this._transport.on('event', event => { + const { name, data } = event; - this.postis.listen(postisMethod, - (...args) => this.emit(eventName, ...args)); - } + if (name === 'participant-joined') { + changeParticipantNumber(this, 1); + } + + if (name === 'participant-left') { + changeParticipantNumber(this, -1); + } + + const eventName = events[name]; + + if (eventName) { + this.emit(eventName, data); + + return true; + } + + return false; + }); } /** @@ -319,10 +337,7 @@ class JitsiMeetExternalAPI extends EventEmitter { * @returns {void} */ dispose() { - if (this.postis) { - this.postis.destroy(); - this.postis = null; - } + this._transport.dispose(); this.removeAllListeners(); if (this.iframeHolder) { this.iframeHolder.parentNode.removeChild(this.iframeHolder); @@ -348,16 +363,9 @@ class JitsiMeetExternalAPI extends EventEmitter { return; } - - if (!this.postis) { - logger.error('Cannot execute command using disposed instance.'); - - return; - } - - this.postis.send({ - method: commands[name], - params: args + this._transport.sendEvent({ + name: commands[name], + data: args }); } diff --git a/modules/transport/PostMessageTransportBackend.js b/modules/transport/PostMessageTransportBackend.js index 906d7e34e..e2e03bd4d 100644 --- a/modules/transport/PostMessageTransportBackend.js +++ b/modules/transport/PostMessageTransportBackend.js @@ -50,14 +50,19 @@ export default class PostMessageTransportBackend { * transport. */ constructor(options = {}) { - const postisOptions = Object.assign({}, defaultPostisOptions, options); + const postisOptions = Object.assign({}, defaultPostisOptions, + options.postisOptions); this.postis = Postis(postisOptions); - // backward compatability - legacyIncomingMethods.forEach(method => - this.postis.listen(method, - params => this._onPostisDataReceived(method, params))); + this._enableLegacyFormat = options.enableLegacyFormat; + + if (!this._enableLegacyFormat) { + // backward compatability + legacyIncomingMethods.forEach(method => + this.postis.listen(method, + params => this._onPostisDataReceived(method, params))); + } this.postis.listen(POSTIS_METHOD_NAME, data => this._dataReceivedCallBack(data)); @@ -123,10 +128,13 @@ export default class PostMessageTransportBackend { params: data }); - // For the legacy use case we don't need any new fields defined in - // Transport class. That's why we are passing only the original object - // passed by the consumer of the Transport class which is data.data. - this._sendLegacyData(data.data); + if (!this._enableLegacyFormat) { + // For the legacy use case we don't need any new fields defined in + // Transport class. That's why we are passing only the original + // object passed by the consumer of the Transport class which is + // data.data. + this._sendLegacyData(data.data); + } } /** diff --git a/modules/transport/index.js b/modules/transport/index.js index cb7ae6e14..d83160e03 100644 --- a/modules/transport/index.js +++ b/modules/transport/index.js @@ -9,15 +9,18 @@ import PostMessageTransportBackend from './PostMessageTransportBackend'; * * @type {Object} */ -const postMessageOptions = {}; +const postisOptions = {}; if (typeof API_ID === 'number') { - postMessageOptions.scope + postisOptions.scope = `jitsi_meet_external_api_${API_ID}`; } export const transport = new Transport({ - transport: new PostMessageTransportBackend(postMessageOptions) + transport: new PostMessageTransportBackend({ + enableLegacyFormat: true, + postisOptions + }) }); /** From e9dc9c47a9e03e35bb792347c19a64b0bda6b156 Mon Sep 17 00:00:00 2001 From: Lyubo Marinov Date: Thu, 27 Apr 2017 15:21:01 -0500 Subject: [PATCH 4/8] Coding style For lack of a better word/phrase, I'm calling all changes coding style. I'm targeting readability through naming and syntax. --- .jshintignore | 2 +- modules/API/API.js | 33 +++--- modules/API/constants.js | 3 +- modules/API/external/external_api.js | 16 ++- modules/remotecontrol/Receiver.js | 26 ++--- modules/remotecontrol/RemoteControl.js | 10 +- .../transport/PostMessageTransportBackend.js | 100 ++++++++++-------- modules/transport/Transport.js | 41 ++++--- modules/transport/index.js | 3 +- 9 files changed, 119 insertions(+), 115 deletions(-) diff --git a/.jshintignore b/.jshintignore index f37de4d03..bf8675b36 100644 --- a/.jshintignore +++ b/.jshintignore @@ -8,9 +8,9 @@ node_modules/ # The following are checked by ESLint with the maximum configuration which # supersedes JSHint. flow-typed/ -react/ modules/API/ modules/transport/ +react/ # The following are checked by ESLint with the minimum configuration which does # not supersede JSHint but take advantage of advanced language features such as diff --git a/modules/API/API.js b/modules/API/API.js index 0c1edd2bc..18c7f3e67 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -37,9 +37,7 @@ function initCommands() { 'email': APP.conference.changeLocalEmail, 'avatar-url': APP.conference.changeLocalAvatarUrl }; - transport.on('event', event => { - const { name, data } = event; - + transport.on('event', ({ data, name }) => { if (name && commands[name]) { commands[name](...data); @@ -101,15 +99,18 @@ class API { * module. * @returns {void} */ - init(options = {}) { - if (!shouldBeEnabled() && !options.forceEnable) { + init({ forceEnable } = {}) { + if (!shouldBeEnabled() && !forceEnable) { return; } /** * Current status (enabled/disabled) of API. + * + * @private + * @type {boolean} */ - this.enabled = true; + this._enabled = true; APP.conference.addListener( JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, @@ -126,10 +127,10 @@ class API { * @returns {void} */ _sendEvent(name, data = {}) { - if (this.enabled) { + if (this._enabled) { transport.sendEvent({ - name, - data + data, + name }); } } @@ -151,17 +152,15 @@ class API { * @param {Object} options - Object with the message properties. * @returns {void} */ - notifyReceivedChatMessage(options = {}) { - const { id, nick, body, ts } = options; - + notifyReceivedChatMessage({ body, id, nick, ts } = {}) { if (APP.conference.isLocalId(id)) { return; } this._sendEvent('incoming-message', { from: id, - nick, message: body, + nick, stamp: ts }); } @@ -198,8 +197,8 @@ class API { */ notifyDisplayNameChanged(id, displayname) { this._sendEvent('display-name-change', { - id, - displayname + displayname, + id }); } @@ -241,8 +240,8 @@ class API { * @returns {void} */ dispose() { - if (this.enabled) { - this.enabled = false; + if (this._enabled) { + this._enabled = false; APP.conference.removeListener( JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED, onDesktopSharingEnabledChanged); diff --git a/modules/API/constants.js b/modules/API/constants.js index 8ecb608bd..e59fbabe0 100644 --- a/modules/API/constants.js +++ b/modules/API/constants.js @@ -3,5 +3,4 @@ declare var getConfigParamsFromUrl: Function; /** * JitsiMeetExternalAPI id - unique for a webpage. */ -export const API_ID - = getConfigParamsFromUrl().jitsi_meet_external_api_id; +export const API_ID = getConfigParamsFromUrl().jitsi_meet_external_api_id; diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 23e1ac13d..24ec9b7c9 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -81,8 +81,8 @@ function configToURLParamsArray(config = {}) { for (const key in config) { // eslint-disable-line guard-for-in try { - params.push(`${key}=${ - encodeURIComponent(JSON.stringify(config[key]))}`); + params.push( + `${key}=${encodeURIComponent(JSON.stringify(config[key]))}`); } catch (e) { console.warn(`Error encoding ${key}: ${e}`); } @@ -233,14 +233,10 @@ class JitsiMeetExternalAPI extends EventEmitter { */ _setupListeners() { - this._transport.on('event', event => { - const { name, data } = event; - + this._transport.on('event', ({ data, name }) => { if (name === 'participant-joined') { changeParticipantNumber(this, 1); - } - - if (name === 'participant-left') { + } else if (name === 'participant-left') { changeParticipantNumber(this, -1); } @@ -364,8 +360,8 @@ class JitsiMeetExternalAPI extends EventEmitter { return; } this._transport.sendEvent({ - name: commands[name], - data: args + data: args, + name: commands[name] }); } diff --git a/modules/remotecontrol/Receiver.js b/modules/remotecontrol/Receiver.js index 5339158da..b6e31150a 100644 --- a/modules/remotecontrol/Receiver.js +++ b/modules/remotecontrol/Receiver.js @@ -1,4 +1,5 @@ -/* global APP, JitsiMeetJS, interfaceConfig, config */ +/* global APP, config, interfaceConfig, JitsiMeetJS */ + import * as JitsiMeetConferenceEvents from '../../ConferenceEvents'; import { DISCO_REMOTE_CONTROL_FEATURE, @@ -10,8 +11,8 @@ import { transport } from '../transport'; import RemoteControlParticipant from "./RemoteControlParticipant"; -const logger = require("jitsi-meet-logger").getLogger(__filename); const ConferenceEvents = JitsiMeetJS.events.conference; +const logger = require("jitsi-meet-logger").getLogger(__filename); /** * This class represents the receiver party for a remote controller session. @@ -33,9 +34,9 @@ export default class Receiver extends RemoteControlParticipant { this._hangupListener = this._onHangup.bind(this); // We expect here that even if we receive the supported event earlier // it will be cached and we'll receive it. - transport.on('event', data => { - if(data.name === REMOTE_CONTROL_EVENT_TYPE) { - this._onRemoteControlAPIEvent(data.event); + transport.on('event', ({ event, name }) => { + if(name === REMOTE_CONTROL_EVENT_TYPE) { + this._onRemoteControlAPIEvent(event); return true; } @@ -193,7 +194,7 @@ export default class Receiver extends RemoteControlParticipant { } this._sendRemoteControlEvent(userId, { type: EVENT_TYPES.permissions, - action: action + action }); } @@ -204,13 +205,12 @@ export default class Receiver extends RemoteControlParticipant { */ _onRemoteControlAPIEvent(event) { switch(event.type) { - case EVENT_TYPES.supported: - this._onRemoteControlSupported(); - break; - case EVENT_TYPES.permissions: - this._onRemoteControlPermissionsEvent( - event.userId, event.action); - break; + case EVENT_TYPES.supported: + this._onRemoteControlSupported(); + break; + case EVENT_TYPES.permissions: + this._onRemoteControlPermissionsEvent(event.userId, event.action); + break; } } diff --git a/modules/remotecontrol/RemoteControl.js b/modules/remotecontrol/RemoteControl.js index 4208b2603..466662471 100644 --- a/modules/remotecontrol/RemoteControl.js +++ b/modules/remotecontrol/RemoteControl.js @@ -25,8 +25,9 @@ class RemoteControl { * enabled or not. */ init() { - if(config.disableRemoteControl || this.initialized - || !APP.conference.isDesktopSharingEnabled) { + if(config.disableRemoteControl + || this.initialized + || !APP.conference.isDesktopSharingEnabled) { return; } logger.log("Initializing remote control."); @@ -42,8 +43,9 @@ class RemoteControl { * the user supports remote control and with false if not. */ checkUserRemoteControlSupport(user) { - return user.getFeatures().then(features => - features.has(DISCO_REMOTE_CONTROL_FEATURE), () => false + return user.getFeatures().then( + features => features.has(DISCO_REMOTE_CONTROL_FEATURE), + () => false ); } } diff --git a/modules/transport/PostMessageTransportBackend.js b/modules/transport/PostMessageTransportBackend.js index e2e03bd4d..f79c96211 100644 --- a/modules/transport/PostMessageTransportBackend.js +++ b/modules/transport/PostMessageTransportBackend.js @@ -1,5 +1,14 @@ import Postis from 'postis'; +/** + * The default options for postis. + * + * @type {Object} + */ +const DEFAULT_POSTIS_OPTIONS = { + window: window.opener || window.parent +}; + /** * The list of methods of incomming postis messages that we have to support for * backward compatability for the users that are directly sending messages to @@ -7,9 +16,18 @@ import Postis from 'postis'; * * @type {string[]} */ -const legacyIncomingMethods = [ 'display-name', 'toggle-audio', 'toggle-video', - 'toggle-film-strip', 'toggle-chat', 'toggle-contact-list', - 'toggle-share-screen', 'video-hangup', 'email', 'avatar-url' ]; +const LEGACY_INCOMING_METHODS = [ + 'avatar-url', + 'display-name', + 'email', + 'toggle-audio', + 'toggle-chat', + 'toggle-contact-list', + 'toggle-film-strip', + 'toggle-share-screen', + 'toggle-video', + 'video-hangup' +]; /** * The list of methods of outgoing postis messages that we have to support for @@ -18,10 +36,16 @@ const legacyIncomingMethods = [ 'display-name', 'toggle-audio', 'toggle-video', * * @type {string[]} */ -const legacyOutgoingMethods = [ 'display-name-change', 'incoming-message', - 'outgoing-message', 'participant-joined', 'participant-left', - 'video-ready-to-close', 'video-conference-joined', - 'video-conference-left' ]; +const LEGACY_OUTGOING_METHODS = [ + 'display-name-change', + 'incoming-message', + 'outgoing-message', + 'participant-joined', + 'participant-left', + 'video-conference-joined', + 'video-conference-left', + 'video-ready-to-close' +]; /** * The postis method used for all messages. @@ -30,15 +54,6 @@ const legacyOutgoingMethods = [ 'display-name-change', 'incoming-message', */ const POSTIS_METHOD_NAME = 'data'; -/** - * The default options for postis. - * - * @type {Object} - */ -const defaultPostisOptions = { - window: window.opener || window.parent -}; - /** * Implements message transport using the postMessage API. */ @@ -49,27 +64,30 @@ export default class PostMessageTransportBackend { * @param {Object} options - Optional parameters for configuration of the * transport. */ - constructor(options = {}) { - const postisOptions = Object.assign({}, defaultPostisOptions, - options.postisOptions); + constructor({ enableLegacyFormat, postisOptions } = {}) { + this.postis = Postis({ + ...DEFAULT_POSTIS_OPTIONS, + ...postisOptions + }); - this.postis = Postis(postisOptions); - - this._enableLegacyFormat = options.enableLegacyFormat; + this._enableLegacyFormat = enableLegacyFormat; if (!this._enableLegacyFormat) { // backward compatability - legacyIncomingMethods.forEach(method => - this.postis.listen(method, - params => this._onPostisDataReceived(method, params))); + LEGACY_INCOMING_METHODS.forEach(method => + this.postis.listen( + method, + params => this._legacyDataReceiveCallback(method, params))); } - this.postis.listen(POSTIS_METHOD_NAME, data => - this._dataReceivedCallBack(data)); - - this._dataReceivedCallBack = () => { - // do nothing until real callback is set; + this._receiveCallback = () => { + // Do nothing until a callback is set by the consumer of + // PostMessageTransportBackend via setReceiveCallback. }; + + this.postis.listen( + POSTIS_METHOD_NAME, + data => this._receiveCallback(data)); } /** @@ -79,15 +97,13 @@ export default class PostMessageTransportBackend { * @param {Any} params - The params property from postis data object. * @returns {void} */ - _onPostisDataReceived(method, params = {}) { - const newData = { + _legacyDataReceiveCallback(method, params = {}) { + this._receiveCallback({ data: { name: method, data: params } - }; - - this._dataReceivedCallBack(newData); + }); } /** @@ -96,13 +112,11 @@ export default class PostMessageTransportBackend { * @param {Object} data - The data to be sent. * @returns {void} */ - _sendLegacyData(data) { - const method = data.name; - - if (method && legacyOutgoingMethods.indexOf(method) !== -1) { + _sendLegacyData({ data, name }) { + if (name && LEGACY_OUTGOING_METHODS.indexOf(name) !== -1) { this.postis.send({ - method, - params: data.data + method: name, + params: data }); } } @@ -143,7 +157,7 @@ export default class PostMessageTransportBackend { * @param {Function} callback - The new callback. * @returns {void} */ - setDataReceivedCallback(callback) { - this._dataReceivedCallBack = callback; + setReceiveCallback(callback) { + this._receiveCallback = callback; } } diff --git a/modules/transport/Transport.js b/modules/transport/Transport.js index 2fa0ae3d9..52d6cca6b 100644 --- a/modules/transport/Transport.js +++ b/modules/transport/Transport.js @@ -14,9 +14,7 @@ export default class Transport { * @param {Object} options - Optional parameters for configuration of the * transport. */ - constructor(options = {}) { - const { transport } = options; - + constructor({ transport } = {}) { this._requestID = 0; this._responseHandlers = new Map(); @@ -66,9 +64,9 @@ export default class Transport { this.emit('request', data.data, (result, error) => { this._transport.send({ type: MESSAGE_TYPE_RESPONSE, - result, error, - id: data.id + id: data.id, + result }); }); } else { @@ -97,22 +95,19 @@ export default class Transport { */ emit(eventName, ...args) { const listenersForEvent = this._listeners.get(eventName); - - if (!listenersForEvent || listenersForEvent.size === 0) { - this._unprocessedMessages.add(args); - - return false; - } - let isProcessed = false; - listenersForEvent.forEach(listener => { - isProcessed = listener(...args) || isProcessed; - }); + if (listenersForEvent && listenersForEvent.size) { + listenersForEvent.forEach(listener => { + isProcessed = listener(...args) || isProcessed; + }); + } if (!isProcessed) { this._unprocessedMessages.add(args); } + + return isProcessed; } /** @@ -146,7 +141,7 @@ export default class Transport { /** * Removes all listeners, or those of the specified eventName. * - * @param {string} [eventName] - The name of the event. + * @param {string} eventName - The name of the event. * @returns {Transport} References to the instance of Transport class, so * that calls can be chained. */ @@ -204,13 +199,13 @@ export default class Transport { if (!this._transport) { return Promise.reject(new Error('No transport defined!')); } + this._requestID++; + const id = this._requestID; return new Promise((resolve, reject) => { - this._responseHandlers.set(this._requestID, response => { - const { result, error } = response; - + this._responseHandlers.set(this._requestID, ({ error, result }) => { if (result) { resolve(result); } else if (error) { @@ -221,9 +216,9 @@ export default class Transport { }); this._transport.send({ - id, type: MESSAGE_TYPE_REQUEST, - data + data, + id }); }); } @@ -236,8 +231,8 @@ export default class Transport { */ setTransport(transport) { this._disposeTransport(); + this._transport = transport; - this._transport.setDataReceivedCallback( - this._onDataReceived.bind(this)); + this._transport.setReceiveCallback(this._onDataReceived.bind(this)); } } diff --git a/modules/transport/index.js b/modules/transport/index.js index d83160e03..788031f63 100644 --- a/modules/transport/index.js +++ b/modules/transport/index.js @@ -12,8 +12,7 @@ import PostMessageTransportBackend from './PostMessageTransportBackend'; const postisOptions = {}; if (typeof API_ID === 'number') { - postisOptions.scope - = `jitsi_meet_external_api_${API_ID}`; + postisOptions.scope = `jitsi_meet_external_api_${API_ID}`; } export const transport = new Transport({ From b49c1c6ba265271c61ddf1f3744e3b118a6b1c1d Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 28 Apr 2017 15:24:20 -0500 Subject: [PATCH 5/8] fix(transport): Code style issues and enableLegacyFormat param bug Improves naming. Fixing typos. enableLegacyFormat param was working like disableLegacyFormat. Improves the structure of transport/index.js --- modules/API/API.js | 9 +- modules/API/constants.js | 4 +- modules/API/external/external_api.js | 9 +- modules/remotecontrol/Receiver.js | 9 +- .../transport/PostMessageTransportBackend.js | 22 +++-- modules/transport/Transport.js | 89 ++++++++++++------- modules/transport/index.js | 46 +++++++--- modules/util/helpers.js | 9 +- react/index.web.js | 4 +- 9 files changed, 141 insertions(+), 60 deletions(-) diff --git a/modules/API/API.js b/modules/API/API.js index 18c7f3e67..a9c50c76f 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -1,5 +1,5 @@ import * as JitsiMeetConferenceEvents from '../../ConferenceEvents'; -import { transport } from '../transport'; +import { getJitsiMeetTransport } from '../transport'; import { API_ID } from './constants'; @@ -18,6 +18,13 @@ let commands = {}; */ let initialScreenSharingState = false; +/** + * The transport instance used for communication with external apps. + * + * @type {Transport} + */ +const transport = getJitsiMeetTransport(); + /** * Initializes supported commands. * diff --git a/modules/API/constants.js b/modules/API/constants.js index e59fbabe0..3bbf0e5dc 100644 --- a/modules/API/constants.js +++ b/modules/API/constants.js @@ -3,4 +3,6 @@ declare var getConfigParamsFromUrl: Function; /** * JitsiMeetExternalAPI id - unique for a webpage. */ -export const API_ID = getConfigParamsFromUrl().jitsi_meet_external_api_id; +export const API_ID + = typeof getConfigParamsFromUrl === 'function' + ? getConfigParamsFromUrl().jitsi_meet_external_api_id : undefined; diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index 24ec9b7c9..b72dc05a4 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -1,8 +1,9 @@ import EventEmitter from 'events'; -import PostMessageTransportBackend - from '../../transport/PostMessageTransportBackend'; -import Transport from '../../transport/Transport'; +import { + PostMessageTransportBackend, + Transport +} from '../../transport'; const logger = require('jitsi-meet-logger').getLogger(__filename); @@ -184,7 +185,7 @@ class JitsiMeetExternalAPI extends EventEmitter { this._createIFrame(Math.max(height, MIN_HEIGHT), Math.max(width, MIN_WIDTH)); this._transport = new Transport({ - transport: new PostMessageTransportBackend({ + backend: new PostMessageTransportBackend({ postisOptions: { scope: `jitsi_meet_external_api_${id}`, window: this.frame.contentWindow diff --git a/modules/remotecontrol/Receiver.js b/modules/remotecontrol/Receiver.js index b6e31150a..444a226db 100644 --- a/modules/remotecontrol/Receiver.js +++ b/modules/remotecontrol/Receiver.js @@ -7,13 +7,20 @@ import { PERMISSIONS_ACTIONS, REMOTE_CONTROL_EVENT_TYPE } from "../../service/remotecontrol/Constants"; -import { transport } from '../transport'; +import { getJitsiMeetTransport } from '../transport'; import RemoteControlParticipant from "./RemoteControlParticipant"; const ConferenceEvents = JitsiMeetJS.events.conference; const logger = require("jitsi-meet-logger").getLogger(__filename); +/** + * The transport instance used for communication with external apps. + * + * @type {Transport} + */ +const transport = getJitsiMeetTransport(); + /** * This class represents the receiver party for a remote controller session. * It handles "remote-control-event" events and sends them to the diff --git a/modules/transport/PostMessageTransportBackend.js b/modules/transport/PostMessageTransportBackend.js index f79c96211..7ab8cc7e6 100644 --- a/modules/transport/PostMessageTransportBackend.js +++ b/modules/transport/PostMessageTransportBackend.js @@ -10,8 +10,8 @@ const DEFAULT_POSTIS_OPTIONS = { }; /** - * The list of methods of incomming postis messages that we have to support for - * backward compatability for the users that are directly sending messages to + * The list of methods of incoming postis messages that we have to support for + * backward compatibility for the users that are directly sending messages to * Jitsi Meet (without using external_api.js) * * @type {string[]} @@ -31,7 +31,7 @@ const LEGACY_INCOMING_METHODS = [ /** * The list of methods of outgoing postis messages that we have to support for - * backward compatability for the users that are directly listening to the + * backward compatibility for the users that are directly listening to the * postis messages send by Jitsi Meet(without using external_api.js). * * @type {string[]} @@ -70,10 +70,18 @@ export default class PostMessageTransportBackend { ...postisOptions }); + /** + * If true PostMessageTransportBackend will process and send data using + * the legacy format and in the same time the current format. Otherwise + * all data received that is using the legacy format will be ignored and + * no data with the legacy format will be sent. + * + * @type {boolean} + */ this._enableLegacyFormat = enableLegacyFormat; - if (!this._enableLegacyFormat) { - // backward compatability + if (this._enableLegacyFormat) { + // backward compatibility LEGACY_INCOMING_METHODS.forEach(method => this.postis.listen( method, @@ -91,7 +99,7 @@ export default class PostMessageTransportBackend { } /** - * Handles incomming legacy postis data. + * Handles incoming legacy postis data. * * @param {string} method - The method property from postis data object. * @param {Any} params - The params property from postis data object. @@ -142,7 +150,7 @@ export default class PostMessageTransportBackend { params: data }); - if (!this._enableLegacyFormat) { + if (this._enableLegacyFormat) { // For the legacy use case we don't need any new fields defined in // Transport class. That's why we are passing only the original // object passed by the consumer of the Transport class which is diff --git a/modules/transport/Transport.js b/modules/transport/Transport.js index 52d6cca6b..1d0eece9d 100644 --- a/modules/transport/Transport.js +++ b/modules/transport/Transport.js @@ -5,45 +5,74 @@ import { } from './constants'; /** - * Stores the currnet transport that have to be used. + * Stores the currnet transport backend that have to be used. Also implements + * request/response mechanism. */ export default class Transport { /** * Creates new instance. * * @param {Object} options - Optional parameters for configuration of the - * transport. + * transport backend. */ - constructor({ transport } = {}) { + constructor({ backend } = {}) { + /** + * The request ID counter used for the id property of the request. This + * property is used to match the responses with the request. + * + * @type {number} + */ this._requestID = 0; + /** + * Maps an IDs of the requests and handlers that will process the + * responses of those requests. + * + * @type {Map} + */ this._responseHandlers = new Map(); + /** + * Maps an event name and listener that have been added to the Transport + * instance. + * + * @type {Map} + */ this._listeners = new Map(); + /** + * A set with the events and requests that were received but not + * processed by any listener. They are later passed on every new + * listener until they are processed. + * + * @type {Set} + */ this._unprocessedMessages = new Set(); + /** + * Alias. + */ this.addListener = this.on; - if (transport) { - this.setTransport(transport); + if (backend) { + this.setBackend(backend); } } /** - * Disposes the current transport. + * Disposes the current transport backend. * * @returns {void} */ - _disposeTransport() { - if (this._transport) { - this._transport.dispose(); - this._transport = null; + _disposeBackend() { + if (this._backend) { + this._backend.dispose(); + this._backend = null; } } /** - * Handles incomming data from the transport. + * Handles incoming data from the transport backend. * * @param {Object} data - The data. * @returns {void} @@ -56,13 +85,9 @@ export default class Transport { handler(data); this._responseHandlers.delete(data.id); } - - return; - } - - if (data.type === MESSAGE_TYPE_REQUEST) { + } else if (data.type === MESSAGE_TYPE_REQUEST) { this.emit('request', data.data, (result, error) => { - this._transport.send({ + this._backend.send({ type: MESSAGE_TYPE_RESPONSE, error, id: data.id, @@ -83,7 +108,7 @@ export default class Transport { this._responseHandlers.clear(); this._unprocessedMessages.clear(); this.removeAllListeners(); - this._disposeTransport(); + this._disposeBackend(); } /** @@ -91,7 +116,8 @@ export default class Transport { * the order they were registered, passing the supplied arguments to each. * * @param {string} eventName - The name of the event. - * @returns {boolean} True if the event had listeners, false otherwise. + * @returns {boolean} True if the event has been processed by any listener, + * false otherwise. */ emit(eventName, ...args) { const listenersForEvent = this._listeners.get(eventName); @@ -141,7 +167,8 @@ export default class Transport { /** * Removes all listeners, or those of the specified eventName. * - * @param {string} eventName - The name of the event. + * @param {string} [eventName] - The name of the event. If this parameter is + * not specified all listeners will be removed. * @returns {Transport} References to the instance of Transport class, so * that calls can be chained. */ @@ -181,8 +208,8 @@ export default class Transport { * @returns {void} */ sendEvent(data = {}) { - if (this._transport) { - this._transport.send({ + if (this._backend) { + this._backend.send({ type: MESSAGE_TYPE_EVENT, data }); @@ -196,8 +223,8 @@ export default class Transport { * @returns {Promise} */ sendRequest(data) { - if (!this._transport) { - return Promise.reject(new Error('No transport defined!')); + if (!this._backend) { + return Promise.reject(new Error('No transport backend defined!')); } this._requestID++; @@ -215,7 +242,7 @@ export default class Transport { } }); - this._transport.send({ + this._backend.send({ type: MESSAGE_TYPE_REQUEST, data, id @@ -224,15 +251,15 @@ export default class Transport { } /** - * Changes the current transport. + * Changes the current backend transport. * - * @param {Object} transport - The new transport that will be used. + * @param {Object} backend - The new transport backend that will be used. * @returns {void} */ - setTransport(transport) { - this._disposeTransport(); + setBackend(backend) { + this._disposeBackend(); - this._transport = transport; - this._transport.setReceiveCallback(this._onDataReceived.bind(this)); + this._backend = backend; + this._backend.setReceiveCallback(this._onDataReceived.bind(this)); } } diff --git a/modules/transport/index.js b/modules/transport/index.js index 788031f63..4fefa93aa 100644 --- a/modules/transport/index.js +++ b/modules/transport/index.js @@ -1,9 +1,16 @@ -import { API_ID } from '../API'; +// FIXME: change to '../API' when we update to webpack2. If we do this now all +// files from API modules will be included in external_api.js. +import { API_ID } from '../API/constants'; import { getJitsiMeetGlobalNS } from '../util/helpers'; import Transport from './Transport'; import PostMessageTransportBackend from './PostMessageTransportBackend'; +export { + Transport, + PostMessageTransportBackend +}; + /** * Option for the default low level transport. * @@ -15,19 +22,38 @@ if (typeof API_ID === 'number') { postisOptions.scope = `jitsi_meet_external_api_${API_ID}`; } -export const transport = new Transport({ - transport: new PostMessageTransportBackend({ - enableLegacyFormat: true, - postisOptions - }) -}); +/** + * The instance of Transport class that will be used by Jitsi Meet. + * + * @type {Transport} + */ +let transport; + +/** + * Returns the instance of Transport class that will be used by Jitsi Meet. + * + * @returns {Transport} + */ +export function getJitsiMeetTransport() { + if (!transport) { + transport = new Transport({ + backend: new PostMessageTransportBackend({ + enableLegacyFormat: true, + postisOptions + }) + }); + } + + return transport; +} /** * Sets the transport to passed transport. * - * @param {Object} newTransport - The new transport. + * @param {Object} externalTransportBackend - The new transport. * @returns {void} */ -getJitsiMeetGlobalNS().useNewExternalTransport = function(newTransport) { - transport.setTransport(newTransport); +getJitsiMeetGlobalNS().setExternalTransportBackend = function( + externalTransportBackend) { + transport.setBackend(externalTransportBackend); }; diff --git a/modules/util/helpers.js b/modules/util/helpers.js index 9c333d6fa..e824bb786 100644 --- a/modules/util/helpers.js +++ b/modules/util/helpers.js @@ -84,8 +84,11 @@ export function debounce(fn, wait = 0, options = {}) { * we store everything that needs to be global (for some reason). */ export function getJitsiMeetGlobalNS() { - if(!window.JitsiMeetGlobalNS) { - window.JitsiMeetGlobalNS = { }; + if(!window.JitsiMeetJS) { + window.JitsiMeetJS = { }; } - return window.JitsiMeetGlobalNS; + if(!window.JitsiMeetJS.app) { + window.JitsiMeetJS.app = { }; + } + return window.JitsiMeetJS.app; } diff --git a/react/index.web.js b/react/index.web.js index d8ef1424e..987e1d4fc 100644 --- a/react/index.web.js +++ b/react/index.web.js @@ -3,7 +3,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import { transport } from '../modules/transport'; +import { getJitsiMeetTransport } from '../modules/transport'; import config from './config'; import { App } from './features/app'; @@ -36,5 +36,5 @@ window.addEventListener('beforeunload', () => { APP.logCollectorStarted = false; } APP.API.dispose(); - transport.dispose(); + getJitsiMeetTransport().dispose(); }); From 96bde3ff4417cf3e051de57d679df6ec7c31a5a3 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Fri, 28 Apr 2017 16:03:36 -0500 Subject: [PATCH 6/8] fix(trnasport): Names of the arguments for Transport and backend Now the backends are working with 'message' and Transport is working with 'request', 'response' and 'event'. --- .../transport/PostMessageTransportBackend.js | 43 ++++++++++--------- modules/transport/Transport.js | 38 ++++++++-------- 2 files changed, 42 insertions(+), 39 deletions(-) diff --git a/modules/transport/PostMessageTransportBackend.js b/modules/transport/PostMessageTransportBackend.js index 7ab8cc7e6..ffdf2b180 100644 --- a/modules/transport/PostMessageTransportBackend.js +++ b/modules/transport/PostMessageTransportBackend.js @@ -52,7 +52,7 @@ const LEGACY_OUTGOING_METHODS = [ * * @type {string} */ -const POSTIS_METHOD_NAME = 'data'; +const POSTIS_METHOD_NAME = 'message'; /** * Implements message transport using the postMessage API. @@ -71,10 +71,10 @@ export default class PostMessageTransportBackend { }); /** - * If true PostMessageTransportBackend will process and send data using - * the legacy format and in the same time the current format. Otherwise - * all data received that is using the legacy format will be ignored and - * no data with the legacy format will be sent. + * If true PostMessageTransportBackend will process and send messages + * using the legacy format and in the same time the current format. + * Otherwise all messages (outgoing and incoming) that are using the + * legacy format will be ignored. * * @type {boolean} */ @@ -85,7 +85,10 @@ export default class PostMessageTransportBackend { LEGACY_INCOMING_METHODS.forEach(method => this.postis.listen( method, - params => this._legacyDataReceiveCallback(method, params))); + params => + this._legacyMessageReceivedCallback(method, params) + ) + ); } this._receiveCallback = () => { @@ -95,17 +98,17 @@ export default class PostMessageTransportBackend { this.postis.listen( POSTIS_METHOD_NAME, - data => this._receiveCallback(data)); + message => this._receiveCallback(message)); } /** - * Handles incoming legacy postis data. + * Handles incoming legacy postis messages. * - * @param {string} method - The method property from postis data object. - * @param {Any} params - The params property from postis data object. + * @param {string} method - The method property from the postis message. + * @param {Any} params - The params property from the postis message. * @returns {void} */ - _legacyDataReceiveCallback(method, params = {}) { + _legacyMessageReceivedCallback(method, params = {}) { this._receiveCallback({ data: { name: method, @@ -115,12 +118,12 @@ export default class PostMessageTransportBackend { } /** - * Sends the passed data via postis using the old format. + * Sends the passed message via postis using the old format. * - * @param {Object} data - The data to be sent. + * @param {Object} legacyMessage - The message to be sent. * @returns {void} */ - _sendLegacyData({ data, name }) { + _sendLegacyMessage({ data, name }) { if (name && LEGACY_OUTGOING_METHODS.indexOf(name) !== -1) { this.postis.send({ method: name, @@ -139,23 +142,23 @@ export default class PostMessageTransportBackend { } /** - * Sends the passed data. + * Sends the passed message. * - * @param {Object} data - The data to be sent. + * @param {Object} message - The message to be sent. * @returns {void} */ - send(data) { + send(message) { this.postis.send({ method: POSTIS_METHOD_NAME, - params: data + params: message }); if (this._enableLegacyFormat) { // For the legacy use case we don't need any new fields defined in // Transport class. That's why we are passing only the original // object passed by the consumer of the Transport class which is - // data.data. - this._sendLegacyData(data.data); + // message.data. + this._sendLegacyMessage(message.data); } } diff --git a/modules/transport/Transport.js b/modules/transport/Transport.js index 1d0eece9d..f1fd658a0 100644 --- a/modules/transport/Transport.js +++ b/modules/transport/Transport.js @@ -72,30 +72,30 @@ export default class Transport { } /** - * Handles incoming data from the transport backend. + * Handles incoming messages from the transport backend. * - * @param {Object} data - The data. + * @param {Object} message - The message. * @returns {void} */ - _onDataReceived(data) { - if (data.type === MESSAGE_TYPE_RESPONSE) { - const handler = this._responseHandlers.get(data.id); + _onMessageReceived(message) { + if (message.type === MESSAGE_TYPE_RESPONSE) { + const handler = this._responseHandlers.get(message.id); if (handler) { - handler(data); - this._responseHandlers.delete(data.id); + handler(message); + this._responseHandlers.delete(message.id); } - } else if (data.type === MESSAGE_TYPE_REQUEST) { - this.emit('request', data.data, (result, error) => { + } else if (message.type === MESSAGE_TYPE_REQUEST) { + this.emit('request', message.data, (result, error) => { this._backend.send({ type: MESSAGE_TYPE_RESPONSE, error, - id: data.id, + id: message.id, result }); }); } else { - this.emit('event', data.data); + this.emit('event', message.data); } } @@ -202,16 +202,16 @@ export default class Transport { } /** - * Sends the passed data. + * Sends the passed event. * - * @param {Object} data - The data to be sent. + * @param {Object} event - The event to be sent. * @returns {void} */ - sendEvent(data = {}) { + sendEvent(event = {}) { if (this._backend) { this._backend.send({ type: MESSAGE_TYPE_EVENT, - data + data: event }); } } @@ -219,10 +219,10 @@ export default class Transport { /** * Sending request. * - * @param {Object} data - The data for the request. + * @param {Object} request - The request to be sent. * @returns {Promise} */ - sendRequest(data) { + sendRequest(request) { if (!this._backend) { return Promise.reject(new Error('No transport backend defined!')); } @@ -244,7 +244,7 @@ export default class Transport { this._backend.send({ type: MESSAGE_TYPE_REQUEST, - data, + data: request, id }); }); @@ -260,6 +260,6 @@ export default class Transport { this._disposeBackend(); this._backend = backend; - this._backend.setReceiveCallback(this._onDataReceived.bind(this)); + this._backend.setReceiveCallback(this._onMessageReceived.bind(this)); } } From dfc94ff1449a441377dabc0b6dd08912924f9212 Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 1 May 2017 15:59:18 -0500 Subject: [PATCH 7/8] ref(iframe_API): Changing the format of the outgoing messages for API.js --- modules/API/API.js | 44 ++++++++++++------- modules/API/external/external_api.js | 2 +- .../transport/PostMessageTransportBackend.js | 2 +- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/modules/API/API.js b/modules/API/API.js index a9c50c76f..b41f847f2 100644 --- a/modules/API/API.js +++ b/modules/API/API.js @@ -127,18 +127,14 @@ class API { } /** - * Sends message to the external application. + * Sends event to the external application. * - * @param {string} name - The name of the event. - * @param {Object} data - The data to be sent. + * @param {Object} event - The event to be sent. * @returns {void} */ - _sendEvent(name, data = {}) { + _sendEvent(event = {}) { if (this._enabled) { - transport.sendEvent({ - data, - name - }); + transport.sendEvent(event); } } @@ -149,7 +145,10 @@ class API { * @returns {void} */ notifySendingChatMessage(message) { - this._sendEvent('outgoing-message', { message }); + this._sendEvent({ + name: 'outgoing-message', + message + }); } /** @@ -164,7 +163,8 @@ class API { return; } - this._sendEvent('incoming-message', { + this._sendEvent({ + name: 'incoming-message', from: id, message: body, nick, @@ -180,7 +180,10 @@ class API { * @returns {void} */ notifyUserJoined(id) { - this._sendEvent('participant-joined', { id }); + this._sendEvent({ + name: 'participant-joined', + id + }); } /** @@ -191,7 +194,10 @@ class API { * @returns {void} */ notifyUserLeft(id) { - this._sendEvent('participant-left', { id }); + this._sendEvent({ + name: 'participant-left', + id + }); } /** @@ -203,7 +209,7 @@ class API { * @returns {void} */ notifyDisplayNameChanged(id, displayname) { - this._sendEvent('display-name-change', { + this._sendEvent({ name: 'display-name-change', displayname, id }); @@ -217,7 +223,10 @@ class API { * @returns {void} */ notifyConferenceJoined(roomName) { - this._sendEvent('video-conference-joined', { roomName }); + this._sendEvent({ + name: 'video-conference-joined', + roomName + }); } /** @@ -228,7 +237,10 @@ class API { * @returns {void} */ notifyConferenceLeft(roomName) { - this._sendEvent('video-conference-left', { roomName }); + this._sendEvent({ + name: 'video-conference-left', + roomName + }); } /** @@ -238,7 +250,7 @@ class API { * @returns {void} */ notifyReadyToClose() { - this._sendEvent('video-ready-to-close', {}); + this._sendEvent({ name: 'video-ready-to-close' }); } /** diff --git a/modules/API/external/external_api.js b/modules/API/external/external_api.js index b72dc05a4..a2e40867b 100644 --- a/modules/API/external/external_api.js +++ b/modules/API/external/external_api.js @@ -234,7 +234,7 @@ class JitsiMeetExternalAPI extends EventEmitter { */ _setupListeners() { - this._transport.on('event', ({ data, name }) => { + this._transport.on('event', ({ name, ...data }) => { if (name === 'participant-joined') { changeParticipantNumber(this, 1); } else if (name === 'participant-left') { diff --git a/modules/transport/PostMessageTransportBackend.js b/modules/transport/PostMessageTransportBackend.js index ffdf2b180..d0a72d0a0 100644 --- a/modules/transport/PostMessageTransportBackend.js +++ b/modules/transport/PostMessageTransportBackend.js @@ -123,7 +123,7 @@ export default class PostMessageTransportBackend { * @param {Object} legacyMessage - The message to be sent. * @returns {void} */ - _sendLegacyMessage({ data, name }) { + _sendLegacyMessage({ name, ...data }) { if (name && LEGACY_OUTGOING_METHODS.indexOf(name) !== -1) { this.postis.send({ method: name, From b297aa3f3ae57252840445813425d79ffd5c7e9e Mon Sep 17 00:00:00 2001 From: hristoterezov Date: Mon, 1 May 2017 17:11:26 -0500 Subject: [PATCH 8/8] ref(remotecontrol): Changing the format of the messages --- .jshintignore | 1 + modules/remotecontrol/Controller.js | 17 ++++--- modules/remotecontrol/Receiver.js | 46 +++++++++---------- .../remotecontrol/RemoteControlParticipant.js | 6 ++- modules/transport/Transport.js | 2 +- 5 files changed, 37 insertions(+), 35 deletions(-) diff --git a/.jshintignore b/.jshintignore index bf8675b36..053199aee 100644 --- a/.jshintignore +++ b/.jshintignore @@ -9,6 +9,7 @@ node_modules/ # supersedes JSHint. flow-typed/ modules/API/ +modules/remotecontrol/RemoteControlParticipant.js modules/transport/ react/ diff --git a/modules/remotecontrol/Controller.js b/modules/remotecontrol/Controller.js index 44f338198..0adb15ea5 100644 --- a/modules/remotecontrol/Controller.js +++ b/modules/remotecontrol/Controller.js @@ -132,15 +132,14 @@ export default class Controller extends RemoteControlParticipant { * @param {RemoteControlEvent} event the remote control event. */ _handleReply(participant, event) { - const remoteControlEvent = event.event; const userId = participant.getId(); - if(this.enabled && event.type === REMOTE_CONTROL_EVENT_TYPE - && remoteControlEvent.type === EVENT_TYPES.permissions + if(this.enabled && event.name === REMOTE_CONTROL_EVENT_TYPE + && event.type === EVENT_TYPES.permissions && userId === this.requestedParticipant) { - if(remoteControlEvent.action !== PERMISSIONS_ACTIONS.grant) { + if(event.action !== PERMISSIONS_ACTIONS.grant) { this.area = null; } - switch(remoteControlEvent.action) { + switch(event.action) { case PERMISSIONS_ACTIONS.grant: { this.controlledParticipant = userId; logger.log("Remote control permissions granted to: " @@ -166,13 +165,13 @@ export default class Controller extends RemoteControlParticipant { * @param {JitsiParticipant} participant the participant that has sent the * event * @param {Object} event EndpointMessage event from the data channels. - * @property {string} type property. The function process only events of - * type REMOTE_CONTROL_EVENT_TYPE + * @property {string} type property. The function process only events with + * name REMOTE_CONTROL_EVENT_TYPE * @property {RemoteControlEvent} event - the remote control event. */ _handleRemoteControlStoppedEvent(participant, event) { - if(this.enabled && event.type === REMOTE_CONTROL_EVENT_TYPE - && event.event.type === EVENT_TYPES.stop + if(this.enabled && event.name === REMOTE_CONTROL_EVENT_TYPE + && event.type === EVENT_TYPES.stop && participant.getId() === this.controlledParticipant) { this._stop(); } diff --git a/modules/remotecontrol/Receiver.js b/modules/remotecontrol/Receiver.js index 444a226db..50ba939a2 100644 --- a/modules/remotecontrol/Receiver.js +++ b/modules/remotecontrol/Receiver.js @@ -6,10 +6,10 @@ import { EVENT_TYPES, PERMISSIONS_ACTIONS, REMOTE_CONTROL_EVENT_TYPE -} from "../../service/remotecontrol/Constants"; +} from '../../service/remotecontrol/Constants'; import { getJitsiMeetTransport } from '../transport'; -import RemoteControlParticipant from "./RemoteControlParticipant"; +import RemoteControlParticipant from './RemoteControlParticipant'; const ConferenceEvents = JitsiMeetJS.events.conference; const logger = require("jitsi-meet-logger").getLogger(__filename); @@ -41,8 +41,8 @@ export default class Receiver extends RemoteControlParticipant { this._hangupListener = this._onHangup.bind(this); // We expect here that even if we receive the supported event earlier // it will be cached and we'll receive it. - transport.on('event', ({ event, name }) => { - if(name === REMOTE_CONTROL_EVENT_TYPE) { + transport.on('event', event => { + if (event.name === REMOTE_CONTROL_EVENT_TYPE) { this._onRemoteControlAPIEvent(event); return true; @@ -100,9 +100,7 @@ export default class Receiver extends RemoteControlParticipant { this._userLeftListener); transport.sendEvent({ name: REMOTE_CONTROL_EVENT_TYPE, - event: { - type: EVENT_TYPES.stop - } + type: EVENT_TYPES.stop }); if(!dontShowDialog) { APP.UI.messageHandler.openMessageDialog( @@ -131,16 +129,21 @@ export default class Receiver extends RemoteControlParticipant { * module. * @param {JitsiParticipant} participant the controller participant * @param {Object} event EndpointMessage event from the data channels. - * @property {string} type property. The function process only events of - * type REMOTE_CONTROL_EVENT_TYPE + * @property {string} type property. The function process only events with + * name REMOTE_CONTROL_EVENT_TYPE * @property {RemoteControlEvent} event - the remote control event. */ _onRemoteControlEvent(participant, event) { - if(this.enabled && event.type === REMOTE_CONTROL_EVENT_TYPE) { - const remoteControlEvent = event.event; - if(this.controller === null - && remoteControlEvent.type === EVENT_TYPES.permissions - && remoteControlEvent.action === PERMISSIONS_ACTIONS.request) { + if (event.name !== REMOTE_CONTROL_EVENT_TYPE) { + return; + } + + const remoteControlEvent = Object.assign({}, event); + + if (this.enabled) { + if (this.controller === null + && event.type === EVENT_TYPES.permissions + && event.action === PERMISSIONS_ACTIONS.request) { // FIXME: Maybe use transport.sendRequest in this case??? remoteControlEvent.userId = participant.getId(); remoteControlEvent.userJID = participant.getJid(); @@ -148,17 +151,14 @@ export default class Receiver extends RemoteControlParticipant { || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME; remoteControlEvent.screenSharing = APP.conference.isSharingScreen; - } else if(this.controller !== participant.getId()) { + } else if (this.controller !== participant.getId()) { return; - } else if(remoteControlEvent.type === EVENT_TYPES.stop) { + } else if (event.type === EVENT_TYPES.stop) { this._stop(); return; } - transport.sendEvent({ - name: REMOTE_CONTROL_EVENT_TYPE, - event: remoteControlEvent - }); - } else if(event.type === REMOTE_CONTROL_EVENT_TYPE) { + transport.sendEvent(remoteControlEvent); + } else { logger.log("Remote control event is ignored because remote " + "control is disabled", event); } @@ -171,7 +171,7 @@ export default class Receiver extends RemoteControlParticipant { * @param {PERMISSIONS_ACTIONS} action the action related to the event. */ _onRemoteControlPermissionsEvent(userId, action) { - if(action === PERMISSIONS_ACTIONS.grant) { + if (action === PERMISSIONS_ACTIONS.grant) { APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT, this._userLeftListener); this.controller = userId; @@ -227,7 +227,7 @@ export default class Receiver extends RemoteControlParticipant { */ _onRemoteControlSupported() { logger.log("Remote Control supported."); - if(!config.disableRemoteControl) { + if (!config.disableRemoteControl) { this._enable(true); } else { logger.log("Remote Control disabled."); diff --git a/modules/remotecontrol/RemoteControlParticipant.js b/modules/remotecontrol/RemoteControlParticipant.js index 0f283ba9f..48bf77974 100644 --- a/modules/remotecontrol/RemoteControlParticipant.js +++ b/modules/remotecontrol/RemoteControlParticipant.js @@ -31,8 +31,10 @@ export default class RemoteControlParticipant { return; } try{ - APP.conference.sendEndpointMessage(to, - {type: REMOTE_CONTROL_EVENT_TYPE, event}); + APP.conference.sendEndpointMessage(to, { + name: REMOTE_CONTROL_EVENT_TYPE, + ...event + }); } catch (e) { logger.error("Failed to send EndpointMessage via the datachannels", e); diff --git a/modules/transport/Transport.js b/modules/transport/Transport.js index f1fd658a0..0b7b395e1 100644 --- a/modules/transport/Transport.js +++ b/modules/transport/Transport.js @@ -232,7 +232,7 @@ export default class Transport { const id = this._requestID; return new Promise((resolve, reject) => { - this._responseHandlers.set(this._requestID, ({ error, result }) => { + this._responseHandlers.set(id, ({ error, result }) => { if (result) { resolve(result); } else if (error) {