瀏覽代碼

Remote control - display the authorization dialog in meet (#1541)

* fix(react/participant): store display name in redux

* feat(remotecontrol): Add option to display the authorization dialog in meet

* feat(remotecontrol): Enable ESLint and Flow
master
hristoterezov 8 年之前
父節點
當前提交
d91340166d

+ 6
- 0
.flowconfig 查看文件

35
 
35
 
36
 experimental.strict_type_args=true
36
 experimental.strict_type_args=true
37
 
37
 
38
+; FIXME: munge_underscores should be false but right now there are some errors
39
+; if we change the value to false
40
+; Treats class properties with underscore as private. Disabled because currently
41
+; for us "_" can mean protected too.
42
+; munge_underscores=false
38
 munge_underscores=true
43
 munge_underscores=true
39
 
44
 
40
 module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
45
 module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
46
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
51
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
47
 suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
52
 suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
48
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
53
 suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
54
+suppress_comment=\\(.\\|\n\\)*\\$FlowDisableNextLine
49
 
55
 
50
 unsafe.enable_getters_and_setters=true
56
 unsafe.enable_getters_and_setters=true
51
 
57
 

+ 1
- 1
.jshintignore 查看文件

9
 # supersedes JSHint.
9
 # supersedes JSHint.
10
 flow-typed/
10
 flow-typed/
11
 modules/API/
11
 modules/API/
12
-modules/remotecontrol/RemoteControlParticipant.js
12
+modules/remotecontrol/
13
 modules/transport/
13
 modules/transport/
14
 react/
14
 react/
15
 
15
 

+ 10
- 0
conference.js 查看文件

1442
         room.on(ConferenceEvents.DISPLAY_NAME_CHANGED, (id, displayName) => {
1442
         room.on(ConferenceEvents.DISPLAY_NAME_CHANGED, (id, displayName) => {
1443
             const formattedDisplayName
1443
             const formattedDisplayName
1444
                 = displayName.substr(0, MAX_DISPLAY_NAME_LENGTH);
1444
                 = displayName.substr(0, MAX_DISPLAY_NAME_LENGTH);
1445
+            APP.store.dispatch(participantUpdated({
1446
+                id,
1447
+                name: formattedDisplayName
1448
+            }));
1445
             APP.API.notifyDisplayNameChanged(id, formattedDisplayName);
1449
             APP.API.notifyDisplayNameChanged(id, formattedDisplayName);
1446
             APP.UI.changeDisplayName(id, formattedDisplayName);
1450
             APP.UI.changeDisplayName(id, formattedDisplayName);
1447
         });
1451
         });
2053
             return;
2057
             return;
2054
         }
2058
         }
2055
 
2059
 
2060
+        APP.store.dispatch(participantUpdated({
2061
+            id: this.getMyUserId(),
2062
+            local: true,
2063
+            name: formattedNickname
2064
+        }));
2065
+
2056
         APP.settings.setDisplayName(formattedNickname);
2066
         APP.settings.setDisplayName(formattedNickname);
2057
         if (room) {
2067
         if (room) {
2058
             room.setDisplayName(formattedNickname);
2068
             room.setDisplayName(formattedNickname);

+ 4
- 1
lang/main.json 查看文件

212
     },
212
     },
