|
@@ -1,25 +1,24 @@
|
1
|
|
-// @flow
|
2
|
|
-
|
3
|
1
|
import { sha512_256 as sha512 } from 'js-sha512';
|
4
|
2
|
import _ from 'lodash';
|
5
|
3
|
|
|
4
|
+// @ts-ignore
|
6
|
5
|
import { getName } from '../../app/functions';
|
|
6
|
+import { IState, IStore } from '../../app/types';
|
7
|
7
|
import { determineTranscriptionLanguage } from '../../transcribing/functions';
|
|
8
|
+import { IStateful } from '../app/types';
|
8
|
9
|
import { JitsiTrackErrors } from '../lib-jitsi-meet';
|
9
|
10
|
import {
|
10
|
|
- getLocalParticipant,
|
11
|
11
|
hiddenParticipantJoined,
|
12
|
12
|
hiddenParticipantLeft,
|
13
|
13
|
participantJoined,
|
14
|
14
|
participantLeft
|
15
|
|
-} from '../participants';
|
16
|
|
-import { toState } from '../redux';
|
17
|
|
-import {
|
18
|
|
- getBackendSafePath,
|
19
|
|
- getJitsiMeetGlobalNS,
|
20
|
|
- safeDecodeURIComponent
|
21
|
|
-} from '../util';
|
|
15
|
+} from '../participants/actions';
|
|
16
|
+import { getLocalParticipant } from '../participants/functions';
|
|
17
|
+import { toState } from '../redux/functions';
|
|
18
|
+import { getJitsiMeetGlobalNS } from '../util/helpers';
|
|
19
|
+import { getBackendSafePath, safeDecodeURIComponent } from '../util/uri';
|
22
|
20
|
|
|
21
|
+// @ts-ignore
|
23
|
22
|
import { setObfuscatedRoom } from './actions';
|
24
|
23
|
import {
|
25
|
24
|
AVATAR_URL_COMMAND,
|
|
@@ -27,22 +26,23 @@ import {
|
27
|
26
|
JITSI_CONFERENCE_URL_KEY
|
28
|
27
|
} from './constants';
|
29
|
28
|
import logger from './logger';
|
|
29
|
+import { IJitsiConference } from './reducer';
|
30
|
30
|
|
31
|
31
|
/**
|
32
|
32
|
* Returns root conference state.
|
33
|
33
|
*
|
34
|
|
- * @param {Object} state - Global state.
|
|
34
|
+ * @param {IState} state - Global state.
|
35
|
35
|
* @returns {Object} Conference state.
|
36
|
36
|
*/
|
37
|
|
-export const getConferenceState = (state: Object) => state['features/base/conference'];
|
|
37
|
+export const getConferenceState = (state: IState) => state['features/base/conference'];
|
38
|
38
|
|
39
|
39
|
/**
|
40
|
40
|
* Is the conference joined or not.
|
41
|
41
|
*
|
42
|
|
- * @param {Object} state - Global state.
|
|
42
|
+ * @param {IState} state - Global state.
|
43
|
43
|
* @returns {boolean}
|
44
|
44
|
*/
|
45
|
|
-export const getIsConferenceJoined = (state: Object) => Boolean(getConferenceState(state).conference);
|
|
45
|
+export const getIsConferenceJoined = (state: IState) => Boolean(getConferenceState(state).conference);
|
46
|
46
|
|
47
|
47
|
/**
|
48
|
48
|
* Attach a set of local tracks to a conference.
|
|
@@ -53,7 +53,7 @@ export const getIsConferenceJoined = (state: Object) => Boolean(getConferenceSta
|
53
|
53
|
* @returns {Promise}
|
54
|
54
|
*/
|
55
|
55
|
export function _addLocalTracksToConference(
|
56
|
|
- conference: { addTrack: Function, getLocalTracks: Function },
|
|
56
|
+ conference: IJitsiConference,
|
57
|
57
|
localTracks: Array<Object>) {
|
58
|
58
|
const conferenceLocalTracks = conference.getLocalTracks();
|
59
|
59
|
const promises = [];
|
|
@@ -63,7 +63,7 @@ export function _addLocalTracksToConference(
|
63
|
63
|
// adding one and the same video track multiple times.
|
64
|
64
|
if (conferenceLocalTracks.indexOf(track) === -1) {
|
65
|
65
|
promises.push(
|
66
|
|
- conference.addTrack(track).catch(err => {
|
|
66
|
+ conference.addTrack(track).catch((err: Error) => {
|
67
|
67
|
_reportError(
|
68
|
68
|
'Failed to add local track to conference',
|
69
|
69
|
err);
|
|
@@ -86,16 +86,16 @@ export function _addLocalTracksToConference(
|
86
|
86
|
* @returns {void}
|
87
|
87
|
*/
|
88
|
88
|
export function commonUserJoinedHandling(
|
89
|
|
- { dispatch }: Object,
|
90
|
|
- conference: Object,
|
91
|
|
- user: Object) {
|
|
89
|
+ { dispatch }: IStore,
|
|
90
|
+ conference: IJitsiConference,
|
|
91
|
+ user: any) {
|
92
|
92
|
const id = user.getId();
|
93
|
93
|
const displayName = user.getDisplayName();
|
94
|
94
|
|
95
|
95
|
if (user.isHidden()) {
|
96
|
96
|
dispatch(hiddenParticipantJoined(id, displayName));
|
97
|
97
|
} else {
|
98
|
|
- const isReplacing = user.isReplacing && user.isReplacing();
|
|
98
|
+ const isReplacing = user?.isReplacing();
|
99
|
99
|
|
100
|
100
|
dispatch(participantJoined({
|
101
|
101
|
botType: user.getBotType(),
|
|
@@ -122,15 +122,15 @@ export function commonUserJoinedHandling(
|
122
|
122
|
* @returns {void}
|
123
|
123
|
*/
|
124
|
124
|
export function commonUserLeftHandling(
|
125
|
|
- { dispatch }: Object,
|
126
|
|
- conference: Object,
|
127
|
|
- user: Object) {
|
|
125
|
+ { dispatch }: IStore,
|
|
126
|
+ conference: IJitsiConference,
|
|
127
|
+ user: any) {
|
128
|
128
|
const id = user.getId();
|
129
|
129
|
|
130
|
130
|
if (user.isHidden()) {
|
131
|
131
|
dispatch(hiddenParticipantLeft(id));
|
132
|
132
|
} else {
|
133
|
|
- const isReplaced = user.isReplaced && user.isReplaced();
|
|
133
|
+ const isReplaced = user.isReplaced?.();
|
134
|
134
|
|
135
|
135
|
dispatch(participantLeft(id, conference, { isReplaced }));
|
136
|
136
|
}
|
|
@@ -140,7 +140,7 @@ export function commonUserLeftHandling(
|
140
|
140
|
* Evaluates a specific predicate for each {@link JitsiConference} known to the
|
141
|
141
|
* redux state features/base/conference while it returns {@code true}.
|
142
|
142
|
*
|
143
|
|
- * @param {Function | Object} stateful - The redux store, state, or
|
|
143
|
+ * @param {IStateful} stateful - The redux store, state, or
|
144
|
144
|
* {@code getState} function.
|
145
|
145
|
* @param {Function} predicate - The predicate to evaluate for each
|
146
|
146
|
* {@code JitsiConference} know to the redux state features/base/conference
|
|
@@ -150,8 +150,8 @@ export function commonUserLeftHandling(
|
150
|
150
|
* features/base/conference.
|
151
|
151
|
*/
|
152
|
152
|
export function forEachConference(
|
153
|
|
- stateful: Function | Object,
|
154
|
|
- predicate: (Object, URL) => boolean) {
|
|
153
|
+ stateful: IStateful,
|
|
154
|
+ predicate: (a: any, b: URL) => boolean) {
|
155
|
155
|
const state = getConferenceState(toState(stateful));
|
156
|
156
|
|
157
|
157
|
for (const v of Object.values(state)) {
|
|
@@ -178,48 +178,48 @@ export function forEachConference(
|
178
|
178
|
/**
|
179
|
179
|
* Returns the display name of the conference.
|
180
|
180
|
*
|
181
|
|
- * @param {Function | Object} stateful - Reference that can be resolved to Redux
|
|
181
|
+ * @param {IStateful} stateful - Reference that can be resolved to Redux
|
182
|
182
|
* state with the {@code toState} function.
|
183
|
183
|
* @returns {string}
|
184
|
184
|
*/
|
185
|
|
-export function getConferenceName(stateful: Function | Object): string {
|
|
185
|
+export function getConferenceName(stateful: IStateful): string {
|
186
|
186
|
const state = toState(stateful);
|
187
|
187
|
const { callee } = state['features/base/jwt'];
|
188
|
188
|
const { callDisplayName } = state['features/base/config'];
|
189
|
189
|
const { localSubject, room, subject } = getConferenceState(state);
|
190
|
190
|
|
191
|
|
- return localSubject
|
|
191
|
+ return (localSubject
|
192
|
192
|
|| subject
|
193
|
193
|
|| callDisplayName
|
194
|
|
- || (callee && callee.name)
|
195
|
|
- || (room && safeStartCase(safeDecodeURIComponent(room)));
|
|
194
|
+ || callee?.name
|
|
195
|
+ || (room && safeStartCase(safeDecodeURIComponent(room)))) ?? '';
|
196
|
196
|
}
|
197
|
197
|
|
198
|
198
|
/**
|
199
|
199
|
* Returns the name of the conference formatted for the title.
|
200
|
200
|
*
|
201
|
|
- * @param {Function | Object} stateful - Reference that can be resolved to Redux state with the {@code toState}
|
|
201
|
+ * @param {IStateful} stateful - Reference that can be resolved to Redux state with the {@code toState}
|
202
|
202
|
* function.
|
203
|
203
|
* @returns {string} - The name of the conference formatted for the title.
|
204
|
204
|
*/
|
205
|
|
-export function getConferenceNameForTitle(stateful: Function | Object) {
|
206
|
|
- return safeStartCase(safeDecodeURIComponent(getConferenceState(toState(stateful)).room));
|
|
205
|
+export function getConferenceNameForTitle(stateful: IStateful) {
|
|
206
|
+ return safeStartCase(safeDecodeURIComponent(getConferenceState(toState(stateful)).room ?? ''));
|
207
|
207
|
}
|
208
|
208
|
|
209
|
209
|
/**
|
210
|
210
|
* Returns an object aggregating the conference options.
|
211
|
211
|
*
|
212
|
|
- * @param {Object|Function} stateful - The redux store state.
|
|
212
|
+ * @param {IStateful} stateful - The redux store state.
|
213
|
213
|
* @returns {Object} - Options object.
|
214
|
214
|
*/
|
215
|
|
-export function getConferenceOptions(stateful: Function | Object) {
|
|
215
|
+export function getConferenceOptions(stateful: IStateful) {
|
216
|
216
|
const state = toState(stateful);
|
217
|
217
|
|
218
|
218
|
const config = state['features/base/config'];
|
219
|
219
|
const { locationURL } = state['features/base/connection'];
|
220
|
220
|
const { tenant } = state['features/base/jwt'];
|
221
|
|
- const { email, name: nick } = getLocalParticipant(state);
|
222
|
|
- const options = { ...config };
|
|
221
|
+ const { email, name: nick } = getLocalParticipant(state) ?? {};
|
|
222
|
+ const options: any = { ...config };
|
223
|
223
|
|
224
|
224
|
if (tenant) {
|
225
|
225
|
options.siteID = tenant;
|
|
@@ -257,11 +257,11 @@ export function getConferenceOptions(stateful: Function | Object) {
|
257
|
257
|
/**
|
258
|
258
|
* Returns the UTC timestamp when the first participant joined the conference.
|
259
|
259
|
*
|
260
|
|
-* @param {Function | Object} stateful - Reference that can be resolved to Redux
|
|
260
|
+* @param {IStateful} stateful - Reference that can be resolved to Redux
|
261
|
261
|
* state with the {@code toState} function.
|
262
|
262
|
* @returns {number}
|
263
|
263
|
*/
|
264
|
|
-export function getConferenceTimestamp(stateful: Function | Object): number {
|
|
264
|
+export function getConferenceTimestamp(stateful: IStateful) {
|
265
|
265
|
const state = toState(stateful);
|
266
|
266
|
const { conferenceTimestamp } = getConferenceState(state);
|
267
|
267
|
|
|
@@ -274,11 +274,11 @@ export function getConferenceTimestamp(stateful: Function | Object): number {
|
274
|
274
|
* {@code conference} state of the feature base/conference which is not joining
|
275
|
275
|
* but may be leaving already.
|
276
|
276
|
*
|
277
|
|
- * @param {Function|Object} stateful - The redux store, state, or
|
|
277
|
+ * @param {IStateful} stateful - The redux store, state, or
|
278
|
278
|
* {@code getState} function.
|
279
|
279
|
* @returns {JitsiConference|undefined}
|
280
|
280
|
*/
|
281
|
|
-export function getCurrentConference(stateful: Function | Object) {
|
|
281
|
+export function getCurrentConference(stateful: IStateful): any {
|
282
|
282
|
const { conference, joining, leaving, membersOnly, passwordRequired }
|
283
|
283
|
= getConferenceState(toState(stateful));
|
284
|
284
|
|
|
@@ -293,25 +293,29 @@ export function getCurrentConference(stateful: Function | Object) {
|
293
|
293
|
/**
|
294
|
294
|
* Returns the stored room name.
|
295
|
295
|
*
|
296
|
|
- * @param {Object} state - The current state of the app.
|
|
296
|
+ * @param {IState} state - The current state of the app.
|
297
|
297
|
* @returns {string}
|
298
|
298
|
*/
|
299
|
|
-export function getRoomName(state: Object): string {
|
|
299
|
+export function getRoomName(state: IState) {
|
300
|
300
|
return getConferenceState(state).room;
|
301
|
301
|
}
|
302
|
302
|
|
303
|
303
|
/**
|
304
|
304
|
* Get an obfuscated room name or create and persist it if it doesn't exists.
|
305
|
305
|
*
|
306
|
|
- * @param {Object} state - The current state of the app.
|
|
306
|
+ * @param {IState} state - The current state of the app.
|
307
|
307
|
* @param {Function} dispatch - The Redux dispatch function.
|
308
|
308
|
* @returns {string} - Obfuscated room name.
|
309
|
309
|
*/
|
310
|
|
-export function getOrCreateObfuscatedRoomName(state: Object, dispatch: Function) {
|
|
310
|
+export function getOrCreateObfuscatedRoomName(state: IState, dispatch: IStore['dispatch']) {
|
311
|
311
|
let { obfuscatedRoom } = getConferenceState(state);
|
312
|
312
|
const { obfuscatedRoomSource } = getConferenceState(state);
|
313
|
313
|
const room = getRoomName(state);
|
314
|
314
|
|
|
315
|
+ if (!room) {
|
|
316
|
+ return;
|
|
317
|
+ }
|
|
318
|
+
|
315
|
319
|
// On native mobile the store doesn't clear when joining a new conference so we might have the obfuscatedRoom
|
316
|
320
|
// stored even though a different room was joined.
|
317
|
321
|
// Check if the obfuscatedRoom was already computed for the current room.
|
|
@@ -327,11 +331,11 @@ export function getOrCreateObfuscatedRoomName(state: Object, dispatch: Function)
|
327
|
331
|
* Analytics may require an obfuscated room name, this functions decides based on a config if the normal or
|
328
|
332
|
* obfuscated room name should be returned.
|
329
|
333
|
*
|
330
|
|
- * @param {Object} state - The current state of the app.
|
|
334
|
+ * @param {IState} state - The current state of the app.
|
331
|
335
|
* @param {Function} dispatch - The Redux dispatch function.
|
332
|
336
|
* @returns {string} - Analytics room name.
|
333
|
337
|
*/
|
334
|
|
-export function getAnalyticsRoomName(state: Object, dispatch: Function) {
|
|
338
|
+export function getAnalyticsRoomName(state: IState, dispatch: IStore['dispatch']) {
|
335
|
339
|
const { analysis: { obfuscateRoomName = false } = {} } = state['features/base/config'];
|
336
|
340
|
|
337
|
341
|
if (obfuscateRoomName) {
|
|
@@ -365,7 +369,7 @@ function getWiFiStatsMethod() {
|
365
|
369
|
* @protected
|
366
|
370
|
* @returns {void}
|
367
|
371
|
*/
|
368
|
|
-export function _handleParticipantError(err: { message: ?string }) {
|
|
372
|
+export function _handleParticipantError(err: Error) {
|
369
|
373
|
// XXX DataChannels are initialized at some later point when the conference
|
370
|
374
|
// has multiple participants, but code that pins or selects a participant
|
371
|
375
|
// might be executed before. So here we're swallowing a particular error.
|
|
@@ -384,7 +388,7 @@ export function _handleParticipantError(err: { message: ?string }) {
|
384
|
388
|
* @returns {boolean} If the specified room name is valid, then true; otherwise,
|
385
|
389
|
* false.
|
386
|
390
|
*/
|
387
|
|
-export function isRoomValid(room: ?string) {
|
|
391
|
+export function isRoomValid(room?: string) {
|
388
|
392
|
return typeof room === 'string' && room !== '';
|
389
|
393
|
}
|
390
|
394
|
|
|
@@ -397,11 +401,11 @@ export function isRoomValid(room: ?string) {
|
397
|
401
|
* @returns {Promise}
|
398
|
402
|
*/
|
399
|
403
|
export function _removeLocalTracksFromConference(
|
400
|
|
- conference: { removeTrack: Function },
|
|
404
|
+ conference: IJitsiConference,
|
401
|
405
|
localTracks: Array<Object>) {
|
402
|
406
|
return Promise.all(localTracks.map(track =>
|
403
|
407
|
conference.removeTrack(track)
|
404
|
|
- .catch(err => {
|
|
408
|
+ .catch((err: Error) => {
|
405
|
409
|
// Local track might be already disposed by direct
|
406
|
410
|
// JitsiTrack#dispose() call. So we should ignore this error
|
407
|
411
|
// here.
|
|
@@ -425,7 +429,7 @@ export function _removeLocalTracksFromConference(
|
425
|
429
|
* @private
|
426
|
430
|
* @returns {void}
|
427
|
431
|
*/
|
428
|
|
-function _reportError(msg, err) {
|
|
432
|
+function _reportError(msg: string, err: Error) {
|
429
|
433
|
// TODO This is a good point to call some global error handler when we have
|
430
|
434
|
// one.
|
431
|
435
|
logger.error(msg, err);
|
|
@@ -443,17 +447,14 @@ function _reportError(msg, err) {
|
443
|
447
|
* @returns {void}
|
444
|
448
|
*/
|
445
|
449
|
export function sendLocalParticipant(
|
446
|
|
- stateful: Function | Object,
|
447
|
|
- conference: {
|
448
|
|
- sendCommand: Function,
|
449
|
|
- setDisplayName: Function,
|
450
|
|
- setLocalParticipantProperty: Function }) {
|
|
450
|
+ stateful: IStateful,
|
|
451
|
+ conference: IJitsiConference) {
|
451
|
452
|
const {
|
452
|
453
|
avatarURL,
|
453
|
454
|
email,
|
454
|
455
|
features,
|
455
|
456
|
name
|
456
|
|
- } = getLocalParticipant(stateful);
|
|
457
|
+ } = getLocalParticipant(stateful) ?? {};
|
457
|
458
|
|
458
|
459
|
avatarURL && conference.sendCommand(AVATAR_URL_COMMAND, {
|
459
|
460
|
value: avatarURL
|