Sfoglia il codice sorgente

feat(transport): Implement transport module

The transport module will be handling all external app
communication.
master
hristoterezov 8 anni fa
parent
commit
0dff35c0db

+ 2
- 0
.jshintignore Vedi File

@@ -9,6 +9,8 @@ node_modules/
9 9
 # supersedes JSHint.
10 10
 flow-typed/
11 11
 react/
12
+modules/API/
13
+modules/transport/
12 14
 
13 15
 # The following are checked by ESLint with the minimum configuration which does
14 16
 # not supersede JSHint but take advantage of advanced language features such as

+ 1
- 1
app.js Vedi File

@@ -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";

+ 63
- 107
modules/API/API.js Vedi File

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

+ 7
- 0
modules/API/constants.js Vedi File

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

+ 2
- 0
modules/API/index.js Vedi File

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

+ 3
- 0
modules/transport/.eslintrc.js Vedi File

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

+ 141
- 0
modules/transport/PostMessageTransportBackend.js Vedi File

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

+ 243
- 0
modules/transport/Transport.js Vedi File

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

+ 20
- 0
modules/transport/constants.js Vedi File

@@ -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 responses.
10
+ *
11
+ * @type {string}
12
+ */
13
+export const MESSAGE_TYPE_RESPONSE = 'response';
14
+
15
+/**
16
+ * The message type for requests.
17
+ *
18
+ * @type {string}
19
+ */
20
+export const MESSAGE_TYPE_REQUEST = 'request';

+ 31
- 0
modules/transport/index.js Vedi File

@@ -0,0 +1,31 @@
1
+import { API_ID } from '../API';
2
+import { getJitsiMeetGlobalNS } from '../util/helpers';
3
+
4
+import Transport from './Transport';
5
+import PostMessageTransportBackend from './PostMessageTransportBackend';
6
+
7
+/**
8
+ * Option for the default low level transport.
9
+ *
10
+ * @type {Object}
11
+ */
12
+const postMessageOptions = {};
13
+
14
+if (typeof API_ID === 'number') {
15
+    postMessageOptions.scope
16
+        = `jitsi_meet_external_api_${API_ID}`;
17
+}
18
+
19
+export const transport = new Transport({
20
+    transport: new PostMessageTransportBackend(postMessageOptions)
21
+});
22
+
23
+/**
24
+ * Sets the transport to passed transport.
25
+ *
26
+ * @param {Object} newTransport - The new transport.
27
+ * @returns {void}
28
+ */
29
+getJitsiMeetGlobalNS().useNewExternalTransport = function(newTransport) {
30
+    transport.setTransport(newTransport);
31
+};

+ 15
- 0
modules/util/helpers.js Vedi File

@@ -74,3 +74,18 @@ export function debounce(fn, wait = 0, options = {}) {
74 74
         }
75 75
     };
76 76
 }
77
+
78
+/**
79
+ * Returns the namespace for all global variables, functions, etc that we need.
80
+ *
81
+ * @returns {Object} the namespace.
82
+ *
83
+ * NOTE: After reactifying everything this should be the only place where
84
+ * we store everything that needs to be global (for some reason).
85
+ */
86
+export function getJitsiMeetGlobalNS() {
87
+    if(!window.JitsiMeetGlobalNS) {
88
+        window.JitsiMeetGlobalNS = { };
89
+    }
90
+    return window.JitsiMeetGlobalNS;
91
+}

+ 3
- 0
react/index.web.js Vedi File

@@ -3,6 +3,8 @@
3 3
 import React from 'react';
4 4
 import ReactDOM from 'react-dom';
5 5
 
6
+import { transport } 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
+    transport.dispose();
37 40
 });

Loading…
Annulla
Salva