213
     "dialog": {
213
     "dialog": {
214
         "add": "Add",
214
         "add": "Add",
215
+        "allow": "Allow",
215
         "kickMessage": "Ouch! You have been kicked out of the meet!",
216
         "kickMessage": "Ouch! You have been kicked out of the meet!",
216
         "popupError": "Your browser is blocking popup windows from this site. Please enable popups in your browser's security settings and try again.",
217
         "popupError": "Your browser is blocking popup windows from this site. Please enable popups in your browser's security settings and try again.",
217
         "passwordErrorTitle": "Password Error",
218
         "passwordErrorTitle": "Password Error",
330
         "muteParticipantTitle": "Mute this participant?",
331
         "muteParticipantTitle": "Mute this participant?",
331
         "muteParticipantBody": "You won't be able to unmute them, but they can unmute themselves at any time.",
332
         "muteParticipantBody": "You won't be able to unmute them, but they can unmute themselves at any time.",
332
         "muteParticipantButton": "Mute",
333
         "muteParticipantButton": "Mute",
333
-        "remoteControlTitle": "Remote Control",
334
+        "remoteControlTitle": "Remote desktop control",
335
+        "remoteControlRequestMessage": "Will you allow __user__ to remotely control your desktop?",
336
+        "remoteControlShareScreenWarning": "Note that if you press \"Allow\" you will share your screen!",
334
         "remoteControlDeniedMessage": "__user__ rejected your remote control request!",
337
         "remoteControlDeniedMessage": "__user__ rejected your remote control request!",
335
         "remoteControlAllowedMessage": "__user__ accepted your remote control request!",
338
         "remoteControlAllowedMessage": "__user__ accepted your remote control request!",
336
         "remoteControlErrorMessage": "An error occurred while trying to request remote control permissions from __user__!",
339
         "remoteControlErrorMessage": "An error occurred while trying to request remote control permissions from __user__!",

+ 3
- 0
modules/remotecontrol/.eslintrc.js 查看文件

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

+ 215
- 139
modules/remotecontrol/Controller.js 查看文件

1
-/* global $, JitsiMeetJS, APP */
2
-const logger = require("jitsi-meet-logger").getLogger(__filename);
3
-import * as KeyCodes from "../keycode/keycode";
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
4
+
5
+import * as KeyCodes from '../keycode/keycode';
4
 import {
6
 import {
5
     EVENT_TYPES,
7
     EVENT_TYPES,
6
     PERMISSIONS_ACTIONS,
8
     PERMISSIONS_ACTIONS,
7
     REMOTE_CONTROL_EVENT_NAME
9
     REMOTE_CONTROL_EVENT_NAME
8
-} from "../../service/remotecontrol/Constants";
9
-import RemoteControlParticipant from "./RemoteControlParticipant";
10
-import UIEvents from "../../service/UI/UIEvents";
10
+} from '../../service/remotecontrol/Constants';
11
+import UIEvents from '../../service/UI/UIEvents';
12
+
13
+import RemoteControlParticipant from './RemoteControlParticipant';
14
+
15
+declare var $: Function;
16
+declare var APP: Object;
17
+declare var JitsiMeetJS: Object;
11
 
18
 
12
 const ConferenceEvents = JitsiMeetJS.events.conference;
19
 const ConferenceEvents = JitsiMeetJS.events.conference;
20
+const logger = getLogger(__filename);
13
 
21
 
14
 /**
22
 /**
15
  * Extract the keyboard key from the keyboard event.
23
  * Extract the keyboard key from the keyboard event.
16
- * @param event {KeyboardEvent} the event.
17
- * @returns {KEYS} the key that is pressed or undefined.
24
+ *
25
+ * @param {KeyboardEvent} event - The event.
26
+ * @returns {KEYS} The key that is pressed or undefined.
18
  */
27
  */
19
 function getKey(event) {
28
 function getKey(event) {
20
     return KeyCodes.keyboardEventToKey(event);
29
     return KeyCodes.keyboardEventToKey(event);
22
 
31
 
23
 /**
32
 /**
24
  * Extract the modifiers from the keyboard event.
33
  * Extract the modifiers from the keyboard event.
25
- * @param event {KeyboardEvent} the event.
26
- * @returns {Array} with possible values: "shift", "control", "alt", "command".
34
+ *
35
+ * @param {KeyboardEvent} event - The event.
36
+ * @returns {Array} With possible values: "shift", "control", "alt", "command".
27
  */
37
  */
28
 function getModifiers(event) {
38
 function getModifiers(event) {
29
-    let modifiers = [];
30
-    if(event.shiftKey) {
31
-        modifiers.push("shift");
39
+    const modifiers = [];
40
+
41
+    if (event.shiftKey) {
42
+        modifiers.push('shift');
32
     }
43
     }
33
 
44
 
34
-    if(event.ctrlKey) {
35
-        modifiers.push("control");
45
+    if (event.ctrlKey) {
46
+        modifiers.push('control');
36
     }
47
     }
37
 
48
 
38
 
49
 
39
-    if(event.altKey) {
40
-        modifiers.push("alt");
50
+    if (event.altKey) {
51
+        modifiers.push('alt');
41
     }
52
     }
42
 
53
 
43
-    if(event.metaKey) {
44
-        modifiers.push("command");
54
+    if (event.metaKey) {
55
+        modifiers.push('command');
45
     }
56
     }
46
 
57
 
47
     return modifiers;
58
     return modifiers;
53
  * party of the remote control session.
64
  * party of the remote control session.
54
  */
65
  */
55
 export default class Controller extends RemoteControlParticipant {
66
 export default class Controller extends RemoteControlParticipant {
67
+    _area: ?Object;
68
+    _controlledParticipant: string | null;
69
+    _isCollectingEvents: boolean;
70
+    _largeVideoChangedListener: Function;
71
+    _requestedParticipant: string | null;
72
+    _stopListener: Function;
73
+    _userLeftListener: Function;
74
+
56
     /**
75
     /**
57
      * Creates new instance.
76
      * Creates new instance.
58
      */
77
      */
59
     constructor() {
78
     constructor() {
60
         super();
79
         super();
61
-        this.isCollectingEvents = false;
62
-        this.controlledParticipant = null;
63
-        this.requestedParticipant = null;
80
+        this._isCollectingEvents = false;
81
+        this._controlledParticipant = null;
82
+        this._requestedParticipant = null;
64
         this._stopListener = this._handleRemoteControlStoppedEvent.bind(this);
83
         this._stopListener = this._handleRemoteControlStoppedEvent.bind(this);
65
         this._userLeftListener = this._onUserLeft.bind(this);
84
         this._userLeftListener = this._onUserLeft.bind(this);
66
         this._largeVideoChangedListener
85
         this._largeVideoChangedListener
69
 
88
 
70
     /**
89
     /**
71
      * Requests permissions from the remote control receiver side.
90
      * Requests permissions from the remote control receiver side.
72
-     * @param {string} userId the user id of the participant that will be
91
+     *
92
+     * @param {string} userId - The user id of the participant that will be
73
      * requested.
93
      * requested.
74
-     * @param {JQuerySelector} eventCaptureArea the area that is going to be
94
+     * @param {JQuerySelector} eventCaptureArea - The area that is going to be
75
      * used mouse and keyboard event capture.
95
      * used mouse and keyboard event capture.
76
-     * @returns {Promise<boolean>} - resolve values:
77
-     * true - accept
78
-     * false - deny
79
-     * null - the participant has left.
96
+     * @returns {Promise<boolean>} Resolve values - true(accept), false(deny),
97
+     * null(the participant has left).
80
      */
98
      */
81
-    requestPermissions(userId, eventCaptureArea) {
82
-        if(!this.enabled) {
83
-            return Promise.reject(new Error("Remote control is disabled!"));
99
+    requestPermissions(userId: string, eventCaptureArea: Object) {
100
+        if (!this.enabled) {
101
+            return Promise.reject(new Error('Remote control is disabled!'));
84
         }
102
         }
85
-        this.area = eventCaptureArea;// $("#largeVideoWrapper")
86
-        logger.log("Requsting remote control permissions from: " + userId);
103
+
104
+        this._area = eventCaptureArea;// $("#largeVideoWrapper")
105
+        logger.log(`Requsting remote control permissions from: ${userId}`);
106
+
87
         return new Promise((resolve, reject) => {
107
         return new Promise((resolve, reject) => {
108
+            // eslint-disable-next-line prefer-const
109
+            let onUserLeft, permissionsReplyListener;
110
+
88
             const clearRequest = () => {
111
             const clearRequest = () => {
89
-                this.requestedParticipant = null;
112
+                this._requestedParticipant = null;
90
                 APP.conference.removeConferenceListener(
113
                 APP.conference.removeConferenceListener(
91
                     ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
114
                     ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
92
                     permissionsReplyListener);
115
                     permissionsReplyListener);
94
                     ConferenceEvents.USER_LEFT,
117
                     ConferenceEvents.USER_LEFT,
95
                     onUserLeft);
118
                     onUserLeft);
96
             };
119
             };
97
-            const permissionsReplyListener = (participant, event) => {
120
+
121
+            permissionsReplyListener = (participant, event) => {
98
                 let result = null;
122
                 let result = null;
123
+
99
                 try {
124
                 try {
100
                     result = this._handleReply(participant, event);
125
                     result = this._handleReply(participant, event);
101
                 } catch (e) {
126
                 } catch (e) {
127
+                    clearRequest();
102
                     reject(e);
128
                     reject(e);
103
                 }
129
                 }
104
-                if(result !== null) {
130
+                if (result !== null) {
105
                     clearRequest();
131
                     clearRequest();
106
                     resolve(result);
132
                     resolve(result);
107
                 }
133
                 }
108
             };
134
             };
109
-            const onUserLeft = (id) => {
110
-                if(id === this.requestedParticipant) {
135
+            onUserLeft = id => {
136
+                if (id === this._requestedParticipant) {
111
                     clearRequest();
137
                     clearRequest();
112
                     resolve(null);
138
                     resolve(null);
113
                 }
139
                 }
114
             };
140
             };
141
+
115
             APP.conference.addConferenceListener(
142
             APP.conference.addConferenceListener(
116
                 ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
143
                 ConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
117
                 permissionsReplyListener);
144
                 permissionsReplyListener);
118
             APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
145
             APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
119
                 onUserLeft);
146
                 onUserLeft);
120
-            this.requestedParticipant = userId;
121
-            this._sendRemoteControlEvent(userId, {
147
+            this._requestedParticipant = userId;
148
+            this.sendRemoteControlEvent(userId, {
122
                 type: EVENT_TYPES.permissions,
149
                 type: EVENT_TYPES.permissions,
123
                 action: PERMISSIONS_ACTIONS.request
150
                 action: PERMISSIONS_ACTIONS.request
124
             }, e => {
151
             }, e => {
130
 
157
 
131
     /**
158
     /**
132
      * Handles the reply of the permissions request.
159
      * Handles the reply of the permissions request.
133
-     * @param {JitsiParticipant} participant the participant that has sent the
134
-     * reply
135
-     * @param {RemoteControlEvent} event the remote control event.
160
+     *
161
+     * @param {JitsiParticipant} participant - The participant that has sent the
162
+     * reply.
163
+     * @param {RemoteControlEvent} event - The remote control event.
164
+     * @returns {void}
136
      */
165
      */
137
-    _handleReply(participant, event) {
166
+    _handleReply(participant: Object, event: Object) {
138
         const userId = participant.getId();
167
         const userId = participant.getId();
139
-        if(this.enabled
168
+
169
+        if (this.enabled
140
                 && event.name === REMOTE_CONTROL_EVENT_NAME
170
                 && event.name === REMOTE_CONTROL_EVENT_NAME
141
                 && event.type === EVENT_TYPES.permissions
171
                 && event.type === EVENT_TYPES.permissions
142
-                && userId === this.requestedParticipant) {
143
-            if(event.action !== PERMISSIONS_ACTIONS.grant) {
144
-                this.area = null;
172
+                && userId === this._requestedParticipant) {
173
+            if (event.action !== PERMISSIONS_ACTIONS.grant) {
174
+                this._area = undefined;
145
             }
175
             }
146
-            switch(event.action) {
147
-                case PERMISSIONS_ACTIONS.grant: {
148
-                    this.controlledParticipant = userId;
149
-                    logger.log("Remote control permissions granted to: "
150
-                        + userId);
151
-                    this._start();
152
-                    return true;
153
-                }
154
-                case PERMISSIONS_ACTIONS.deny:
155
-                    return false;
156
-                case PERMISSIONS_ACTIONS.error:
157
-                    throw new Error("Error occurred on receiver side");
158
-                default:
159
-                    throw new Error("Unknown reply received!");
176
+            switch (event.action) {
177
+            case PERMISSIONS_ACTIONS.grant: {
178
+                this._controlledParticipant = userId;
179
+                logger.log('Remote control permissions granted to:', userId);
180
+                this._start();
181
+
182
+                return true;
183
+            }
184
+            case PERMISSIONS_ACTIONS.deny:
185
+                return false;
186
+            case PERMISSIONS_ACTIONS.error:
187
+                throw new Error('Error occurred on receiver side');
188
+            default:
189
+                throw new Error('Unknown reply received!');
160
             }
190
             }
161
         } else {
191
         } else {
162
-            //different message type or another user -> ignoring the message
192
+            // different message type or another user -> ignoring the message
163
             return null;
193
             return null;
164
         }
194
         }
165
     }
195
     }
166
 
196
 
167
     /**
197
     /**
168
      * Handles remote control stopped.
198
      * Handles remote control stopped.
169
-     * @param {JitsiParticipant} participant the participant that has sent the
170
-     * event
171
-     * @param {Object} event EndpointMessage event from the data channels.
172
-     * @property {string} type property. The function process only events with
173
-     * name REMOTE_CONTROL_EVENT_NAME
174
-     * @property {RemoteControlEvent} event - the remote control event.
199
+     *
200
+     * @param {JitsiParticipant} participant - The participant that has sent the
201
+     * event.
202
+     * @param {Object} event - EndpointMessage event from the data channels.
203
+     * @property {string} type - The function process only events with
204
+     * name REMOTE_CONTROL_EVENT_NAME.
205
+     * @returns {void}
175
      */
206
      */
176
-    _handleRemoteControlStoppedEvent(participant, event) {
177
-        if(this.enabled
207
+    _handleRemoteControlStoppedEvent(participant: Object, event: Object) {
208
+        if (this.enabled
178
                 && event.name === REMOTE_CONTROL_EVENT_NAME
209
                 && event.name === REMOTE_CONTROL_EVENT_NAME
179
                 && event.type === EVENT_TYPES.stop
210
                 && event.type === EVENT_TYPES.stop
180
-                && participant.getId() === this.controlledParticipant) {
211
+                && participant.getId() === this._controlledParticipant) {
181
             this._stop();
212
             this._stop();
182
         }
213
         }
183
     }
214
     }
185
     /**
216
     /**
186
      * Starts processing the mouse and keyboard events. Sets conference
217
      * Starts processing the mouse and keyboard events. Sets conference
187
      * listeners. Disables keyboard events.
218
      * listeners. Disables keyboard events.
219
+     *
220
+     * @returns {void}
188
      */
221
      */
189
     _start() {
222
     _start() {
190
-        logger.log("Starting remote control controller.");
223
+        logger.log('Starting remote control controller.');
191
         APP.UI.addListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
224
         APP.UI.addListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
192
             this._largeVideoChangedListener);
225
             this._largeVideoChangedListener);
193
         APP.conference.addConferenceListener(
226
         APP.conference.addConferenceListener(
200
 
233
 
201
     /**
234
     /**
202
      * Disables the keyboatd shortcuts. Starts collecting remote control
235
      * Disables the keyboatd shortcuts. Starts collecting remote control
203
-     * events.
236
+     * events. It can be used to resume an active remote control session wchich
237
+     * was paused with this.pause().
204
      *
238
      *
205
-     * It can be used to resume an active remote control session wchich was
206
-     * paused with this.pause().
239
+     * @returns {void}
207
      */
240
      */
208
     resume() {
241
     resume() {
209
-        if(!this.enabled || this.isCollectingEvents) {
242
+        if (!this.enabled || this._isCollectingEvents || !this._area) {
210
             return;
243
             return;
211
         }
244
         }
212
-        logger.log("Resuming remote control controller.");
213
-        this.isCollectingEvents = true;
245
+        logger.log('Resuming remote control controller.');
246
+        this._isCollectingEvents = true;
214
         APP.keyboardshortcut.enable(false);
247
         APP.keyboardshortcut.enable(false);
215
-        this.area.mousemove(event => {
216
-            const position = this.area.position();
217
-            this._sendRemoteControlEvent(this.controlledParticipant, {
248
+
249
+        // $FlowDisableNextLine: we are sure that this._area is not null.
250
+        this._area.mousemove(event => {
251
+            // $FlowDisableNextLine: we are sure that this._area is not null.
252
+            const position = this._area.position();
253
+
254
+            this.sendRemoteControlEvent(this._controlledParticipant, {
218
                 type: EVENT_TYPES.mousemove,
255
                 type: EVENT_TYPES.mousemove,
219
-                x: (event.pageX - position.left)/this.area.width(),
220
-                y: (event.pageY - position.top)/this.area.height()
256
+
257
+                // $FlowDisableNextLine: we are sure that this._area is not null
258
+                x: (event.pageX - position.left) / this._area.width(),
259
+
260
+                // $FlowDisableNextLine: we are sure that this._area is not null
261
+                y: (event.pageY - position.top) / this._area.height()
221
             });
262
             });
222
         });
263
         });
223
-        this.area.mousedown(this._onMouseClickHandler.bind(this,
264
+
265
+        // $FlowDisableNextLine: we are sure that this._area is not null.
266
+        this._area.mousedown(this._onMouseClickHandler.bind(this,
224
             EVENT_TYPES.mousedown));
267
             EVENT_TYPES.mousedown));
225
-        this.area.mouseup(this._onMouseClickHandler.bind(this,
268
+
269
+        // $FlowDisableNextLine: we are sure that this._area is not null.
270
+        this._area.mouseup(this._onMouseClickHandler.bind(this,
226
             EVENT_TYPES.mouseup));
271
             EVENT_TYPES.mouseup));
227
-        this.area.dblclick(
272
+
273
+        // $FlowDisableNextLine: we are sure that this._area is not null.
274
+        this._area.dblclick(
228
             this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick));
275
             this._onMouseClickHandler.bind(this, EVENT_TYPES.mousedblclick));
229
-        this.area.contextmenu(() => false);
230
-        this.area[0].onmousewheel = event => {
231
-            this._sendRemoteControlEvent(this.controlledParticipant, {
276
+
277
+        // $FlowDisableNextLine: we are sure that this._area is not null.
278
+        this._area.contextmenu(() => false);
279
+
280
+        // $FlowDisableNextLine: we are sure that this._area is not null.
281
+        this._area[0].onmousewheel = event => {
282
+            this.sendRemoteControlEvent(this._controlledParticipant, {
232
                 type: EVENT_TYPES.mousescroll,
283
                 type: EVENT_TYPES.mousescroll,
233
                 x: event.deltaX,
284
                 x: event.deltaX,
234
                 y: event.deltaY
285
                 y: event.deltaY
243
      * Stops processing the mouse and keyboard events. Removes added listeners.
294
      * Stops processing the mouse and keyboard events. Removes added listeners.
244
      * Enables the keyboard shortcuts. Displays dialog to notify the user that
295
      * Enables the keyboard shortcuts. Displays dialog to notify the user that
245
      * remote control session has ended.
296
      * remote control session has ended.
297
+     *
298
+     * @returns {void}
246
      */
299
      */
247
     _stop() {
300
     _stop() {
248
-        if(!this.controlledParticipant) {
301
+        if (!this._controlledParticipant) {
249
             return;
302
             return;
250
         }
303
         }
251
-        logger.log("Stopping remote control controller.");
304
+        logger.log('Stopping remote control controller.');
252
         APP.UI.removeListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
305
         APP.UI.removeListener(UIEvents.LARGE_VIDEO_ID_CHANGED,
253
             this._largeVideoChangedListener);
306
             this._largeVideoChangedListener);
254
         APP.conference.removeConferenceListener(
307
         APP.conference.removeConferenceListener(
256
             this._stopListener);
309
             this._stopListener);
257
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
310
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
258
             this._userLeftListener);
311
             this._userLeftListener);
259
-        this.controlledParticipant = null;
312
+        this._controlledParticipant = null;
260
         this.pause();
313
         this.pause();
261
-        this.area = null;
314
+        this._area = undefined;
262
         APP.UI.messageHandler.openMessageDialog(
315
         APP.UI.messageHandler.openMessageDialog(
263
-            "dialog.remoteControlTitle",
264
-            "dialog.remoteControlStopMessage"
316
+            'dialog.remoteControlTitle',
317
+            'dialog.remoteControlStopMessage'
265
         );
318
         );
266
     }
319
     }
267
 
320
 
268
     /**
321
     /**
269
-     * Executes this._stop() mehtod:
270
-     * Stops processing the mouse and keyboard events. Removes added listeners.
271
-     * Enables the keyboard shortcuts. Displays dialog to notify the user that
272
-     * remote control session has ended.
322
+     * Executes this._stop() mehtod which stops processing the mouse and
323
+     * keyboard events, removes added listeners, enables the keyboard shortcuts,
324
+     * displays dialog to notify the user that remote control session has ended.
325
+     * In addition sends stop message to the controlled participant.
273
      *
326
      *
274
-     * In addition:
275
-     * Sends stop message to the controlled participant.
327
+     * @returns {void}
276
      */
328
      */
277
     stop() {
329
     stop() {
278
-        if(!this.controlledParticipant) {
330
+        if (!this._controlledParticipant) {
279
             return;
331
             return;
280
         }
332
         }
281
-        this._sendRemoteControlEvent(this.controlledParticipant, {
333
+        this.sendRemoteControlEvent(this._controlledParticipant, {
282
             type: EVENT_TYPES.stop
334
             type: EVENT_TYPES.stop
283
         });
335
         });
284
         this._stop();
336
         this._stop();
288
      * Pauses the collecting of events and enables the keyboard shortcus. But
340
      * Pauses the collecting of events and enables the keyboard shortcus. But
289
      * it doesn't removes any other listeners. Basically the remote control
341
      * it doesn't removes any other listeners. Basically the remote control
290
      * session will be still active after this.pause(), but no events from the
342
      * session will be still active after this.pause(), but no events from the
291
-     * controller side will be captured and sent.
343
+     * controller side will be captured and sent. You can resume the collecting
344
+     * of the events with this.resume().
292
      *
345
      *
293
-     * You can resume the collecting of the events with this.resume().
346
+     * @returns {void}
294
      */
347
      */
295
     pause() {
348
     pause() {
296
-        if(!this.controlledParticipant) {
349
+        if (!this._controlledParticipant) {
297
             return;
350
             return;
298
         }
351
         }
299
-        logger.log("Pausing remote control controller.");
300
-        this.isCollectingEvents = false;
352
+        logger.log('Pausing remote control controller.');
353
+        this._isCollectingEvents = false;
301
         APP.keyboardshortcut.enable(true);
354
         APP.keyboardshortcut.enable(true);
302
-        this.area.off( "mousemove" );
303
-        this.area.off( "mousedown" );
304
-        this.area.off( "mouseup" );
305
-        this.area.off( "contextmenu" );
306
-        this.area.off( "dblclick" );
307
-        $(window).off( "keydown");
308
-        $(window).off( "keyup");
309
-        this.area[0].onmousewheel = undefined;
355
+
356
+        // $FlowDisableNextLine: we are sure that this._area is not null.
357
+        this._area.off('mousemove');
358
+
359
+        // $FlowDisableNextLine: we are sure that this._area is not null.
360
+        this._area.off('mousedown');
361
+
362
+        // $FlowDisableNextLine: we are sure that this._area is not null.
363
+        this._area.off('mouseup');
364
+
365
+        // $FlowDisableNextLine: we are sure that this._area is not null.
366
+        this._area.off('contextmenu');
367
+
368
+        // $FlowDisableNextLine: we are sure that this._area is not null.
369
+        this._area.off('dblclick');
370
+
371
+        $(window).off('keydown');
372
+        $(window).off('keyup');
373
+
374
+        // $FlowDisableNextLine: we are sure that this._area is not null.
375
+        this._area[0].onmousewheel = undefined;
310
     }
376
     }
311
 
377
 
312
     /**
378
     /**
313
      * Handler for mouse click events.
379
      * Handler for mouse click events.
314
-     * @param {String} type the type of event ("mousedown"/"mouseup")
315
-     * @param {Event} event the mouse event.
380
+     *
381
+     * @param {string} type - The type of event ("mousedown"/"mouseup").
382
+     * @param {Event} event - The mouse event.
383
+     * @returns {void}
316
      */
384
      */
317
-    _onMouseClickHandler(type, event) {
318
-        this._sendRemoteControlEvent(this.controlledParticipant, {
319
-            type: type,
385
+    _onMouseClickHandler(type: string, event: Object) {
386
+        this.sendRemoteControlEvent(this._controlledParticipant, {
387
+            type,
320
             button: event.which
388
             button: event.which
321
         });
389
         });
322
     }
390
     }
323
 
391
 
324
     /**
392
     /**
325
      * Returns true if the remote control session is started.
393
      * Returns true if the remote control session is started.
394
+     *
326
      * @returns {boolean}
395
      * @returns {boolean}
327
      */
396
      */
328
     isStarted() {
397
     isStarted() {
329
-        return this.controlledParticipant !== null;
398
+        return this._controlledParticipant !== null;
330
     }
399
     }
331
 
400
 
332
     /**
401
     /**
333
-     * Returns the id of the requested participant
334
-     * @returns {string} this.requestedParticipant.
402
+     * Returns the id of the requested participant.
403
+     *
404
+     * @returns {string} The id of the requested participant.
335
      * NOTE: This id should be the result of JitsiParticipant.getId() call.
405
      * NOTE: This id should be the result of JitsiParticipant.getId() call.
336
      */
406
      */
337
     getRequestedParticipant() {
407
     getRequestedParticipant() {
338
-        return this.requestedParticipant;
408
+        return this._requestedParticipant;
339
     }
409
     }
340
 
410
 
341
     /**
411
     /**
342
      * Handler for key press events.
412
      * Handler for key press events.
343
-     * @param {String} type the type of event ("keydown"/"keyup")
344
-     * @param {Event} event the key event.
413
+     *
414
+     * @param {string} type - The type of event ("keydown"/"keyup").
415
+     * @param {Event} event - The key event.
416
+     * @returns {void}
345
      */
417
      */
346
-    _onKeyPessHandler(type, event) {
347
-        this._sendRemoteControlEvent(this.controlledParticipant, {
348
-            type: type,
418
+    _onKeyPessHandler(type: string, event: Object) {
419
+        this.sendRemoteControlEvent(this._controlledParticipant, {
420
+            type,
349
             key: getKey(event),
421
             key: getKey(event),
350
-            modifiers: getModifiers(event),
422
+            modifiers: getModifiers(event)
351
         });
423
         });
352
     }
424
     }
353
 
425
 
354
     /**
426
     /**
355
      * Calls the stop method if the other side have left.
427
      * Calls the stop method if the other side have left.
356
-     * @param {string} id - the user id for the participant that have left
428
+     *
429
+     * @param {string} id - The user id for the participant that have left.
430
+     * @returns {void}
357
      */
431
      */
358
-    _onUserLeft(id) {
359
-        if(this.controlledParticipant === id) {
432
+    _onUserLeft(id: string) {
433
+        if (this._controlledParticipant === id) {
360
             this._stop();
434
             this._stop();
361
         }
435
         }
362
     }
436
     }
363
 
437
 
364
     /**
438
     /**
365
      * Handles changes of the participant displayed on the large video.
439
      * Handles changes of the participant displayed on the large video.
366
-     * @param {string} id - the user id for the participant that is displayed.
440
+     *
441
+     * @param {string} id - The user id for the participant that is displayed.
442
+     * @returns {void}
367
      */
443
      */
368
-    _onLargeVideoIdChanged(id) {
369
-        if (!this.controlledParticipant) {
444
+    _onLargeVideoIdChanged(id: string) {
445
+        if (!this._controlledParticipant) {
370
             return;
446
             return;
371
         }
447
         }
372
-        if(this.controlledParticipant == id) {
448
+        if (this._controlledParticipant === id) {
373
             this.resume();
449
             this.resume();
374
         } else {
450
         } else {
375
             this.pause();
451
             this.pause();

+ 164
- 78
modules/remotecontrol/Receiver.js 查看文件

1
-/* global APP, config, interfaceConfig, JitsiMeetJS */
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
2
 
4
 
3
 import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
5
 import * as JitsiMeetConferenceEvents from '../../ConferenceEvents';
6
+import {
7
+    openRemoteControlAuthorizationDialog
8
+} from '../../react/features/remote-control';
4
 import {
9
 import {
5
     DISCO_REMOTE_CONTROL_FEATURE,
10
     DISCO_REMOTE_CONTROL_FEATURE,
6
     EVENT_TYPES,
11
     EVENT_TYPES,
11
 
16
 
12
 import RemoteControlParticipant from './RemoteControlParticipant';
17
 import RemoteControlParticipant from './RemoteControlParticipant';
13
 
18
 
19
+declare var APP: Object;
20
+declare var config: Object;
21
+declare var interfaceConfig: Object;
22
+declare var JitsiMeetJS: Object;
23
+
14
 const ConferenceEvents = JitsiMeetJS.events.conference;
24
 const ConferenceEvents = JitsiMeetJS.events.conference;
15
-const logger = require("jitsi-meet-logger").getLogger(__filename);
25
+const logger = getLogger(__filename);
16
 
26
 
17
 /**
27
 /**
18
  * The transport instance used for communication with external apps.
28
  * The transport instance used for communication with external apps.
28
  * and executed.
38
  * and executed.
29
  */
39
  */
30
 export default class Receiver extends RemoteControlParticipant {
40
 export default class Receiver extends RemoteControlParticipant {
41
+    _controller: ?string;
42
+    _enabled: boolean;
43
+    _hangupListener: Function;
44
+    _remoteControlEventsListener: Function;
45
+    _userLeftListener: Function;
46
+
31
     /**
47
     /**
32
      * Creates new instance.
48
      * Creates new instance.
33
-     * @constructor
34
      */
49
      */
35
     constructor() {
50
     constructor() {
36
         super();
51
         super();
37
-        this.controller = null;
52
+        this._controller = null;
38
         this._remoteControlEventsListener
53
         this._remoteControlEventsListener
39
             = this._onRemoteControlEvent.bind(this);
54
             = this._onRemoteControlEvent.bind(this);
40
         this._userLeftListener = this._onUserLeft.bind(this);
55
         this._userLeftListener = this._onUserLeft.bind(this);
41
         this._hangupListener = this._onHangup.bind(this);
56
         this._hangupListener = this._onHangup.bind(this);
57
+
42
         // We expect here that even if we receive the supported event earlier
58
         // We expect here that even if we receive the supported event earlier
43
         // it will be cached and we'll receive it.
59
         // it will be cached and we'll receive it.
44
         transport.on('event', event => {
60
         transport.on('event', event => {
53
     }
69
     }
54
 
70
 
55
     /**
71
     /**
56
-     * Enables / Disables the remote control
57
-     * @param {boolean} enabled the new state.
72
+     * Enables / Disables the remote control.
73
+     *
74
+     * @param {boolean} enabled - The new state.
75
+     * @returns {void}
58
      */
76
      */
59
-    _enable(enabled) {
60
-        if(this.enabled === enabled) {
77
+    _enable(enabled: boolean) {
78
+        if (this._enabled === enabled) {
61
             return;
79
             return;
62
         }
80
         }
63
-        this.enabled = enabled;
64
-        if(enabled === true) {
65
-            logger.log("Remote control receiver enabled.");
81
+        this._enabled = enabled;
82
+        if (enabled === true) {
83
+            logger.log('Remote control receiver enabled.');
84
+
66
             // Announce remote control support.
85
             // Announce remote control support.
67
             APP.connection.addFeature(DISCO_REMOTE_CONTROL_FEATURE, true);
86
             APP.connection.addFeature(DISCO_REMOTE_CONTROL_FEATURE, true);
68
             APP.conference.addConferenceListener(
87
             APP.conference.addConferenceListener(
71
             APP.conference.addListener(JitsiMeetConferenceEvents.BEFORE_HANGUP,
90
             APP.conference.addListener(JitsiMeetConferenceEvents.BEFORE_HANGUP,
72
                 this._hangupListener);
91
                 this._hangupListener);
73
         } else {
92
         } else {
74
-            logger.log("Remote control receiver disabled.");
93
+            logger.log('Remote control receiver disabled.');
75
             this._stop(true);
94
             this._stop(true);
76
             APP.connection.removeFeature(DISCO_REMOTE_CONTROL_FEATURE);
95
             APP.connection.removeFeature(DISCO_REMOTE_CONTROL_FEATURE);
77
             APP.conference.removeConferenceListener(
96
             APP.conference.removeConferenceListener(
88
      * events. Sends stop message to the wrapper application. Optionally
107
      * events. Sends stop message to the wrapper application. Optionally
89
      * displays dialog for informing the user that remote control session
108
      * displays dialog for informing the user that remote control session
90
      * ended.
109
      * ended.
91
-     * @param {boolean} dontShowDialog - if true the dialog won't be displayed.
110
+     *
111
+     * @param {boolean} [dontShowDialog] - If true the dialog won't be
112
+     * displayed.
113
+     * @returns {void}
92
      */
114
      */
93
-    _stop(dontShowDialog = false) {
94
-        if(!this.controller) {
115
+    _stop(dontShowDialog: boolean = false) {
116
+        if (!this._controller) {
95
             return;
117
             return;
96
         }
118
         }
97
-        logger.log("Remote control receiver stop.");
98
-        this.controller = null;
119
+        logger.log('Remote control receiver stop.');
120
+        this._controller = null;
99
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
121
         APP.conference.removeConferenceListener(ConferenceEvents.USER_LEFT,
100
             this._userLeftListener);
122
             this._userLeftListener);
101
-        transport.sendEvent({
102
-            name: REMOTE_CONTROL_EVENT_NAME,
103
-            type: EVENT_TYPES.stop
104
-        });
105
-        if(!dontShowDialog) {
123
+        if (this.remoteControlExternalAuth) {
124
+            transport.sendEvent({
125
+                name: REMOTE_CONTROL_EVENT_NAME,
126
+                type: EVENT_TYPES.stop
127
+            });
128
+        }
129
+        if (!dontShowDialog) {
106
             APP.UI.messageHandler.openMessageDialog(
130
             APP.UI.messageHandler.openMessageDialog(
107
-                "dialog.remoteControlTitle",
108
-                "dialog.remoteControlStopMessage"
131
+                'dialog.remoteControlTitle',
132
+                'dialog.remoteControlStopMessage'
109
             );
133
             );
110
         }
134
         }
111
     }
135
     }
112
 
136
 
113
     /**
137
     /**
114
-     * Calls this._stop() and sends stop message to the controller participant
138
+     * Calls this._stop() and sends stop message to the controller participant.
139
+     *
140
+     * @returns {void}
115
      */
141
      */
116
     stop() {
142
     stop() {
117
-        if(!this.controller) {
143
+        if (!this._controller) {
118
             return;
144
             return;
119
         }
145
         }
120
-        this._sendRemoteControlEvent(this.controller, {
146
+        this.sendRemoteControlEvent(this._controller, {
121
             type: EVENT_TYPES.stop
147
             type: EVENT_TYPES.stop
122
         });
148
         });
123
         this._stop();
149
         this._stop();
127
      * Listens for data channel EndpointMessage events. Handles only events of
153
      * Listens for data channel EndpointMessage events. Handles only events of
128
      * type remote control. Sends "remote-control-event" events to the API
154
      * type remote control. Sends "remote-control-event" events to the API
129
      * module.
155
      * module.
130
-     * @param {JitsiParticipant} participant the controller participant
131
-     * @param {Object} event EndpointMessage event from the data channels.
132
-     * @property {string} type property. The function process only events with
133
-     * name REMOTE_CONTROL_EVENT_NAME
134
-     * @property {RemoteControlEvent} event - the remote control event.
156
+     *
157
+     * @param {JitsiParticipant} participant - The controller participant.
158
+     * @param {Object} event - EndpointMessage event from the data channels.
159
+     * @param {string} event.name - The function process only events with
160
+     * name REMOTE_CONTROL_EVENT_NAME.
161
+     * @returns {void}
135
      */
162
      */
136
-    _onRemoteControlEvent(participant, event) {
163
+    _onRemoteControlEvent(participant: Object, event: Object) {
137
         if (event.name !== REMOTE_CONTROL_EVENT_NAME) {
164
         if (event.name !== REMOTE_CONTROL_EVENT_NAME) {
138
             return;
165
             return;
139
         }
166
         }
140
 
167
 
141
         const remoteControlEvent = Object.assign({}, event);
168
         const remoteControlEvent = Object.assign({}, event);
142
 
169
 
143
-        if (this.enabled) {
144
-            if (this.controller === null
170
+        if (this._enabled) {
171
+            if (this._controller === null
145
                     && event.type === EVENT_TYPES.permissions
172
                     && event.type === EVENT_TYPES.permissions
146
                     && event.action === PERMISSIONS_ACTIONS.request) {
173
                     && event.action === PERMISSIONS_ACTIONS.request) {
174
+                const userId = participant.getId();
175
+
176
+                if (!config.remoteControlExternalAuth) {
177
+                    APP.store.dispatch(
178
+                        openRemoteControlAuthorizationDialog(userId));
179
+
180
+                    return;
181
+                }
182
+
147
                 // FIXME: Maybe use transport.sendRequest in this case???
183
                 // FIXME: Maybe use transport.sendRequest in this case???
148
-                remoteControlEvent.userId = participant.getId();
184
+                remoteControlEvent.userId = userId;
149
                 remoteControlEvent.userJID = participant.getJid();
185
                 remoteControlEvent.userJID = participant.getJid();
150
                 remoteControlEvent.displayName = participant.getDisplayName()
186
                 remoteControlEvent.displayName = participant.getDisplayName()
151
                     || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
187
                     || interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
152
                 remoteControlEvent.screenSharing
188
                 remoteControlEvent.screenSharing
153
                     = APP.conference.isSharingScreen;
189
                     = APP.conference.isSharingScreen;
154
-            } else if (this.controller !== participant.getId()) {
190
+            } else if (this._controller !== participant.getId()) {
155
                 return;
191
                 return;
156
             } else if (event.type === EVENT_TYPES.stop) {
192
             } else if (event.type === EVENT_TYPES.stop) {
157
                 this._stop();
193
                 this._stop();
194
+
158
                 return;
195
                 return;
159
             }
196
             }
160
             transport.sendEvent(remoteControlEvent);
197
             transport.sendEvent(remoteControlEvent);
161
         } else {
198
         } else {
162
-            logger.log("Remote control event is ignored because remote "
163
-                + "control is disabled", event);
199
+            logger.log('Remote control event is ignored because remote '
200
+                + 'control is disabled', event);
164
         }
201
         }
165
     }
202
     }
166
 
203
 
167
     /**
204
     /**
168
      * Handles remote control permission events.
205
      * Handles remote control permission events.
169
-     * @param {String} userId the user id of the participant related to the
206
+     *
207
+     * @param {string} userId - The user id of the participant related to the
170
      * event.
208
      * event.
171
-     * @param {PERMISSIONS_ACTIONS} action the action related to the event.
209
+     * @param {PERMISSIONS_ACTIONS} action - The action related to the event.
210
+     * @returns {void}
211
+     */
212
+    _onRemoteControlPermissionsEvent(userId: string, action: string) {
213
+        switch (action) {
214
+        case PERMISSIONS_ACTIONS.grant:
215
+            this.grant(userId);
216
+            break;
217
+        case PERMISSIONS_ACTIONS.deny:
218
+            this.deny(userId);
219
+            break;
220
+        case PERMISSIONS_ACTIONS.error:
221
+            this.sendRemoteControlEvent(userId, {
222
+                type: EVENT_TYPES.permissions,
223
+                action
224
+            });
225
+            break;
226
+        default:
227
+
228
+                // Unknown action. Ignore.
229
+        }
230
+    }
231
+
232
+    /**
233
+     * Denies remote control access for user associated with the passed user id.
234
+     *
235
+     * @param {string} userId - The id associated with the user who sent the
236
+     * request for remote control authorization.
237
+     * @returns {void}
238
+     */
239
+    deny(userId: string) {
240
+        this.sendRemoteControlEvent(userId, {
241
+            type: EVENT_TYPES.permissions,
242
+            action: PERMISSIONS_ACTIONS.deny
243
+        });
244
+    }
245
+
246
+    /**
247
+     * Grants remote control access to user associated with the passed user id.
248
+     *
249
+     * @param {string} userId - The id associated with the user who sent the
250
+     * request for remote control authorization.
251
+     * @returns {void}
172
      */
252
      */
173
-    _onRemoteControlPermissionsEvent(userId, action) {
174
-        if (action === PERMISSIONS_ACTIONS.grant) {
175
-            APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
176
-                this._userLeftListener);
177
-            this.controller = userId;
178
-            logger.log("Remote control permissions granted to: " + userId);
179
-            if(!APP.conference.isSharingScreen) {
180
-                APP.conference.toggleScreenSharing();
181
-                APP.conference.screenSharingPromise.then(() => {
182
-                    if(APP.conference.isSharingScreen) {
183
-                        this._sendRemoteControlEvent(userId, {
184
-                            type: EVENT_TYPES.permissions,
185
-                            action: action
186
-                        });
187
-                    } else {
188
-                        this._sendRemoteControlEvent(userId, {
189
-                            type: EVENT_TYPES.permissions,
190
-                            action: PERMISSIONS_ACTIONS.error
191
-                        });
192
-                    }
193
-                }).catch(() => {
194
-                    this._sendRemoteControlEvent(userId, {
253
+    grant(userId: string) {
254
+        APP.conference.addConferenceListener(ConferenceEvents.USER_LEFT,
255
+            this._userLeftListener);
256
+        this._controller = userId;
257
+        logger.log(`Remote control permissions granted to: ${userId}`);
258
+        if (APP.conference.isSharingScreen) {
259
+            this.sendRemoteControlEvent(userId, {
260
+                type: EVENT_TYPES.permissions,
261
+                action: PERMISSIONS_ACTIONS.grant
262
+            });
263
+        } else {
264
+            APP.conference.toggleScreenSharing();
265
+            APP.conference.screenSharingPromise.then(() => {
266
+                if (APP.conference.isSharingScreen) {
267
+                    this.sendRemoteControlEvent(userId, {
268
+                        type: EVENT_TYPES.permissions,
269
+                        action: PERMISSIONS_ACTIONS.grant
270
+                    });
271
+                } else {
272
+                    this.sendRemoteControlEvent(userId, {
195
                         type: EVENT_TYPES.permissions,
273
                         type: EVENT_TYPES.permissions,
196
                         action: PERMISSIONS_ACTIONS.error
274
                         action: PERMISSIONS_ACTIONS.error
197
                     });
275
                     });
276
+                }
277
+            }).catch(() => {
278
+                this.sendRemoteControlEvent(userId, {
279
+                    type: EVENT_TYPES.permissions,
280
+                    action: PERMISSIONS_ACTIONS.error
198
                 });
281
                 });
199
-                return;
200
-            }
282
+            });
201
         }
283
         }
202
-        this._sendRemoteControlEvent(userId, {
203
-            type: EVENT_TYPES.permissions,
204
-            action
205
-        });
206
     }
284
     }
207
 
285
 
208
     /**
286
     /**
209
      * Handles remote control events from the external app. Currently only
287
      * 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.
288
+     * events with type = EVENT_TYPES.supported or EVENT_TYPES.permissions.
289
+     *
290
+     * @param {RemoteControlEvent} event - The remote control event.
291
+     * @returns {void}
212
      */
292
      */
213
-    _onRemoteControlAPIEvent(event) {
214
-        switch(event.type) {
293
+    _onRemoteControlAPIEvent(event: Object) {
294
+        switch (event.type) {
215
         case EVENT_TYPES.permissions:
295
         case EVENT_TYPES.permissions:
216
             this._onRemoteControlPermissionsEvent(event.userId, event.action);
296
             this._onRemoteControlPermissionsEvent(event.userId, event.action);
217
             break;
297
             break;
224
     /**
304
     /**
225
      * Handles events for support for executing remote control events into
305
      * Handles events for support for executing remote control events into
226
      * the wrapper application.
306
      * the wrapper application.
307
+     *
308
+     * @returns {void}
227
      */
309
      */
228
     _onRemoteControlSupported() {
310
     _onRemoteControlSupported() {
229
-        logger.log("Remote Control supported.");
311
+        logger.log('Remote Control supported.');
230
         if (config.disableRemoteControl) {
312
         if (config.disableRemoteControl) {
231
-            logger.log("Remote Control disabled.");
313
+            logger.log('Remote Control disabled.');
232
         } else {
314
         } else {
233
             this._enable(true);
315
             this._enable(true);
234
         }
316
         }
236
 
318
 
237
     /**
319
     /**
238
      * Calls the stop method if the other side have left.
320
      * Calls the stop method if the other side have left.
239
-     * @param {string} id - the user id for the participant that have left
321
+     *
322
+     * @param {string} id - The user id for the participant that have left.
323
+     * @returns {void}
240
      */
324
      */
241
-    _onUserLeft(id) {
242
-        if(this.controller === id) {
325
+    _onUserLeft(id: string) {
326
+        if (this._controller === id) {
243
             this._stop();
327
             this._stop();
244
         }
328
         }
245
     }
329
     }
246
 
330
 
247
     /**
331
     /**
248
      * Handles hangup events. Disables the receiver.
332
      * Handles hangup events. Disables the receiver.
333
+     *
334
+     * @returns {void}
249
      */
335
      */
250
     _onHangup() {
336
     _onHangup() {
251
         this._enable(false);
337
         this._enable(false);

+ 23
- 12
modules/remotecontrol/RemoteControl.js 查看文件

1
-/* global APP, config */
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
2
 
4
 
3
 import { DISCO_REMOTE_CONTROL_FEATURE }
5
 import { DISCO_REMOTE_CONTROL_FEATURE }
4
     from '../../service/remotecontrol/Constants';
6
     from '../../service/remotecontrol/Constants';
6
 import Controller from './Controller';
8
 import Controller from './Controller';
7
 import Receiver from './Receiver';
9
 import Receiver from './Receiver';
8
 
10
 
9
-const logger = require('jitsi-meet-logger').getLogger(__filename);
11
+const logger = getLogger(__filename);
12
+
13
+declare var APP: Object;
14
+declare var config: Object;
10
 
15
 
11
 /**
16
 /**
12
  * Implements the remote control functionality.
17
  * Implements the remote control functionality.
13
  */
18
  */
14
 class RemoteControl {
19
 class RemoteControl {
20
+    _initialized: boolean;
21
+    controller: Controller;
22
+    receiver: Receiver;
23
+
15
     /**
24
     /**
16
      * Constructs new instance. Creates controller and receiver properties.
25
      * Constructs new instance. Creates controller and receiver properties.
17
-     * @constructor
18
      */
26
      */
19
     constructor() {
27
     constructor() {
20
         this.controller = new Controller();
28
         this.controller = new Controller();
21
-        this.initialized = false;
29
+        this._initialized = false;
22
     }
30
     }
23
 
31
 
24
     /**
32
     /**
25
      * Initializes the remote control - checks if the remote control should be
33
      * Initializes the remote control - checks if the remote control should be
26
      * enabled or not.
34
      * enabled or not.
35
+     *
36
+     * @returns {void}
27
      */
37
      */
28
     init() {
38
     init() {
29
-        if(config.disableRemoteControl
30
-                || this.initialized
39
+        if (config.disableRemoteControl
40
+                || this._initialized
31
                 || !APP.conference.isDesktopSharingEnabled) {
41
                 || !APP.conference.isDesktopSharingEnabled) {
32
             return;
42
             return;
33
         }
43
         }
34
-        logger.log("Initializing remote control.");
35
-        this.initialized = true;
44
+        logger.log('Initializing remote control.');
45
+        this._initialized = true;
36
         this.controller.enable(true);
46
         this.controller.enable(true);
37
         this.receiver = new Receiver();
47
         this.receiver = new Receiver();
38
     }
48
     }
39
 
49
 
40
     /**
50
     /**
41
-     * Checks whether the passed user supports remote control or not
42
-     * @param {JitsiParticipant} user the user to be tested
43
-     * @returns {Promise<boolean>} the promise will be resolved with true if
51
+     * Checks whether the passed user supports remote control or not.
52
+     *
53
+     * @param {JitsiParticipant} user - The user to be tested.
54
+     * @returns {Promise<boolean>} The promise will be resolved with true if
44
      * the user supports remote control and with false if not.
55
      * the user supports remote control and with false if not.
45
      */
56
      */
46
-    checkUserRemoteControlSupport(user) {
57
+    checkUserRemoteControlSupport(user: Object) {
47
         return user.getFeatures().then(
58
         return user.getFeatures().then(
48
             features => features.has(DISCO_REMOTE_CONTROL_FEATURE),
59
             features => features.has(DISCO_REMOTE_CONTROL_FEATURE),
49
             () => false);
60
             () => false);

+ 36
- 16
modules/remotecontrol/RemoteControlParticipant.js 查看文件

1
-/* global APP */
1
+/* @flow */
2
+
3
+import { getLogger } from 'jitsi-meet-logger';
2
 
4
 
3
 import {
5
 import {
4
     REMOTE_CONTROL_EVENT_NAME
6
     REMOTE_CONTROL_EVENT_NAME
5
-} from "../../service/remotecontrol/Constants";
7
+} from '../../service/remotecontrol/Constants';
8
+
9
+const logger = getLogger(__filename);
6
 
10
 
7
-const logger = require("jitsi-meet-logger").getLogger(__filename);
11
+declare var APP: Object;
8
 
12
 
13
+/**
14
+ * Implements common logic for Receiver class and Controller class.
15
+ */
9
 export default class RemoteControlParticipant {
16
 export default class RemoteControlParticipant {
17
+    _enabled: boolean;
18
+
10
     /**
19
     /**
11
      * Creates new instance.
20
      * Creates new instance.
12
      */
21
      */
13
     constructor() {
22
     constructor() {
14
-        this.enabled = false;
23
+        this._enabled = false;
15
     }
24
     }
16
 
25
 
17
     /**
26
     /**
18
-     * Enables / Disables the remote control
19
-     * @param {boolean} enabled the new state.
27
+     * Enables / Disables the remote control.
28
+     *
29
+     * @param {boolean} enabled - The new state.
30
+     * @returns {void}
20
      */
31
      */
21
-    enable(enabled) {
22
-        this.enabled = enabled;
32
+    enable(enabled: boolean) {
33
+        this._enabled = enabled;
23
     }
34
     }
24
 
35
 
25
     /**
36
     /**
26
      * Sends remote control event to other participant trough data channel.
37
      * Sends remote control event to other participant trough data channel.
27
-     * @param {RemoteControlEvent} event the remote control event.
28
-     * @param {Function} onDataChannelFail handler for data channel failure.
38
+     *
39
+     * @param {string} to - The participant who will receive the event.
40
+     * @param {RemoteControlEvent} event - The remote control event.
41
+     * @param {Function} onDataChannelFail - Handler for data channel failure.
42
+     * @returns {void}
29
      */
43
      */
30
-    _sendRemoteControlEvent(to, event, onDataChannelFail = () => {}) {
31
-        if(!this.enabled || !to) {
44
+    sendRemoteControlEvent(
45
+            to: ?string,
46
+            event: Object,
47
+            onDataChannelFail: ?Function) {
48
+        if (!this._enabled || !to) {
32
             logger.warn(
49
             logger.warn(
33
-                "Remote control: Skip sending remote control event. Params:",
50
+                'Remote control: Skip sending remote control event. Params:',
34
                 this.enable,
51
                 this.enable,
35
                 to);
52
                 to);
53
+
36
             return;
54
             return;
37
         }
55
         }
38
-        try{
56
+        try {
39
             APP.conference.sendEndpointMessage(to, {
57
             APP.conference.sendEndpointMessage(to, {
40
                 name: REMOTE_CONTROL_EVENT_NAME,
58
                 name: REMOTE_CONTROL_EVENT_NAME,
41
                 ...event
59
                 ...event
42
             });
60
             });
43
         } catch (e) {
61
         } catch (e) {
44
             logger.error(
62
             logger.error(
45
-                "Failed to send EndpointMessage via the datachannels",
63
+                'Failed to send EndpointMessage via the datachannels',
46
                 e);
64
                 e);
47
-            onDataChannelFail(e);
65
+            if (typeof onDataChannelFail === 'function') {
66
+                onDataChannelFail(e);
67
+            }
48
         }
68
         }
49
     }
69
     }
50
 }
70
 }

+ 2
- 1
react/features/app/components/AbstractApp.js 查看文件

88
             localParticipant = {
88
             localParticipant = {
89
                 avatarID: APP.settings.getAvatarId(),
89
                 avatarID: APP.settings.getAvatarId(),
90
                 avatarURL: APP.settings.getAvatarUrl(),
90
                 avatarURL: APP.settings.getAvatarUrl(),
91
-                email: APP.settings.getEmail()
91
+                email: APP.settings.getEmail(),
92
+                name: APP.settings.getDisplayName()
92
             };
93
             };
93
         }
94
         }
94
         dispatch(localParticipantJoined(localParticipant));
95
         dispatch(localParticipantJoined(localParticipant));

+ 1
- 1
react/features/base/dialog/components/AbstractDialog.js 查看文件

24
         cancelTitleKey: React.PropTypes.string,
24
         cancelTitleKey: React.PropTypes.string,
25
 
25
 
26
         /**
26
         /**
27
-         * Used to show hide the dialog on cancel.
27
+         * Used to show/hide the dialog on cancel.
28
          */
28
          */
29
         dispatch: React.PropTypes.func,
29
         dispatch: React.PropTypes.func,
30
 
30
 

+ 21
- 0
react/features/remote-control/actions.js 查看文件

1
+import { openDialog } from '../base/dialog';
2
+
3
+import { RemoteControlAuthorizationDialog } from './components';
4
+
5
+/**
6
+ * Signals that the remote control authorization dialog should be displayed.
7
+ *
8
+ * @param {string} participantId - The id of the participant who is requesting
9
+ * the authorization.
10
+ * @returns {{
11
+ *     type: OPEN_DIALOG,
12
+ *     component: {RemoteControlAuthorizationDialog},
13
+ *     componentProps: {
14
+ *         participantId: {string}
15
+ *      }
16
+ * }}
17
+ * @public
18
+ */
19
+export function openRemoteControlAuthorizationDialog(participantId) {
20
+    return openDialog(RemoteControlAuthorizationDialog, { participantId });
21
+}

+ 165
- 0
react/features/remote-control/components/RemoteControlAuthorizationDialog.js 查看文件

1
+import React, { Component } from 'react';
2
+import { connect } from 'react-redux';
3
+
4
+import {
5
+    Dialog,
6
+    hideDialog
7
+} from '../../base/dialog';
8
+import { translate } from '../../base/i18n';
9
+import { getParticipantById } from '../../base/participants';
10
+
11
+declare var APP: Object;
12
+
13
+/**
14
+ * Implements a dialog for remote control authorization.
15
+ */
16
+class RemoteControlAuthorizationDialog extends Component {
17
+    /**
18
+     * RemoteControlAuthorizationDialog component's property types.
19
+     *
20
+     * @static
21
+     */
22
+    static propTypes = {
23
+        /**
24
+         * The display name of the participant who is requesting authorization
25
+         * for remote desktop control session.
26
+         *
27
+         * @private
28
+         */
29
+        _displayName: React.PropTypes.string,
30
+
31
+        /**
32
+         * Used to show/hide the dialog on cancel.
33
+         */
34
+        dispatch: React.PropTypes.func,
35
+
36
+        /**
37
+         * The ID of the participant who is requesting authorization for remote
38
+         * desktop control session.
39
+         *
40
+         * @public
41
+         */
42
+        participantId: React.PropTypes.string,
43
+
44
+        /**
45
+         * Invoked to obtain translated strings.
46
+         */
47
+        t: React.PropTypes.func
48
+    }
49
+
50
+    /**
51
+     * Initializes a new RemoteControlAuthorizationDialog instance.
52
+     *
53
+     * @param {Object} props - The read-only properties with which the new
54
+     * instance is to be initialized.
55
+     */
56
+    constructor(props) {
57
+        super(props);
58
+
59
+        this._onCancel = this._onCancel.bind(this);
60
+        this._onSubmit = this._onSubmit.bind(this);
61
+    }
62
+
63
+    /**
64
+     * Implements React's {@link Component#render()}.
65
+     *
66
+     * @inheritdoc
67
+     */
68
+    render() {
69
+        return (
70
+            <Dialog
71
+                okTitleKey = { 'dialog.allow' }
72
+                onCancel = { this._onCancel }
73
+                onSubmit = { this._onSubmit }
74
+                titleKey = 'dialog.remoteControlTitle'
75
+                width = 'small'>
76
+                {
77
+                    this.props.t('dialog.remoteControlRequestMessage',
78
+                    { user: this.props._displayName })
79
+                }
80
+                {
81
+                    this._getAdditionalMessage()
82
+                }
83
+            </Dialog>
84
+        );
85
+    }
86
+
87
+    /**
88
+     * Renders additional message text for the dialog.
89
+     *
90
+     * @private
91
+     * @returns {ReactElement}
92
+     */
93
+    _getAdditionalMessage() {
94
+        // FIXME: Once we have this information in redux we should
95
+        // start getting it from there.
96
+        if (APP.conference.isSharingScreen) {
97
+            return null;
98
+        }
99
+
100
+        return (
101
+            <div>
102
+                <br />
103
+                { this.props.t('dialog.remoteControlShareScreenWarning') }
104
+            </div>
105
+        );
106
+    }
107
+
108
+    /**
109
+     * Notifies the remote control module about the denial of the remote control
110
+     * request.
111
+     *
112
+     * @private
113
+     * @returns {boolean} Returns true to close the dialog.
114
+     */
115
+    _onCancel() {
116
+        // FIXME: This should be action one day.
117
+        APP.remoteControl.receiver.deny(this.props.participantId);
118
+
119
+        return true;
120
+    }
121
+
122
+    /**
123
+     * Notifies the remote control module that the remote control request is
124
+     * accepted.
125
+     *
126
+     * @private
127
+     * @returns {boolean} Returns false to prevent closure because the dialog is
128
+     * closed manually to be sure that if the desktop picker dialog can be
129
+     * displayed (if this dialog is displayed when we try to display the desktop
130
+     * picker window, the action will be ignored).
131
+     */
132
+    _onSubmit() {
133
+        this.props.dispatch(hideDialog());
134
+
135
+        // FIXME: This should be action one day.
136
+        APP.remoteControl.receiver.grant(this.props.participantId);
137
+
138
+        return false;
139
+    }
140
+}
141
+
142
+/**
143
+ * Maps (parts of) the Redux state to the RemoteControlAuthorizationDialog's
144
+ * props.
145
+ *
146
+ * @param {Object} state - The Redux state.
147
+ * @param {Object} ownProps - The React Component props passed to the associated
148
+ * (instance of) RemoteControlAuthorizationDialog.
149
+ * @private
150
+ * @returns {{
151
+ *     _displayName: string
152
+ * }}
153
+ */
154
+function _mapStateToProps(state, ownProps) {
155
+    const { _displayName, participantId } = ownProps;
156
+    const participant = getParticipantById(
157
+            state['features/base/participants'], participantId);
158
+
159
+    return {
160
+        _displayName: participant ? participant.name : _displayName
161
+    };
162
+}
163
+
164
+export default translate(
165
+    connect(_mapStateToProps)(RemoteControlAuthorizationDialog));

+ 2
- 0
react/features/remote-control/components/index.js 查看文件

1
+export { default as RemoteControlAuthorizationDialog }
2
+    from './RemoteControlAuthorizationDialog';

+ 2
- 0
react/features/remote-control/index.js 查看文件

1
+export * from './actions';
2
+export * from './components';

Loading…
取消
儲存