Bläddra i källkod

Merge branch 'abstract_transport2'

Additionally, attempt to move closer to the coding style adopted by
react/.
j8
Lyubo Marinov 8 år sedan
förälder
incheckning
75a486ff96

+ 3
- 0
.jshintignore Visa fil

@@ -8,6 +8,9 @@ node_modules/
8 8
 # The following are checked by ESLint with the maximum configuration which
9 9
 # supersedes JSHint.
10 10
 flow-typed/
11
+modules/API/
12
+modules/remotecontrol/RemoteControlParticipant.js
13
+modules/transport/
11 14
 react/
12 15
 
13 16
 # The following are checked by ESLint with the minimum configuration which does

+ 1
- 1
app.js Visa fil

@@ -18,7 +18,7 @@ window.toastr = require("toastr");
18 18
 import UI from "./modules/UI/UI";
19 19
 import settings from "./modules/settings/Settings";
20 20
 import conference from './conference';
21
-import API from './modules/API/API';
21
+import API from './modules/API';
22 22
 
23 23
 import translation from "./modules/translation/translation";
24 24
 import remoteControl from "./modules/remotecontrol/RemoteControl";

+ 1
- 1
conference.js Visa fil

@@ -603,8 +603,8 @@ export default {
603 603
 
604 604
                 APP.store.dispatch(showDesktopSharingButton());
605 605
 
606
-                APP.remoteControl.init();
607 606
                 this._createRoom(tracks);
607
+                APP.remoteControl.init();
608 608
 
609 609
                 if (UIUtil.isButtonEnabled('contacts')
610 610
                     && !interfaceConfig.filmStripOnly) {

+ 84
- 121
modules/API/API.js Visa fil

@@ -1,8 +1,9 @@
1
-/* global APP, getConfigParamsFromUrl */
1
+import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
2
+import { getJitsiMeetTransport } from '../transport';
2 3
 
3
-import postisInit from 'postis';
4
+import { API_ID } from './constants';
4 5
 
5
-import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
6
+declare var APP: Object;
6 7
 
7 8
 /**
8 9
  * List of the available commands.
@@ -18,21 +19,11 @@ let commands = {};
18 19
 let initialScreenSharingState = false;
19 20
 
20 21
 /**
21
- * JitsiMeetExternalAPI id - unique for a webpage.
22
- */
23
-const jitsiMeetExternalApiId
24
-    = getConfigParamsFromUrl().jitsi_meet_external_api_id;
25
-
26
-/**
27
- * Postis instance. Used to communicate with the external application. If
28
- * undefined, then API is disabled.
29
- */
30
-let postis;
31
-
32
-/**
33
- * Object that will execute sendMessage.
22
+ * The transport instance used for communication with external apps.
23
+ *
24
+ * @type {Transport}
34 25
  */
35
-const target = window.opener || window.parent;
26
+const transport = getJitsiMeetTransport();
36 27
 
37 28
 /**
38 29
  * Initializes supported commands.
@@ -51,12 +42,17 @@ function initCommands() {
51 42
         'toggle-share-screen': toggleScreenSharing,
52 43
         'video-hangup': () => APP.conference.hangup(),
53 44
         'email': APP.conference.changeLocalEmail,
54
-        'avatar-url': APP.conference.changeLocalAvatarUrl,
55
-        'remote-control-event':
56
-            event => APP.remoteControl.onRemoteControlAPIEvent(event)
45
+        'avatar-url': APP.conference.changeLocalAvatarUrl
57 46
     };
58
-    Object.keys(commands).forEach(
59
-        key => postis.listen(key, args => commands[key](...args)));
47
+    transport.on('event', ({ data, name }) => {
48
+        if (name && commands[name]) {
49
+            commands[name](...data);
50
+
51
+            return true;
52
+        }
53
+
54
+        return false;
55
+    });
60 56
 }
61 57
 
62 58
 /**
@@ -72,25 +68,13 @@ function onDesktopSharingEnabledChanged(enabled = false) {
72 68
     }
73 69
 }
74 70
 
75
-/**
76
- * Sends message to the external application.
77
- *
78
- * @param {Object} message - The message to be sent.
79
- * @returns {void}
80
- */
81
-function sendMessage(message) {
82
-    if (postis) {
83
-        postis.send(message);
84
-    }
85
-}
86
-
87 71
 /**
88 72
  * Check whether the API should be enabled or not.
89 73
  *
90 74
  * @returns {boolean}
91 75
  */
92 76
 function shouldBeEnabled() {
93
-    return typeof jitsiMeetExternalApiId === 'number';
77
+    return typeof API_ID === 'number';
94 78
 }
95 79
 
96 80
 /**
@@ -106,21 +90,6 @@ function toggleScreenSharing() {
106 90
     }
107 91
 }
108 92
 
109
-/**
110
- * Sends event object to the external application that has been subscribed for
111
- * that event.
112
- *
113
- * @param {string} name - The name event.
114
- * @param {Object} object - Data associated with the event.
115
- * @returns {void}
116
- */
117
-function triggerEvent(name, object) {
118
-    sendMessage({
119
-        method: name,
120
-        params: object
121
-    });
122
-}
123
-
124 93
 /**
125 94
  * Implements API class that communicates with external API class and provides
126 95
  * interface to access Jitsi Meet features by external applications that embed
@@ -137,47 +106,49 @@ class API {
137 106
      * module.
138 107
      * @returns {void}
139 108
      */
140
-    init(options = {}) {
141
-        if (!shouldBeEnabled() && !options.forceEnable) {
109
+    init({ forceEnable } = {}) {
110
+        if (!shouldBeEnabled() && !forceEnable) {
142 111
             return;
143 112
         }
144 113
 
145
-        if (!postis) {
146
-            APP.conference.addListener(
147
-                JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
148
-                onDesktopSharingEnabledChanged);
149
-            this._initPostis();
150
-        }
114
+        /**
115
+         * Current status (enabled/disabled) of API.
116
+         *
117
+         * @private
118
+         * @type {boolean}
119
+         */
120
+        this._enabled = true;
121
+
122
+        APP.conference.addListener(
123
+            JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
124
+            onDesktopSharingEnabledChanged);
125
+
126
+        initCommands();
151 127
     }
152 128
 
153 129
     /**
154
-     * Initializes postis library.
130
+     * Sends event to the external application.
155 131
      *
132
+     * @param {Object} event - The event to be sent.
156 133
      * @returns {void}
157
-     *
158
-     * @private
159 134
      */
160
-    _initPostis() {
161
-        const postisOptions = {
162
-            window: target
163
-        };
164
-
165
-        if (typeof jitsiMeetExternalApiId === 'number') {
166
-            postisOptions.scope
167
-                = `jitsi_meet_external_api_${jitsiMeetExternalApiId}`;
135
+    _sendEvent(event = {}) {
136
+        if (this._enabled) {
137
+            transport.sendEvent(event);
168 138
         }
169
-        postis = postisInit(postisOptions);
170
-        initCommands();
171 139
     }
172 140
 
173 141
     /**
174 142
      * Notify external application (if API is enabled) that message was sent.
175 143
      *
176
-     * @param {string} body - Message body.
144
+     * @param {string} message - Message body.
177 145
      * @returns {void}
178 146
      */
179
-    notifySendingChatMessage(body) {
180
-        triggerEvent('outgoing-message', { 'message': body });
147
+    notifySendingChatMessage(message) {
148
+        this._sendEvent({
149
+            name: 'outgoing-message',
150
+            message
151
+        });
181 152
     }
182 153
 
183 154
     /**
@@ -187,21 +158,18 @@ class API {
187 158
      * @param {Object} options - Object with the message properties.
188 159
      * @returns {void}
189 160
      */
190
-    notifyReceivedChatMessage(options = {}) {
191
-        const { id, nick, body, ts } = options;
192
-
161
+    notifyReceivedChatMessage({ body, id, nick, ts } = {}) {
193 162
         if (APP.conference.isLocalId(id)) {
194 163
             return;
195 164
         }
196 165
 
197
-        triggerEvent(
198
-            'incoming-message',
199
-            {
200
-                'from': id,
201
-                'message': body,
202
-                'nick': nick,
203
-                'stamp': ts
204
-            });
166
+        this._sendEvent({
167
+            name: 'incoming-message',
168
+            from: id,
169
+            message: body,
170
+            nick,
171
+            stamp: ts
172
+        });
205 173
     }
206 174
 
207 175
     /**
@@ -212,7 +180,10 @@ class API {
212 180
      * @returns {void}
213 181
      */
214 182
     notifyUserJoined(id) {
215
-        triggerEvent('participant-joined', { id });
183
+        this._sendEvent({
184
+            name: 'participant-joined',
185
+            id
186
+        });
216 187
     }
217 188
 
218 189
     /**
@@ -223,7 +194,10 @@ class API {
223 194
      * @returns {void}
224 195
      */
225 196
     notifyUserLeft(id) {
226
-        triggerEvent('participant-left', { id });
197
+        this._sendEvent({
198
+            name: 'participant-left',
199
+            id
200
+        });
227 201
     }
228 202
 
229 203
     /**
@@ -231,39 +205,43 @@ class API {
231 205
      * nickname.
232 206
      *
233 207
      * @param {string} id - User id.
234
-     * @param {string} displayName - User nickname.
208
+     * @param {string} displayname - User nickname.
235 209
      * @returns {void}
236 210
      */
237
-    notifyDisplayNameChanged(id, displayName) {
238
-        triggerEvent(
239
-            'display-name-change',
240
-            {
241
-                displayname: displayName,
242
-                id
243
-            });
211
+    notifyDisplayNameChanged(id, displayname) {
212
+        this._sendEvent({
213
+            name: 'display-name-change',
214
+            displayname,
215
+            id
216
+        });
244 217
     }
245 218
 
246 219
     /**
247 220
      * Notify external application (if API is enabled) that the conference has
248 221
      * been joined.
249 222
      *
250
-     * @param {string} room - The room name.
223
+     * @param {string} roomName - The room name.
251 224
      * @returns {void}
252 225
      */
253
-    notifyConferenceJoined(room) {
254
-        triggerEvent('video-conference-joined', { roomName: room });
226
+    notifyConferenceJoined(roomName) {
227
+        this._sendEvent({
228
+            name: 'video-conference-joined',
229
+            roomName
230
+        });
255 231
     }
256 232
 
257 233
     /**
258 234
      * Notify external application (if API is enabled) that user changed their
259 235
      * nickname.
260 236
      *
261
-     * @param {string} room - User id.
262
-     * @param {string} displayName - User nickname.
237
+     * @param {string} roomName - User id.
263 238
      * @returns {void}
264 239
      */
265
-    notifyConferenceLeft(room) {
266
-        triggerEvent('video-conference-left', { roomName: room });
240
+    notifyConferenceLeft(roomName) {
241
+        this._sendEvent({
242
+            name: 'video-conference-left',
243
+            roomName
244
+        });
267 245
     }
268 246
 
269 247
     /**
@@ -273,32 +251,17 @@ class API {
273 251
      * @returns {void}
274 252
      */
275 253
     notifyReadyToClose() {
276
-        triggerEvent('video-ready-to-close', {});
254
+        this._sendEvent({ name: 'video-ready-to-close' });
277 255
     }
278 256
 
279 257
     /**
280
-     * Sends remote control event.
281
-     *
282
-     * @param {RemoteControlEvent} event - The remote control event.
283
-     * @returns {void}
284
-     */
285
-    sendRemoteControlEvent(event) {
286
-        sendMessage({
287
-            method: 'remote-control-event',
288
-            params: event
289
-        });
290
-    }
291
-
292
-    /**
293
-     * Removes the listeners.
258
+     * Disposes the allocated resources.
294 259
      *
295 260
      * @returns {void}
296 261
      */
297 262
     dispose() {
298
-        if (postis) {
299
-            postis.destroy();
300
-            postis = undefined;
301
-
263
+        if (this._enabled) {
264
+            this._enabled = false;
302 265
             APP.conference.removeListener(
303 266
                 JitsiMeetConferenceEvents.DESKTOP_SHARING_ENABLED_CHANGED,
304 267
                 onDesktopSharingEnabledChanged);

+ 9
- 0
modules/API/constants.js Visa fil

@@ -0,0 +1,9 @@
1
+declare var getConfigParamsFromUrl: Function;
2
+
3
+/**
4
+ * JitsiMeetExternalAPI id - unique for a webpage.
5
+ */
6
+export const API_ID
7
+    = typeof getConfigParamsFromUrl === 'function'
8
+        ? getConfigParamsFromUrl().jitsi_meet_external_api_id
9
+        : undefined;

+ 42
- 37
modules/API/external/external_api.js Visa fil

@@ -1,5 +1,9 @@
1 1
 import EventEmitter from 'events';
2
-import postisInit from 'postis';
2
+
3
+import {
4
+    PostMessageTransportBackend,
5
+    Transport
6
+} from '../../transport';
3 7
 
4 8
 const logger = require('jitsi-meet-logger').getLogger(__filename);
5 9
 
@@ -25,14 +29,14 @@ const commands = {
25 29
  * events expected by jitsi-meet
26 30
  */
27 31
 const events = {
28
-    displayNameChange: 'display-name-change',
29
-    incomingMessage: 'incoming-message',
30
-    outgoingMessage: 'outgoing-message',
31
-    participantJoined: 'participant-joined',
32
-    participantLeft: 'participant-left',
33
-    readyToClose: 'video-ready-to-close',
34
-    videoConferenceJoined: 'video-conference-joined',
35
-    videoConferenceLeft: 'video-conference-left'
32
+    'display-name-change': 'displayNameChange',
33
+    'incoming-message': 'incomingMessage',
34
+    'outgoing-message': 'outgoingMessage',
35
+    'participant-joined': 'participantJoined',
36
+    'participant-left': 'participantLeft',
37
+    'video-ready-to-close': 'readyToClose',
38
+    'video-conference-joined': 'videoConferenceJoined',
39
+    'video-conference-left': 'videoConferenceLeft'
36 40
 };
37 41
 
38 42
 /**
@@ -78,8 +82,8 @@ function configToURLParamsArray(config = {}) {
78 82
 
79 83
     for (const key in config) { // eslint-disable-line guard-for-in
80 84
         try {
81
-            params.push(`${key}=${
82
-                encodeURIComponent(JSON.stringify(config[key]))}`);
85
+            params.push(
86
+                `${key}=${encodeURIComponent(JSON.stringify(config[key]))}`);
83 87
         } catch (e) {
84 88
             console.warn(`Error encoding ${key}: ${e}`);
85 89
         }
@@ -180,9 +184,13 @@ class JitsiMeetExternalAPI extends EventEmitter {
180 184
         });
181 185
         this._createIFrame(Math.max(height, MIN_HEIGHT),
182 186
             Math.max(width, MIN_WIDTH));
183
-        this.postis = postisInit({
184
-            scope: `jitsi_meet_external_api_${id}`,
185
-            window: this.frame.contentWindow
187
+        this._transport = new Transport({
188
+            backend: new PostMessageTransportBackend({
189
+                postisOptions: {
190
+                    scope: `jitsi_meet_external_api_${id}`,
191
+                    window: this.frame.contentWindow
192
+                }
193
+            })
186 194
         });
187 195
         this.numberOfParticipants = 1;
188 196
         this._setupListeners();
@@ -225,17 +233,24 @@ class JitsiMeetExternalAPI extends EventEmitter {
225 233
      * @private
226 234
      */
227 235
     _setupListeners() {
228
-        this.postis.listen('participant-joined',
229
-            changeParticipantNumber.bind(null, this, 1));
230
-        this.postis.listen('participant-left',
231
-            changeParticipantNumber.bind(null, this, -1));
232 236
 
233
-        for (const eventName in events) { // eslint-disable-line guard-for-in
234
-            const postisMethod = events[eventName];
237
+        this._transport.on('event', ({ name, ...data }) => {
238
+            if (name === 'participant-joined') {
239
+                changeParticipantNumber(this, 1);
240
+            } else if (name === 'participant-left') {
241
+                changeParticipantNumber(this, -1);
242
+            }
235 243
 
236
-            this.postis.listen(postisMethod,
237
-                (...args) => this.emit(eventName, ...args));
238
-        }
244
+            const eventName = events[name];
245
+
246
+            if (eventName) {
247
+                this.emit(eventName, data);
248
+
249
+                return true;
250
+            }
251
+
252
+            return false;
253
+        });
239 254
     }
240 255
 
241 256
     /**
@@ -319,10 +334,7 @@ class JitsiMeetExternalAPI extends EventEmitter {
319 334
      * @returns {void}
320 335
      */
321 336
     dispose() {
322
-        if (this.postis) {
323
-            this.postis.destroy();
324
-            this.postis = null;
325
-        }
337
+        this._transport.dispose();
326 338
         this.removeAllListeners();
327 339
         if (this.iframeHolder) {
328 340
             this.iframeHolder.parentNode.removeChild(this.iframeHolder);
@@ -348,16 +360,9 @@ class JitsiMeetExternalAPI extends EventEmitter {
348 360
 
349 361
             return;
350 362
         }
351
-
352
-        if (!this.postis) {
353
-            logger.error('Cannot execute command using disposed instance.');
354
-
355
-            return;
356
-        }
357
-
358
-        this.postis.send({
359
-            method: commands[name],
360
-            params: args
363
+        this._transport.sendEvent({
364
+            data: args,
365
+            name: commands[name]
361 366
         });
362 367
     }
363 368
 

+ 2
- 0
modules/API/index.js Visa fil

@@ -0,0 +1,2 @@
1
+export default from './API';
2
+export * from './constants';

+ 17
- 13
modules/remotecontrol/Controller.js Visa fil

@@ -1,8 +1,11 @@
1 1
 /* global $, JitsiMeetJS, APP */
2 2
 const logger = require("jitsi-meet-logger").getLogger(__filename);
3 3
 import * as KeyCodes from "../keycode/keycode";
4
-import {EVENT_TYPES, REMOTE_CONTROL_EVENT_TYPE, PERMISSIONS_ACTIONS}
5
-    from "../../service/remotecontrol/Constants";
4
+import {
5
+    EVENT_TYPES,
6
+    PERMISSIONS_ACTIONS,
7
+    REMOTE_CONTROL_EVENT_NAME
8
+} from "../../service/remotecontrol/Constants";
6 9
 import RemoteControlParticipant from "./RemoteControlParticipant";
7 10
 import UIEvents from "../../service/UI/UIEvents";
8 11
 
@@ -132,15 +135,15 @@ export default class Controller extends RemoteControlParticipant {
132 135
      * @param {RemoteControlEvent} event the remote control event.
133 136
      */
134 137
     _handleReply(participant, event) {
135
-        const remoteControlEvent = event.event;
136 138
         const userId = participant.getId();
137
-        if(this.enabled && event.type === REMOTE_CONTROL_EVENT_TYPE
138
-            && remoteControlEvent.type === EVENT_TYPES.permissions
139
-            && userId === this.requestedParticipant) {
140
-            if(remoteControlEvent.action !== PERMISSIONS_ACTIONS.grant) {
139
+        if(this.enabled
140
+                && event.name === REMOTE_CONTROL_EVENT_NAME
141
+                && event.type === EVENT_TYPES.permissions
142
+                && userId === this.requestedParticipant) {
143
+            if(event.action !== PERMISSIONS_ACTIONS.grant) {
141 144
                 this.area = null;
142 145
             }
143
-            switch(remoteControlEvent.action) {
146
+            switch(event.action) {
144 147
                 case PERMISSIONS_ACTIONS.grant: {
145 148
                     this.controlledParticipant = userId;
146 149
                     logger.log("Remote control permissions granted to: "
@@ -166,14 +169,15 @@ export default class Controller extends RemoteControlParticipant {
166 169
      * @param {JitsiParticipant} participant the participant that has sent the
167 170
      * event
168 171
      * @param {Object} event EndpointMessage event from the data channels.
169
-     * @property {string} type property. The function process only events of
170
-     * type REMOTE_CONTROL_EVENT_TYPE
172
+     * @property {string} type property. The function process only events with
173
+     * name REMOTE_CONTROL_EVENT_NAME
171 174
      * @property {RemoteControlEvent} event - the remote control event.
172 175
      */
173 176
     _handleRemoteControlStoppedEvent(participant, event) {
174
-        if(this.enabled && event.type === REMOTE_CONTROL_EVENT_TYPE
175
-            && event.event.type === EVENT_TYPES.stop
176
-            && participant.getId() === this.controlledParticipant) {
177
+        if(this.enabled
178
+                && event.name === REMOTE_CONTROL_EVENT_NAME
179
+                && event.type === EVENT_TYPES.stop
180
+                && participant.getId() === this.controlledParticipant) {
177 181
             this._stop();
178 182
         }
179 183
     }

+ 83
- 22
modules/remotecontrol/Receiver.js Visa fil

@@ -1,11 +1,25 @@
1
-/* global APP, JitsiMeetJS, interfaceConfig */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
3
-import {DISCO_REMOTE_CONTROL_FEATURE, REMOTE_CONTROL_EVENT_TYPE, EVENT_TYPES,
4
-    PERMISSIONS_ACTIONS} from "../../service/remotecontrol/Constants";
5
-import RemoteControlParticipant from "./RemoteControlParticipant";
1
+/* global APP, config, interfaceConfig, JitsiMeetJS */
2
+
6 3
 import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
4
+import {
5
+    DISCO_REMOTE_CONTROL_FEATURE,
6
+    EVENT_TYPES,
7
+    PERMISSIONS_ACTIONS,
8
+    REMOTE_CONTROL_EVENT_NAME
9
+} from '../../service/remotecontrol/Constants';
10
+import { getJitsiMeetTransport } from '../transport';
11
+
12
+import RemoteControlParticipant from './RemoteControlParticipant';
7 13
 
8 14
 const ConferenceEvents = JitsiMeetJS.events.conference;
15
+const logger = require("jitsi-meet-logger").getLogger(__filename);
16
+
17
+/**
18
+ * The transport instance used for communication with external apps.
19
+ *
20
+ * @type {Transport}
21
+ */
22
+const transport = getJitsiMeetTransport();
9 23
 
10 24
 /**
11 25
  * This class represents the receiver party for a remote controller session.
@@ -25,13 +39,24 @@ export default class Receiver extends RemoteControlParticipant {
25 39
             = this._onRemoteControlEvent.bind(this);
26 40
         this._userLeftListener = this._onUserLeft.bind(this);
27 41
         this._hangupListener = this._onHangup.bind(this);
42
+        // We expect here that even if we receive the supported event earlier
43
+        // it will be cached and we'll receive it.
44
+        transport.on('event', event => {
45
+            if (event.name === REMOTE_CONTROL_EVENT_NAME) {
46
+                this._onRemoteControlAPIEvent(event);
47
+
48
+                return true;
49
+            }
50
+
51
+            return false;
52
+        });
28 53
     }
29 54
 
30 55
     /**
31 56
      * Enables / Disables the remote control
32 57
      * @param {boolean} enabled the new state.
33 58
      */
34
-    enable(enabled) {
59
+    _enable(enabled) {
35 60
         if(this.enabled === enabled) {
36 61
             return;
37 62
         }
@@ -73,7 +98,8 @@ export default class Receiver extends RemoteControlParticipant {
73 98
         this.controller = null;
74 99
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
75 100
             this._userLeftListener);
76
-        APP.API.sendRemoteControlEvent({
101
+        transport.sendEvent({
102
+            name: REMOTE_CONTROL_EVENT_NAME,
77 103
             type: EVENT_TYPES.stop
78 104
         });
79 105
         if(!dontShowDialog) {
@@ -103,43 +129,49 @@ export default class Receiver extends RemoteControlParticipant {
103 129
      * module.
104 130
      * @param {JitsiParticipant} participant the controller participant
105 131
      * @param {Object} event EndpointMessage event from the data channels.
106
-     * @property {string} type property. The function process only events of
107
-     * type REMOTE_CONTROL_EVENT_TYPE
132
+     * @property {string} type property. The function process only events with
133
+     * name REMOTE_CONTROL_EVENT_NAME
108 134
      * @property {RemoteControlEvent} event - the remote control event.
109 135
      */
110 136
     _onRemoteControlEvent(participant, event) {
111
-        if(this.enabled && event.type === REMOTE_CONTROL_EVENT_TYPE) {
112
-            const remoteControlEvent = event.event;
113
-            if(this.controller === null
114
-                && remoteControlEvent.type === EVENT_TYPES.permissions
115
-                && remoteControlEvent.action === PERMISSIONS_ACTIONS.request) {
137
+        if (event.name !== REMOTE_CONTROL_EVENT_NAME) {
138
+            return;
139
+        }
140
+
141
+        const remoteControlEvent = Object.assign({}, event);
142
+
143
+        if (this.enabled) {
144
+            if (this.controller === null
145
+                    && event.type === EVENT_TYPES.permissions
146
+                    && event.action === PERMISSIONS_ACTIONS.request) {
147
+                // FIXME: Maybe use transport.sendRequest in this case???
116 148
                 remoteControlEvent.userId = participant.getId();
117 149
                 remoteControlEvent.userJID = participant.getJid();
118 150
                 remoteControlEvent.displayName = participant.getDisplayName()
119 151
                     || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
120 152
                 remoteControlEvent.screenSharing
121 153
                     = APP.conference.isSharingScreen;
122
-            } else if(this.controller !== participant.getId()) {
154
+            } else if (this.controller !== participant.getId()) {
123 155
                 return;
124
-            } else if(remoteControlEvent.type === EVENT_TYPES.stop) {
156
+            } else if (event.type === EVENT_TYPES.stop) {
125 157
                 this._stop();
126 158
                 return;
127 159
             }
128
-            APP.API.sendRemoteControlEvent(remoteControlEvent);
129
-        } else if(event.type === REMOTE_CONTROL_EVENT_TYPE) {
160
+            transport.sendEvent(remoteControlEvent);
161
+        } else {
130 162
             logger.log("Remote control event is ignored because remote "
131 163
                 + "control is disabled", event);
132 164
         }
133 165
     }
134 166
 
135 167
     /**
136
-     * Handles remote control permission events received from the API module.
168
+     * Handles remote control permission events.
137 169
      * @param {String} userId the user id of the participant related to the
138 170
      * event.
139 171
      * @param {PERMISSIONS_ACTIONS} action the action related to the event.
140 172
      */
141 173
     _onRemoteControlPermissionsEvent(userId, action) {
142
-        if(action === PERMISSIONS_ACTIONS.grant) {
174
+        if (action === PERMISSIONS_ACTIONS.grant) {
143 175
             APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
144 176
                 this._userLeftListener);
145 177
             this.controller = userId;
@@ -169,10 +201,39 @@ export default class Receiver extends RemoteControlParticipant {
169 201
         }
170 202
         this._sendRemoteControlEvent(userId, {
171 203
             type: EVENT_TYPES.permissions,
172
-            action: action
204
+            action
173 205
         });
174 206
     }
175 207
 
208
+    /**
209
+     * Handles remote control events from the external app. Currently only
210
+     * events with type = EVENT_TYPES.supported or EVENT_TYPES.permissions
211
+     * @param {RemoteControlEvent} event the remote control event.
212
+     */
213
+    _onRemoteControlAPIEvent(event) {
214
+        switch(event.type) {
215
+        case EVENT_TYPES.permissions:
216
+            this._onRemoteControlPermissionsEvent(event.userId, event.action);
217
+            break;
218
+        case EVENT_TYPES.supported:
219
+            this._onRemoteControlSupported();
220
+            break;
221
+        }
222
+    }
223
+
224
+    /**
225
+     * Handles events for support for executing remote control events into
226
+     * the wrapper application.
227
+     */
228
+    _onRemoteControlSupported() {
229
+        logger.log("Remote Control supported.");
230
+        if (config.disableRemoteControl) {
231
+            logger.log("Remote Control disabled.");
232
+        } else {
233
+            this._enable(true);
234
+        }
235
+    }
236
+
176 237
     /**
177 238
      * Calls the stop method if the other side have left.
178 239
      * @param {string} id - the user id for the participant that have left
@@ -187,6 +248,6 @@ export default class Receiver extends RemoteControlParticipant {
187 248
      * Handles hangup events. Disables the receiver.
188 249
      */
189 250
     _onHangup() {
190
-        this.enable(false);
251
+        this._enable(false);
191 252
     }
192 253
 }

+ 16
- 52
modules/remotecontrol/RemoteControl.js Visa fil

@@ -1,9 +1,12 @@
1 1
 /* global APP, config */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
3
-import Controller from "./Controller";
4
-import Receiver from "./Receiver";
5
-import {EVENT_TYPES, DISCO_REMOTE_CONTROL_FEATURE}
6
-    from "../../service/remotecontrol/Constants";
2
+
3
+import { DISCO_REMOTE_CONTROL_FEATURE }
4
+    from '../../service/remotecontrol/Constants';
5
+
6
+import Controller from './Controller';
7
+import Receiver from './Receiver';
8
+
9
+const logger = require('jitsi-meet-logger').getLogger(__filename);
7 10
 
8 11
 /**
9 12
  * Implements the remote control functionality.
@@ -15,62 +18,23 @@ class RemoteControl {
15 18
      */
16 19
     constructor() {
17 20
         this.controller = new Controller();
18
-        this.receiver = new Receiver();
19
-        this.enabled = false;
20 21
         this.initialized = false;
21 22
     }
22 23
 
23 24
     /**
24 25
      * Initializes the remote control - checks if the remote control should be
25
-     * enabled or not, initializes the API module.
26
+     * enabled or not.
26 27
      */
27 28
     init() {
28
-        if(config.disableRemoteControl || this.initialized
29
-            || !APP.conference.isDesktopSharingEnabled) {
29
+        if(config.disableRemoteControl
30
+                || this.initialized
31
+                || !APP.conference.isDesktopSharingEnabled) {
30 32
             return;
31 33
         }
32 34
         logger.log("Initializing remote control.");
33 35
         this.initialized = true;
34
-        APP.API.init({
35
-            forceEnable: true,
36
-        });
37 36
         this.controller.enable(true);
38
-        if(this.enabled) { // supported message came before init.
39
-            this._onRemoteControlSupported();
40
-        }
41
-    }
42
-
43
-    /**
44
-     * Handles remote control events from the API module. Currently only events
45
-     * with type = EVENT_TYPES.supported or EVENT_TYPES.permissions
46
-     * @param {RemoteControlEvent} event the remote control event.
47
-     */
48
-    onRemoteControlAPIEvent(event) {
49
-        switch(event.type) {
50
-            case EVENT_TYPES.supported:
51
-                this._onRemoteControlSupported();
52
-                break;
53
-            case EVENT_TYPES.permissions:
54
-                this.receiver._onRemoteControlPermissionsEvent(
55
-                    event.userId, event.action);
56
-                break;
57
-        }
58
-    }
59
-
60
-    /**
61
-     * Handles API event for support for executing remote control events into
62
-     * the wrapper application.
63
-     */
64
-    _onRemoteControlSupported() {
65
-        logger.log("Remote Control supported.");
66
-        if(!config.disableRemoteControl) {
67
-            this.enabled = true;
68
-            if(this.initialized) {
69
-                this.receiver.enable(true);
70
-            }
71
-        } else {
72
-            logger.log("Remote Control disabled.");
73
-        }
37
+        this.receiver = new Receiver();
74 38
     }
75 39
 
76 40
     /**
@@ -80,9 +44,9 @@ class RemoteControl {
80 44
      * the user supports remote control and with false if not.
81 45
      */
82 46
     checkUserRemoteControlSupport(user) {
83
-        return user.getFeatures().then(features =>
84
-            features.has(DISCO_REMOTE_CONTROL_FEATURE), () => false
85
-        );
47
+        return user.getFeatures().then(
48
+            features => features.has(DISCO_REMOTE_CONTROL_FEATURE),
49
+            () => false);
86 50
     }
87 51
 }
88 52
 

+ 15
- 7
modules/remotecontrol/RemoteControlParticipant.js Visa fil

@@ -1,7 +1,10 @@
1 1
 /* global APP */
2
+
3
+import {
4
+    REMOTE_CONTROL_EVENT_NAME
5
+} from "../../service/remotecontrol/Constants";
6
+
2 7
 const logger = require("jitsi-meet-logger").getLogger(__filename);
3
-import {REMOTE_CONTROL_EVENT_TYPE}
4
-    from "../../service/remotecontrol/Constants";
5 8
 
6 9
 export default class RemoteControlParticipant {
7 10
     /**
@@ -26,15 +29,20 @@ export default class RemoteControlParticipant {
26 29
      */
27 30
     _sendRemoteControlEvent(to, event, onDataChannelFail = () => {}) {
28 31
         if(!this.enabled || !to) {
29
-            logger.warn("Remote control: Skip sending remote control event."
30
-                + " Params:", this.enable, to);
32
+            logger.warn(
33
+                "Remote control: Skip sending remote control event. Params:",
34
+                this.enable,
35
+                to);
31 36
             return;
32 37
         }
33 38
         try{
34
-            APP.conference.sendEndpointMessage(to,
35
-                {type: REMOTE_CONTROL_EVENT_TYPE, event});
39
+            APP.conference.sendEndpointMessage(to, {
40
+                name: REMOTE_CONTROL_EVENT_NAME,
41
+                ...event
42
+            });
36 43
         } catch (e) {
37
-            logger.error("Failed to send EndpointMessage via the datachannels",
44
+            logger.error(
45
+                "Failed to send EndpointMessage via the datachannels",
38 46
                 e);
39 47
             onDataChannelFail(e);
40 48
         }

+ 3
- 0
modules/transport/.eslintrc.js Visa fil

@@ -0,0 +1,3 @@
1
+module.exports = {
2
+    'extends': '../../react/.eslintrc.js'
3
+};

+ 174
- 0
modules/transport/PostMessageTransportBackend.js Visa fil

@@ -0,0 +1,174 @@
1
+import Postis from 'postis';
2
+
3
+/**
4
+ * The default options for postis.
5
+ *
6
+ * @type {Object}
7
+ */
8
+const DEFAULT_POSTIS_OPTIONS = {
9
+    window: window.opener || window.parent
10
+};
11
+
12
+/**
13
+ * The list of methods of incoming postis messages that we have to support for
14
+ * backward compatibility for the users that are directly sending messages to
15
+ * Jitsi Meet (without using external_api.js)
16
+ *
17
+ * @type {string[]}
18
+ */
19
+const LEGACY_INCOMING_METHODS = [
20
+    'avatar-url',
21
+    'display-name',
22
+    'email',
23
+    'toggle-audio',
24
+    'toggle-chat',
25
+    'toggle-contact-list',
26
+    'toggle-film-strip',
27
+    'toggle-share-screen',
28
+    'toggle-video',
29
+    'video-hangup'
30
+];
31
+
32
+/**
33
+ * The list of methods of outgoing postis messages that we have to support for
34
+ * backward compatibility for the users that are directly listening to the
35
+ * postis messages send by Jitsi Meet(without using external_api.js).
36
+ *
37
+ * @type {string[]}
38
+ */
39
+const LEGACY_OUTGOING_METHODS = [
40
+    'display-name-change',
41
+    'incoming-message',
42
+    'outgoing-message',
43
+    'participant-joined',
44
+    'participant-left',
45
+    'video-conference-joined',
46
+    'video-conference-left',
47
+    'video-ready-to-close'
48
+];
49
+
50
+/**
51
+ * The postis method used for all messages.
52
+ *
53
+ * @type {string}
54
+ */
55
+const POSTIS_METHOD_NAME = 'message';
56
+
57
+/**
58
+ * Implements message transport using the postMessage API.
59
+ */
60
+export default class PostMessageTransportBackend {
61
+    /**
62
+     * Creates new PostMessageTransportBackend instance.
63
+     *
64
+     * @param {Object} options - Optional parameters for configuration of the
65
+     * transport.
66
+     */
67
+    constructor({ enableLegacyFormat, postisOptions } = {}) {
68
+        this.postis = Postis({
69
+            ...DEFAULT_POSTIS_OPTIONS,
70
+            ...postisOptions
71
+        });
72
+
73
+        /**
74
+         * If true PostMessageTransportBackend will process and send messages
75
+         * using the legacy format and in the same time the current format.
76
+         * Otherwise all messages (outgoing and incoming) that are using the
77
+         * legacy format will be ignored.
78
+         *
79
+         * @type {boolean}
80
+         */
81
+        this._enableLegacyFormat = enableLegacyFormat;
82
+
83
+        if (this._enableLegacyFormat) {
84
+            // backward compatibility
85
+            LEGACY_INCOMING_METHODS.forEach(method =>
86
+                this.postis.listen(
87
+                    method,
88
+                    params =>
89
+                        this._legacyMessageReceivedCallback(method, params)
90
+                )
91
+            );
92
+        }
93
+
94
+        this._receiveCallback = () => {
95
+            // Do nothing until a callback is set by the consumer of
96
+            // PostMessageTransportBackend via setReceiveCallback.
97
+        };
98
+
99
+        this.postis.listen(
100
+            POSTIS_METHOD_NAME,
101
+            message => this._receiveCallback(message));
102
+    }
103
+
104
+    /**
105
+     * Handles incoming legacy postis messages.
106
+     *
107
+     * @param {string} method - The method property from the postis message.
108
+     * @param {Any} params - The params property from the postis message.
109
+     * @returns {void}
110
+     */
111
+    _legacyMessageReceivedCallback(method, params = {}) {
112
+        this._receiveCallback({
113
+            data: {
114
+                name: method,
115
+                data: params
116
+            }
117
+        });
118
+    }
119
+
120
+    /**
121
+     * Sends the passed message via postis using the old format.
122
+     *
123
+     * @param {Object} legacyMessage - The message to be sent.
124
+     * @returns {void}
125
+     */
126
+    _sendLegacyMessage({ name, ...data }) {
127
+        if (name && LEGACY_OUTGOING_METHODS.indexOf(name) !== -1) {
128
+            this.postis.send({
129
+                method: name,
130
+                params: data
131
+            });
132
+        }
133
+    }
134
+
135
+    /**
136
+     * Disposes the allocated resources.
137
+     *
138
+     * @returns {void}
139
+     */
140
+    dispose() {
141
+        this.postis.destroy();
142
+    }
143
+
144
+    /**
145
+     * Sends the passed message.
146
+     *
147
+     * @param {Object} message - The message to be sent.
148
+     * @returns {void}
149
+     */
150
+    send(message) {
151
+        this.postis.send({
152
+            method: POSTIS_METHOD_NAME,
153
+            params: message
154
+        });
155
+
156
+        if (this._enableLegacyFormat) {
157
+            // For the legacy use case we don't need any new fields defined in
158
+            // Transport class. That's why we are passing only the original
159
+            // object passed by the consumer of the Transport class which is
160
+            // message.data.
161
+            this._sendLegacyMessage(message.data);
162
+        }
163
+    }
164
+
165
+    /**
166
+     * Sets the callback for receiving data.
167
+     *
168
+     * @param {Function} callback - The new callback.
169
+     * @returns {void}
170
+     */
171
+    setReceiveCallback(callback) {
172
+        this._receiveCallback = callback;
173
+    }
174
+}

+ 265
- 0
modules/transport/Transport.js Visa fil

@@ -0,0 +1,265 @@
1
+import {
2
+    MESSAGE_TYPE_EVENT,
3
+    MESSAGE_TYPE_REQUEST,
4
+    MESSAGE_TYPE_RESPONSE
5
+} from './constants';
6
+
7
+/**
8
+ * Stores the currnet transport backend that have to be used. Also implements
9
+ * request/response mechanism.
10
+ */
11
+export default class Transport {
12
+    /**
13
+     * Creates new instance.
14
+     *
15
+     * @param {Object} options - Optional parameters for configuration of the
16
+     * transport backend.
17
+     */
18
+    constructor({ backend } = {}) {
19
+        /**
20
+         * Maps an event name and listener that have been added to the Transport
21
+         * instance.
22
+         *
23
+         * @type {Map<string, Function>}
24
+         */
25
+        this._listeners = new Map();
26
+
27
+        /**
28
+         * The request ID counter used for the id property of the request. This
29
+         * property is used to match the responses with the request.
30
+         *
31
+         * @type {number}
32
+         */
33
+        this._requestID = 0;
34
+
35
+        /**
36
+         * Maps an IDs of the requests and handlers that will process the
37
+         * responses of those requests.
38
+         *
39
+         * @type {Map<number, Function>}
40
+         */
41
+        this._responseHandlers = new Map();
42
+
43
+        /**
44
+         * A set with the events and requests that were received but not
45
+         * processed by any listener. They are later passed on every new
46
+         * listener until they are processed.
47
+         *
48
+         * @type {Set<Object>}
49
+         */
50
+        this._unprocessedMessages = new Set();
51
+
52
+        /**
53
+         * Alias.
54
+         */
55
+        this.addListener = this.on;
56
+
57
+        if (backend) {
58
+            this.setBackend(backend);
59
+        }
60
+    }
61
+
62
+    /**
63
+     * Disposes the current transport backend.
64
+     *
65
+     * @returns {void}
66
+     */
67
+    _disposeBackend() {
68
+        if (this._backend) {
69
+            this._backend.dispose();
70
+            this._backend = null;
71
+        }
72
+    }
73
+
74
+    /**
75
+     * Handles incoming messages from the transport backend.
76
+     *
77
+     * @param {Object} message - The message.
78
+     * @returns {void}
79
+     */
80
+    _onMessageReceived(message) {
81
+        if (message.type === MESSAGE_TYPE_RESPONSE) {
82
+            const handler = this._responseHandlers.get(message.id);
83
+
84
+            if (handler) {
85
+                handler(message);
86
+                this._responseHandlers.delete(message.id);
87
+            }
88
+        } else if (message.type === MESSAGE_TYPE_REQUEST) {
89
+            this.emit('request', message.data, (result, error) => {
90
+                this._backend.send({
91
+                    type: MESSAGE_TYPE_RESPONSE,
92
+                    error,
93
+                    id: message.id,
94
+                    result
95
+                });
96
+            });
97
+        } else {
98
+            this.emit('event', message.data);
99
+        }
100
+    }
101
+
102
+    /**
103
+     * Disposes the allocated resources.
104
+     *
105
+     * @returns {void}
106
+     */
107
+    dispose() {
108
+        this._responseHandlers.clear();
109
+        this._unprocessedMessages.clear();
110
+        this.removeAllListeners();
111
+        this._disposeBackend();
112
+    }
113
+
114
+    /**
115
+     * Calls each of the listeners registered for the event named eventName, in
116
+     * the order they were registered, passing the supplied arguments to each.
117
+     *
118
+     * @param {string} eventName -  The name of the event.
119
+     * @returns {boolean} True if the event has been processed by any listener,
120
+     * false otherwise.
121
+     */
122
+    emit(eventName, ...args) {
123
+        const listenersForEvent = this._listeners.get(eventName);
124
+        let isProcessed = false;
125
+
126
+        if (listenersForEvent && listenersForEvent.size) {
127
+            listenersForEvent.forEach(listener => {
128
+                isProcessed = listener(...args) || isProcessed;
129
+            });
130
+        }
131
+
132
+        if (!isProcessed) {
133
+            this._unprocessedMessages.add(args);
134
+        }
135
+
136
+        return isProcessed;
137
+    }
138
+
139
+    /**
140
+     * Adds the listener function to the listeners collection for the event
141
+     * named eventName.
142
+     *
143
+     * @param {string} eventName -  The name of the event.
144
+     * @param {Function} listener - The listener that will be added.
145
+     * @returns {Transport} References to the instance of Transport class, so
146
+     * that calls can be chained.
147
+     */
148
+    on(eventName, listener) {
149
+        let listenersForEvent = this._listeners.get(eventName);
150
+
151
+        if (!listenersForEvent) {
152
+            listenersForEvent = new Set();
153
+            this._listeners.set(eventName, listenersForEvent);
154
+        }
155
+
156
+        listenersForEvent.add(listener);
157
+
158
+        this._unprocessedMessages.forEach(args => {
159
+            if (listener(...args)) {
160
+                this._unprocessedMessages.delete(args);
161
+            }
162
+        });
163
+
164
+        return this;
165
+    }
166
+
167
+    /**
168
+     * Removes all listeners, or those of the specified eventName.
169
+     *
170
+     * @param {string} [eventName] - The name of the event. If this parameter is
171
+     * not specified all listeners will be removed.
172
+     * @returns {Transport} References to the instance of Transport class, so
173
+     * that calls can be chained.
174
+     */
175
+    removeAllListeners(eventName) {
176
+        if (eventName) {
177
+            this._listeners.delete(eventName);
178
+        } else {
179
+            this._listeners.clear();
180
+        }
181
+
182
+        return this;
183
+    }
184
+
185
+    /**
186
+     * Removes the listener function from the listeners collection for the event
187
+     * named eventName.
188
+     *
189
+     * @param {string} eventName -  The name of the event.
190
+     * @param {Function} listener - The listener that will be removed.
191
+     * @returns {Transport} References to the instance of Transport class, so
192
+     * that calls can be chained.
193
+     */
194
+    removeListener(eventName, listener) {
195
+        const listenersForEvent = this._listeners.get(eventName);
196
+
197
+        if (listenersForEvent) {
198
+            listenersForEvent.delete(listener);
199
+        }
200
+
201
+        return this;
202
+    }
203
+
204
+    /**
205
+     * Sends the passed event.
206
+     *
207
+     * @param {Object} event - The event to be sent.
208
+     * @returns {void}
209
+     */
210
+    sendEvent(event = {}) {
211
+        if (this._backend) {
212
+            this._backend.send({
213
+                type: MESSAGE_TYPE_EVENT,
214
+                data: event
215
+            });
216
+        }
217
+    }
218
+
219
+    /**
220
+     * Sending request.
221
+     *
222
+     * @param {Object} request - The request to be sent.
223
+     * @returns {Promise}
224
+     */
225
+    sendRequest(request) {
226
+        if (!this._backend) {
227
+            return Promise.reject(new Error('No transport backend defined!'));
228
+        }
229
+
230
+        this._requestID++;
231
+
232
+        const id = this._requestID;
233
+
234
+        return new Promise((resolve, reject) => {
235
+            this._responseHandlers.set(id, ({ error, result }) => {
236
+                if (result) {
237
+                    resolve(result);
238
+                } else if (error) {
239
+                    reject(error);
240
+                } else { // no response
241
+                    reject(new Error('Unexpected response format!'));
242
+                }
243
+            });
244
+
245
+            this._backend.send({
246
+                type: MESSAGE_TYPE_REQUEST,
247
+                data: request,
248
+                id
249
+            });
250
+        });
251
+    }
252
+
253
+    /**
254
+     * Changes the current backend transport.
255
+     *
256
+     * @param {Object} backend - The new transport backend that will be used.
257
+     * @returns {void}
258
+     */
259
+    setBackend(backend) {
260
+        this._disposeBackend();
261
+
262
+        this._backend = backend;
263
+        this._backend.setReceiveCallback(this._onMessageReceived.bind(this));
264
+    }
265
+}

+ 20
- 0
modules/transport/constants.js Visa fil

@@ -0,0 +1,20 @@
1
+/**
2
+ * The message type for events.
3
+ *
4
+ * @type {string}
5
+ */
6
+export const MESSAGE_TYPE_EVENT = 'event';
7
+
8
+/**
9
+ * The message type for requests.
10
+ *
11
+ * @type {string}
12
+ */
13
+export const MESSAGE_TYPE_REQUEST = 'request';
14
+
15
+/**
16
+ * The message type for responses.
17
+ *
18
+ * @type {string}
19
+ */
20
+export const MESSAGE_TYPE_RESPONSE = 'response';

+ 57
- 0
modules/transport/index.js Visa fil

@@ -0,0 +1,57 @@
1
+// FIXME: change to '../API' when we update to webpack2. If we do this now all
2
+// files from API modules will be included in external_api.js.
3
+import { API_ID } from '../API/constants';
4
+import { getJitsiMeetGlobalNS } from '../util/helpers';
5
+
6
+import PostMessageTransportBackend from './PostMessageTransportBackend';
7
+import Transport from './Transport';
8
+
9
+export {
10
+    PostMessageTransportBackend,
11
+    Transport
12
+};
13
+
14
+/**
15
+ * Option for the default low level transport.
16
+ *
17
+ * @type {Object}
18
+ */
19
+const postisOptions = {};
20
+
21
+if (typeof API_ID === 'number') {
22
+    postisOptions.scope = `jitsi_meet_external_api_${API_ID}`;
23
+}
24
+
25
+/**
26
+ * The instance of Transport class that will be used by Jitsi Meet.
27
+ *
28
+ * @type {Transport}
29
+ */
30
+let transport;
31
+
32
+/**
33
+ * Returns the instance of Transport class that will be used by Jitsi Meet.
34
+ *
35
+ * @returns {Transport}
36
+ */
37
+export function getJitsiMeetTransport() {
38
+    if (!transport) {
39
+        transport = new Transport({
40
+            backend: new PostMessageTransportBackend({
41
+                enableLegacyFormat: true,
42
+                postisOptions
43
+            })
44
+        });
45
+    }
46
+
47
+    return transport;
48
+}
49
+
50
+/**
51
+ * Sets the transport to passed transport.
52
+ *
53
+ * @param {Object} externalTransportBackend - The new transport.
54
+ * @returns {void}
55
+ */
56
+getJitsiMeetGlobalNS().setExternalTransportBackend = externalTransportBackend =>
57
+    transport.setBackend(externalTransportBackend);

+ 46
- 29
modules/util/helpers.js Visa fil

@@ -16,35 +16,6 @@ export function createDeferred() {
16 16
     return deferred;
17 17
 }
18 18
 
19
-/**
20
- * Reload page.
21
- */
22
-export function reload() {
23
-    window.location.reload();
24
-}
25
-
26
-/**
27
- * Redirects to a specific new URL by replacing the current location (in the
28
- * history).
29
- *
30
- * @param {string} url the URL pointing to the location where the user should
31
- * be redirected to.
32
- */
33
-export function replace(url) {
34
-    window.location.replace(url);
35
-}
36
-
37
-/**
38
- * Prints the error and reports it to the global error handler.
39
- *
40
- * @param e {Error} the error
41
- * @param msg {string} [optional] the message printed in addition to the error
42
- */
43
-export function reportError(e, msg = "") {
44
-    logger.error(msg, e);
45
-    window.onerror && window.onerror(msg, null, null, null, e);
46
-}
47
-
48 19
 /**
49 20
  * Creates a debounced function that delays invoking func until after wait
50 21
  * milliseconds have elapsed since the last time the debounced function was
@@ -74,3 +45,49 @@ export function debounce(fn, wait = 0, options = {}) {
74 45
         }
75 46
     };
76 47
 }
48
+
49
+/**
50
+ * Returns the namespace for all global variables, functions, etc that we need.
51
+ *
52
+ * @returns {Object} the namespace.
53
+ *
54
+ * NOTE: After React-ifying everything this should be the only global.
55
+ */
56
+export function getJitsiMeetGlobalNS() {
57
+    if (!window.JitsiMeetJS) {
58
+        window.JitsiMeetJS = {};
59
+    }
60
+    if (!window.JitsiMeetJS.app) {
61
+        window.JitsiMeetJS.app = {};
62
+    }
63
+    return window.JitsiMeetJS.app;
64
+}
65
+
66
+/**
67
+ * Reload page.
68
+ */
69
+export function reload() {
70
+    window.location.reload();
71
+}
72
+
73
+/**
74
+ * Redirects to a specific new URL by replacing the current location (in the
75
+ * history).
76
+ *
77
+ * @param {string} url the URL pointing to the location where the user should
78
+ * be redirected to.
79
+ */
80
+export function replace(url) {
81
+    window.location.replace(url);
82
+}
83
+
84
+/**
85
+ * Prints the error and reports it to the global error handler.
86
+ *
87
+ * @param e {Error} the error
88
+ * @param msg {string} [optional] the message printed in addition to the error
89
+ */
90
+export function reportError(e, msg = "") {
91
+    logger.error(msg, e);
92
+    window.onerror && window.onerror(msg, null, null, null, e);
93
+}

+ 3
- 0
react/index.web.js Visa fil

@@ -3,6 +3,8 @@
3 3
 import React from 'react';
4 4
 import ReactDOM from 'react-dom';
5 5
 
6
+import { getJitsiMeetTransport } from '../modules/transport';
7
+
6 8
 import config from './config';
7 9
 import { App } from './features/app';
8 10
 
@@ -34,4 +36,5 @@ window.addEventListener('beforeunload', () => {
34 36
         APP.logCollectorStarted = false;
35 37
     }
36 38
     APP.API.dispose();
39
+    getJitsiMeetTransport().dispose();
37 40
 });

+ 1
- 1
service/remotecontrol/Constants.js Visa fil

@@ -37,7 +37,7 @@ export const PERMISSIONS_ACTIONS = {
37 37
 /**
38 38
  * The type of remote control events sent trough the API module.
39 39
  */
40
-export const REMOTE_CONTROL_EVENT_TYPE = "remote-control-event";
40
+export const REMOTE_CONTROL_EVENT_NAME = "remote-control-event";
41 41
 
42 42
 /**
43 43
  * The remote control event.

Laddar…
Avbryt
Spara