@webex/plugin-meetings 3.9.0-webinar5k.1 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/constants.js +24 -0
- package/dist/constants.js.map +1 -1
- package/dist/controls-options-manager/index.js +22 -5
- package/dist/controls-options-manager/index.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/interceptors/index.js +7 -0
- package/dist/interceptors/index.js.map +1 -1
- package/dist/interceptors/locusRouteToken.js +116 -0
- package/dist/interceptors/locusRouteToken.js.map +1 -0
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/controlsUtils.js +11 -2
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/index.js +76 -322
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +4 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/media/properties.js +53 -5
- package/dist/media/properties.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js +14 -0
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +467 -277
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/request.js +177 -14
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/type.js +7 -0
- package/dist/meeting/type.js.map +1 -0
- package/dist/meeting/util.js +100 -3
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +29 -21
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +20 -16
- package/dist/meetings/index.js.map +1 -1
- package/dist/member/index.js +9 -0
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js +10 -0
- package/dist/member/util.js.map +1 -1
- package/dist/members/index.js +10 -7
- package/dist/members/index.js.map +1 -1
- package/dist/members/util.js +7 -2
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/constants.js +2 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/multistream/mediaRequestManager.js +1 -1
- package/dist/multistream/mediaRequestManager.js.map +1 -1
- package/dist/multistream/remoteMedia.js +34 -5
- package/dist/multistream/remoteMedia.js.map +1 -1
- package/dist/multistream/remoteMediaGroup.js +42 -2
- package/dist/multistream/remoteMediaGroup.js.map +1 -1
- package/dist/reachability/index.js +3 -3
- package/dist/reachability/index.js.map +1 -1
- package/dist/types/constants.d.ts +23 -0
- package/dist/types/controls-options-manager/index.d.ts +9 -1
- package/dist/types/interceptors/index.d.ts +2 -1
- package/dist/types/interceptors/locusRouteToken.d.ts +38 -0
- package/dist/types/locus-info/index.d.ts +9 -54
- package/dist/types/media/properties.d.ts +21 -0
- package/dist/types/meeting/in-meeting-actions.d.ts +14 -0
- package/dist/types/meeting/index.d.ts +64 -29
- package/dist/types/meeting/request.d.ts +42 -0
- package/dist/types/meeting/type.d.ts +9 -0
- package/dist/types/meeting/util.d.ts +13 -0
- package/dist/types/meeting-info/meeting-info-v2.d.ts +6 -3
- package/dist/types/meetings/index.d.ts +3 -1
- package/dist/types/member/index.d.ts +1 -0
- package/dist/types/member/util.d.ts +5 -0
- package/dist/types/members/index.d.ts +12 -11
- package/dist/types/members/util.d.ts +8 -4
- package/dist/types/metrics/constants.d.ts +1 -0
- package/dist/types/multistream/remoteMedia.d.ts +20 -1
- package/dist/types/multistream/remoteMediaGroup.d.ts +11 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +25 -27
- package/src/constants.ts +26 -2
- package/src/controls-options-manager/index.ts +26 -5
- package/src/index.ts +2 -1
- package/src/interceptors/index.ts +2 -1
- package/src/interceptors/locusRouteToken.ts +80 -0
- package/src/locus-info/controlsUtils.ts +18 -0
- package/src/locus-info/index.ts +69 -357
- package/src/locus-info/parser.ts +5 -1
- package/src/media/properties.ts +43 -0
- package/src/meeting/in-meeting-actions.ts +29 -0
- package/src/meeting/index.ts +296 -87
- package/src/meeting/request.ts +141 -0
- package/src/meeting/type.ts +9 -0
- package/src/meeting/util.ts +107 -3
- package/src/meeting-info/meeting-info-v2.ts +24 -5
- package/src/meetings/index.ts +15 -22
- package/src/member/index.ts +10 -0
- package/src/member/util.ts +14 -0
- package/src/members/index.ts +20 -10
- package/src/members/util.ts +20 -3
- package/src/metrics/constants.ts +1 -0
- package/src/multistream/mediaRequestManager.ts +7 -7
- package/src/multistream/remoteMedia.ts +34 -4
- package/src/multistream/remoteMediaGroup.ts +37 -2
- package/src/reachability/index.ts +3 -3
- package/test/unit/spec/common/browser-detection.js +0 -24
- package/test/unit/spec/controls-options-manager/index.js +47 -0
- package/test/unit/spec/fixture/locus.js +1 -0
- package/test/unit/spec/interceptors/locusRouteToken.ts +87 -0
- package/test/unit/spec/locus-info/index.js +80 -361
- package/test/unit/spec/locus-info/parser.js +3 -2
- package/test/unit/spec/media/properties.ts +137 -0
- package/test/unit/spec/meeting/in-meeting-actions.ts +14 -0
- package/test/unit/spec/meeting/index.js +637 -53
- package/test/unit/spec/meeting/muteState.js +32 -6
- package/test/unit/spec/meeting/request.js +21 -0
- package/test/unit/spec/meeting/utils.js +171 -18
- package/test/unit/spec/meeting-info/meetinginfov2.js +8 -3
- package/test/unit/spec/meetings/index.js +12 -5
- package/test/unit/spec/member/util.js +24 -0
- package/test/unit/spec/members/collection.js +120 -0
- package/test/unit/spec/members/index.js +107 -2
- package/test/unit/spec/members/request.js +55 -0
- package/test/unit/spec/members/utils.js +116 -14
- package/test/unit/spec/multistream/mediaRequestManager.ts +19 -6
- package/test/unit/spec/multistream/remoteMedia.ts +66 -2
- package/test/unit/spec/reachability/index.ts +158 -3
- package/test/unit/spec/roap/turnDiscovery.ts +3 -3
- package/dist/hashTree/constants.js +0 -23
- package/dist/hashTree/constants.js.map +0 -1
- package/dist/hashTree/hashTree.js +0 -516
- package/dist/hashTree/hashTree.js.map +0 -1
- package/dist/hashTree/hashTreeParser.js +0 -521
- package/dist/hashTree/hashTreeParser.js.map +0 -1
- package/dist/types/hashTree/constants.d.ts +0 -8
- package/dist/types/hashTree/hashTree.d.ts +0 -128
- package/dist/types/hashTree/hashTreeParser.d.ts +0 -152
- package/src/hashTree/constants.ts +0 -12
- package/src/hashTree/hashTree.ts +0 -460
- package/src/hashTree/hashTreeParser.ts +0 -556
- package/test/unit/spec/hashTree/hashTree.ts +0 -394
- package/test/unit/spec/hashTree/hashTreeParser.ts +0 -156
package/src/members/util.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from '../constants';
|
|
15
15
|
|
|
16
16
|
import {RoleAssignmentOptions, RoleAssignmentRequest, ServerRoleShape} from './types';
|
|
17
|
+
import {Invitee} from '../meeting/type';
|
|
17
18
|
|
|
18
19
|
const MembersUtil = {
|
|
19
20
|
/**
|
|
@@ -105,7 +106,7 @@ const MembersUtil = {
|
|
|
105
106
|
return requestParams;
|
|
106
107
|
},
|
|
107
108
|
|
|
108
|
-
isInvalidInvitee: (invitee) => {
|
|
109
|
+
isInvalidInvitee: (invitee: Invitee) => {
|
|
109
110
|
if (!(invitee && (invitee.email || invitee.emailAddress || invitee.phoneNumber))) {
|
|
110
111
|
return true;
|
|
111
112
|
}
|
|
@@ -189,13 +190,21 @@ const MembersUtil = {
|
|
|
189
190
|
* @param {String} requestingParticipantId id of the participant who is sending request (optional)
|
|
190
191
|
* @param {String} alias alias name
|
|
191
192
|
* @param {String} locusUrl url
|
|
193
|
+
* @param {String} suffix optional suffix
|
|
192
194
|
* @returns {Object} consists of {memberID: string, requestingParticipantId: string, alias: string, locusUrl: string}
|
|
193
195
|
*/
|
|
194
|
-
generateEditDisplayNameMemberOptions: (
|
|
196
|
+
generateEditDisplayNameMemberOptions: (
|
|
195
197
|
memberId,
|
|
196
198
|
requestingParticipantId,
|
|
197
199
|
alias,
|
|
198
200
|
locusUrl,
|
|
201
|
+
suffix
|
|
202
|
+
) => ({
|
|
203
|
+
memberId,
|
|
204
|
+
requestingParticipantId,
|
|
205
|
+
alias,
|
|
206
|
+
locusUrl,
|
|
207
|
+
suffix,
|
|
199
208
|
}),
|
|
200
209
|
|
|
201
210
|
getMuteMemberRequestParams: (options) => {
|
|
@@ -300,10 +309,18 @@ const MembersUtil = {
|
|
|
300
309
|
* @returns {Object} request parameters (method, uri, body) needed to make a editDisplayName request
|
|
301
310
|
*/
|
|
302
311
|
editDisplayNameMemberRequestParams: (options) => {
|
|
303
|
-
const body
|
|
312
|
+
const body: {
|
|
313
|
+
aliasValue: string;
|
|
314
|
+
requestingParticipantId: string;
|
|
315
|
+
suffixValue?: string;
|
|
316
|
+
} = {
|
|
304
317
|
aliasValue: options.alias,
|
|
305
318
|
requestingParticipantId: options.requestingParticipantId,
|
|
306
319
|
};
|
|
320
|
+
|
|
321
|
+
if (options.suffix !== undefined) {
|
|
322
|
+
body.suffixValue = options.suffix;
|
|
323
|
+
}
|
|
307
324
|
const uri = `${options.locusUrl}/${PARTICIPANT}/${options.memberId}/${ALIAS}`;
|
|
308
325
|
|
|
309
326
|
return {
|
package/src/metrics/constants.ts
CHANGED
|
@@ -86,6 +86,7 @@ const BEHAVIORAL_METRICS = {
|
|
|
86
86
|
VERIFY_REGISTRATION_ID_SUCCESS: 'js_sdk_verify_registrationId_success',
|
|
87
87
|
VERIFY_REGISTRATION_ID_ERROR: 'js_sdk_verify_registrationId_error',
|
|
88
88
|
JOIN_FORBIDDEN_ERROR: 'js_sdk_join_forbidden_error',
|
|
89
|
+
MEDIA_ISSUE_DETECTED: 'js_sdk_media_issue_detected',
|
|
89
90
|
};
|
|
90
91
|
|
|
91
92
|
export {BEHAVIORAL_METRICS as default};
|
|
@@ -15,7 +15,7 @@ import {cloneDeepWith, debounce, isEmpty} from 'lodash';
|
|
|
15
15
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
16
16
|
|
|
17
17
|
import {ReceiveSlot, ReceiveSlotEvents} from './receiveSlot';
|
|
18
|
-
import {
|
|
18
|
+
import {MAX_FS_VALUES} from './remoteMedia';
|
|
19
19
|
|
|
20
20
|
export interface ActiveSpeakerPolicyInfo {
|
|
21
21
|
policy: 'active-speaker';
|
|
@@ -123,12 +123,12 @@ export class MediaRequestManager {
|
|
|
123
123
|
|
|
124
124
|
private getDegradedClientRequests(clientRequests: ClientRequestsMap) {
|
|
125
125
|
const maxFsLimits = [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
126
|
+
MAX_FS_VALUES['1080p'],
|
|
127
|
+
MAX_FS_VALUES['720p'],
|
|
128
|
+
MAX_FS_VALUES['540p'],
|
|
129
|
+
MAX_FS_VALUES['360p'],
|
|
130
|
+
MAX_FS_VALUES['180p'],
|
|
131
|
+
MAX_FS_VALUES['90p'],
|
|
132
132
|
];
|
|
133
133
|
|
|
134
134
|
// reduce max-fs until total macroblocks is below limit
|
|
@@ -19,17 +19,18 @@ export type RemoteVideoResolution =
|
|
|
19
19
|
| 'large' // 1080p or less
|
|
20
20
|
| 'best'; // highest possible resolution
|
|
21
21
|
|
|
22
|
-
const MAX_FS_VALUES = {
|
|
22
|
+
export const MAX_FS_VALUES = {
|
|
23
23
|
'90p': 60,
|
|
24
24
|
'180p': 240,
|
|
25
25
|
'360p': 920,
|
|
26
|
+
'540p': 2040,
|
|
26
27
|
'720p': 3600,
|
|
27
28
|
'1080p': 8192,
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* Converts pane size into h264 maxFs
|
|
32
|
-
* @param {
|
|
33
|
+
* @param {RemoteVideoResolution} paneSize
|
|
33
34
|
* @returns {number}
|
|
34
35
|
*/
|
|
35
36
|
export function getMaxFs(paneSize: RemoteVideoResolution): number {
|
|
@@ -89,6 +90,13 @@ export class RemoteMedia extends EventsScope {
|
|
|
89
90
|
|
|
90
91
|
public readonly id: RemoteMediaId;
|
|
91
92
|
|
|
93
|
+
/**
|
|
94
|
+
* The max frame size of the media request, used for logging and media requests.
|
|
95
|
+
* Set by setSizeHint() based on video element dimensions.
|
|
96
|
+
* When > 0, this value takes precedence over options.resolution in sendMediaRequest().
|
|
97
|
+
*/
|
|
98
|
+
private maxFrameSize = 0;
|
|
99
|
+
|
|
92
100
|
/**
|
|
93
101
|
* Constructs RemoteMedia instance
|
|
94
102
|
*
|
|
@@ -136,15 +144,34 @@ export class RemoteMedia extends EventsScope {
|
|
|
136
144
|
fs = MAX_FS_VALUES['180p'];
|
|
137
145
|
} else if (height < getThresholdHeight(360)) {
|
|
138
146
|
fs = MAX_FS_VALUES['360p'];
|
|
147
|
+
} else if (height < getThresholdHeight(540)) {
|
|
148
|
+
fs = MAX_FS_VALUES['540p'];
|
|
139
149
|
} else if (height <= 720) {
|
|
140
150
|
fs = MAX_FS_VALUES['720p'];
|
|
141
151
|
} else {
|
|
142
152
|
fs = MAX_FS_VALUES['1080p'];
|
|
143
153
|
}
|
|
144
154
|
|
|
155
|
+
this.maxFrameSize = fs;
|
|
145
156
|
this.receiveSlot?.setMaxFs(fs);
|
|
146
157
|
}
|
|
147
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Get the current effective maxFs value that would be used in media requests
|
|
161
|
+
* @returns {number | undefined} The maxFs value, or undefined if no constraints
|
|
162
|
+
*/
|
|
163
|
+
public getEffectiveMaxFs(): number | undefined {
|
|
164
|
+
if (this.maxFrameSize > 0) {
|
|
165
|
+
return this.maxFrameSize;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (this.options.resolution) {
|
|
169
|
+
return getMaxFs(this.options.resolution);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
|
|
148
175
|
/**
|
|
149
176
|
* Invalidates the remote media by clearing the reference to a receive slot and
|
|
150
177
|
* cancelling the media request.
|
|
@@ -185,6 +212,9 @@ export class RemoteMedia extends EventsScope {
|
|
|
185
212
|
throw new Error('sendMediaRequest() called on an invalidated RemoteMedia instance');
|
|
186
213
|
}
|
|
187
214
|
|
|
215
|
+
// Use maxFrameSize from setSizeHint if available, otherwise fallback to options.resolution
|
|
216
|
+
const maxFs = this.getEffectiveMaxFs();
|
|
217
|
+
|
|
188
218
|
this.mediaRequestId = this.mediaRequestManager.addRequest(
|
|
189
219
|
{
|
|
190
220
|
policyInfo: {
|
|
@@ -192,9 +222,9 @@ export class RemoteMedia extends EventsScope {
|
|
|
192
222
|
csi,
|
|
193
223
|
},
|
|
194
224
|
receiveSlots: [this.receiveSlot],
|
|
195
|
-
codecInfo:
|
|
225
|
+
codecInfo: maxFs && {
|
|
196
226
|
codec: 'h264',
|
|
197
|
-
maxFs
|
|
227
|
+
maxFs,
|
|
198
228
|
},
|
|
199
229
|
},
|
|
200
230
|
commit
|
|
@@ -215,6 +215,9 @@ export class RemoteMediaGroup {
|
|
|
215
215
|
private sendActiveSpeakerMediaRequest(commit: boolean) {
|
|
216
216
|
this.cancelActiveSpeakerMediaRequest(false);
|
|
217
217
|
|
|
218
|
+
// Calculate the effective maxFs based on all unpinned RemoteMedia instances
|
|
219
|
+
const effectiveMaxFs = this.getEffectiveMaxFsForActiveSpeaker();
|
|
220
|
+
|
|
218
221
|
this.mediaRequestId = this.mediaRequestManager.addRequest(
|
|
219
222
|
{
|
|
220
223
|
policyInfo: {
|
|
@@ -230,9 +233,9 @@ export class RemoteMediaGroup {
|
|
|
230
233
|
receiveSlots: this.unpinnedRemoteMedia.map((remoteMedia) =>
|
|
231
234
|
remoteMedia.getUnderlyingReceiveSlot()
|
|
232
235
|
) as ReceiveSlot[],
|
|
233
|
-
codecInfo:
|
|
236
|
+
codecInfo: effectiveMaxFs && {
|
|
234
237
|
codec: 'h264',
|
|
235
|
-
maxFs:
|
|
238
|
+
maxFs: effectiveMaxFs,
|
|
236
239
|
},
|
|
237
240
|
},
|
|
238
241
|
commit
|
|
@@ -300,4 +303,36 @@ export class RemoteMediaGroup {
|
|
|
300
303
|
this.unpinnedRemoteMedia.includes(remoteMedia) || this.pinnedRemoteMedia.includes(remoteMedia)
|
|
301
304
|
);
|
|
302
305
|
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Calculate the effective maxFs for the active speaker media request based on unpinned RemoteMedia instances
|
|
309
|
+
* @returns {number | undefined} The calculated maxFs value, or undefined if no constraints
|
|
310
|
+
* @private
|
|
311
|
+
*/
|
|
312
|
+
private getEffectiveMaxFsForActiveSpeaker(): number | undefined {
|
|
313
|
+
// Get all effective maxFs values from unpinned RemoteMedia instances
|
|
314
|
+
const maxFsValues = this.unpinnedRemoteMedia
|
|
315
|
+
.map((remoteMedia) => remoteMedia.getEffectiveMaxFs())
|
|
316
|
+
.filter((maxFs) => maxFs !== undefined);
|
|
317
|
+
|
|
318
|
+
// Use the highest maxFs value to ensure we don't under-request resolution for any instance
|
|
319
|
+
if (maxFsValues.length > 0) {
|
|
320
|
+
return Math.max(...maxFsValues);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Fall back to group's resolution option
|
|
324
|
+
if (this.options.resolution) {
|
|
325
|
+
return getMaxFs(this.options.resolution);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Get the current effective maxFs that would be used for the active speaker media request
|
|
333
|
+
* @returns {number | undefined} The effective maxFs value
|
|
334
|
+
*/
|
|
335
|
+
public getEffectiveMaxFs(): number | undefined {
|
|
336
|
+
return this.getEffectiveMaxFsForActiveSpeaker();
|
|
337
|
+
}
|
|
303
338
|
}
|
|
@@ -923,10 +923,10 @@ export default class Reachability extends EventsScope {
|
|
|
923
923
|
|
|
924
924
|
// update expected results counters to include this cluster
|
|
925
925
|
this.expectedResultsCount[cluster.isVideoMesh ? 'videoMesh' : 'public'].udp +=
|
|
926
|
-
cluster.udp.length;
|
|
926
|
+
cluster.udp.length > 0 ? 1 : 0;
|
|
927
927
|
if (!cluster.isVideoMesh) {
|
|
928
|
-
this.expectedResultsCount.public.tcp += cluster.tcp.length;
|
|
929
|
-
this.expectedResultsCount.public.xtls += cluster.xtls.length;
|
|
928
|
+
this.expectedResultsCount.public.tcp += cluster.tcp.length > 0 ? 1 : 0;
|
|
929
|
+
this.expectedResultsCount.public.xtls += cluster.xtls.length > 0 ? 1 : 0;
|
|
930
930
|
}
|
|
931
931
|
});
|
|
932
932
|
|
|
@@ -18,16 +18,6 @@ const USER_AGENT_SAFARI_MAC =
|
|
|
18
18
|
const USER_AGENT_FIREFOX_MAC =
|
|
19
19
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) ' + 'Gecko/20100101 Firefox/87.0';
|
|
20
20
|
|
|
21
|
-
const mockDetectionObject = {
|
|
22
|
-
/* eslint-disable global-require */
|
|
23
|
-
getOSName: () => require('os').platform(),
|
|
24
|
-
getOSVersion: () => require('os').release(),
|
|
25
|
-
/* eslint-enable global-require */
|
|
26
|
-
getBrowserName: () => '',
|
|
27
|
-
getBrowserVersion: () => '',
|
|
28
|
-
isBrowser: () => false,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
21
|
describe('common/browser-detection', () => {
|
|
32
22
|
it('returns the correct browser name.', () => {
|
|
33
23
|
assert.equal(
|
|
@@ -102,18 +92,4 @@ describe('common/browser-detection', () => {
|
|
|
102
92
|
'This browser is NOT Firefox'
|
|
103
93
|
);
|
|
104
94
|
});
|
|
105
|
-
|
|
106
|
-
it('returns the mock object when there is no userAgent', () => {
|
|
107
|
-
Object.defineProperty(global.window.navigator, 'userAgent', {
|
|
108
|
-
get: () => undefined,
|
|
109
|
-
configurable: true,
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const {getBrowserName, getBrowserVersion, getOSName, getOSVersion} = BrowserDetection(null);
|
|
113
|
-
|
|
114
|
-
assert.equal(getBrowserName(), mockDetectionObject.getBrowserName());
|
|
115
|
-
assert.equal(getBrowserVersion(), mockDetectionObject.getBrowserVersion());
|
|
116
|
-
assert.equal(getOSName(), mockDetectionObject.getOSName());
|
|
117
|
-
assert.equal(getOSVersion(), mockDetectionObject.getOSVersion());
|
|
118
|
-
});
|
|
119
95
|
});
|
|
@@ -133,6 +133,7 @@ describe('plugin-meetings', () => {
|
|
|
133
133
|
|
|
134
134
|
manager.set({
|
|
135
135
|
locusUrl: 'test/id',
|
|
136
|
+
mainLocusUrl: '',
|
|
136
137
|
displayHints: [],
|
|
137
138
|
});
|
|
138
139
|
});
|
|
@@ -201,6 +202,38 @@ describe('plugin-meetings', () => {
|
|
|
201
202
|
Util.canUpdate = restorable;
|
|
202
203
|
});
|
|
203
204
|
});
|
|
205
|
+
|
|
206
|
+
it('should call request with mainLocusUrl and locusUrl as authorizingLocusUrl if mainLocusUrl is exist and not same with locusUrl', () => {
|
|
207
|
+
const restorable = Util.canUpdate;
|
|
208
|
+
Util.canUpdate = sinon.stub().returns(true);
|
|
209
|
+
manager.mainLocusUrl = 'test/main';
|
|
210
|
+
|
|
211
|
+
const audio = {scope: 'audio', properties: {a: 1, b: 2}};
|
|
212
|
+
const reactions = {scope: 'reactions', properties: {c: 3, d: 4}};
|
|
213
|
+
|
|
214
|
+
return manager.update(audio, reactions)
|
|
215
|
+
.then(() => {
|
|
216
|
+
assert.calledWith(request.request, {
|
|
217
|
+
uri: 'test/main/controls',
|
|
218
|
+
body: {
|
|
219
|
+
audio: audio.properties,
|
|
220
|
+
authorizingLocusUrl: 'test/id'
|
|
221
|
+
},
|
|
222
|
+
method: HTTP_VERBS.PATCH,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
assert.calledWith(request.request, {
|
|
226
|
+
uri: 'test/main/controls',
|
|
227
|
+
body: {
|
|
228
|
+
reactions: reactions.properties,
|
|
229
|
+
authorizingLocusUrl: 'test/id'
|
|
230
|
+
},
|
|
231
|
+
method: HTTP_VERBS.PATCH,
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
Util.canUpdate = restorable;
|
|
235
|
+
});
|
|
236
|
+
});
|
|
204
237
|
});
|
|
205
238
|
|
|
206
239
|
describe('Mute/Unmute All', () => {
|
|
@@ -214,6 +247,7 @@ describe('plugin-meetings', () => {
|
|
|
214
247
|
|
|
215
248
|
manager.set({
|
|
216
249
|
locusUrl: 'test/id',
|
|
250
|
+
mainLocusUrl: '',
|
|
217
251
|
displayHints: [],
|
|
218
252
|
})
|
|
219
253
|
});
|
|
@@ -305,6 +339,19 @@ describe('plugin-meetings', () => {
|
|
|
305
339
|
|
|
306
340
|
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
307
341
|
});
|
|
342
|
+
|
|
343
|
+
it('request with mainLocusUrl and make locusUrl as authorizingLocusUrl if mainLocusUrl is exist and not same with locusUrl', () => {
|
|
344
|
+
manager.setDisplayHints(['MUTE_ALL', 'DISABLE_HARD_MUTE', 'DISABLE_MUTE_ON_ENTRY']);
|
|
345
|
+
manager.mainLocusUrl = `test/main`;
|
|
346
|
+
|
|
347
|
+
const result = manager.setMuteAll(true, true, true, ['attendee']);
|
|
348
|
+
|
|
349
|
+
assert.calledWith(request.request, { uri: 'test/main/controls',
|
|
350
|
+
body: { audio: { muted: true, disallowUnmute: true, muteOnEntry: true, roles: ['attendee'] }, authorizingLocusUrl: 'test/id' },
|
|
351
|
+
method: HTTP_VERBS.PATCH});
|
|
352
|
+
|
|
353
|
+
assert.deepEqual(result, request.request.firstCall.returnValue);
|
|
354
|
+
});
|
|
308
355
|
});
|
|
309
356
|
});
|
|
310
357
|
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* eslint-disable camelcase */
|
|
6
|
+
import 'jsdom-global/register';
|
|
7
|
+
import {assert} from '@webex/test-helper-chai';
|
|
8
|
+
import MockWebex from '@webex/test-helper-mock-webex';
|
|
9
|
+
import {LocusRouteTokenInterceptor} from '@webex/plugin-meetings/src/interceptors';
|
|
10
|
+
import Meetings from '@webex/plugin-meetings';
|
|
11
|
+
|
|
12
|
+
const X_CISCO_PART_ROUTE_TOKEN = 'X-Cisco-Part-Route-Token';
|
|
13
|
+
|
|
14
|
+
describe('LocusRouteTokenInterceptor', () => {
|
|
15
|
+
let interceptor, webex;
|
|
16
|
+
const TEST_LOCUS_ID = '0f1eba56-91e2-2a11-9b2b-1e2da077f066';
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
webex = new MockWebex({
|
|
19
|
+
children: {
|
|
20
|
+
meetings: Meetings,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
interceptor = Reflect.apply(LocusRouteTokenInterceptor.create, webex, []);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('getLocusIdByRequestUrl should return locusId from url', () => {
|
|
27
|
+
const url = `https://locus-test.webex.com/locus/api/v1/loci/${TEST_LOCUS_ID}/foo`;
|
|
28
|
+
assert.equal(interceptor.getLocusIdByRequestUrl(url), TEST_LOCUS_ID);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('getLocusIdByRequestUrl should return undefined when no locusId in url', () => {
|
|
32
|
+
const url = 'https://locus-test.webex.com/locus/api/v1/foo';
|
|
33
|
+
assert.isUndefined(interceptor.getLocusIdByRequestUrl(url));
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('getLocusIdByRequestUrl should return undefined when url is undefined', () => {
|
|
37
|
+
assert.isUndefined(interceptor.getLocusIdByRequestUrl(undefined));
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('onResponse should store route token when header exists', async () => {
|
|
41
|
+
const response = {
|
|
42
|
+
headers: {
|
|
43
|
+
[X_CISCO_PART_ROUTE_TOKEN]: 'test-token',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const result = await interceptor.onResponse(
|
|
48
|
+
{
|
|
49
|
+
uri: `https://locus-test.webex.com/locus/api/v1/loci/${TEST_LOCUS_ID}/foo`,
|
|
50
|
+
},
|
|
51
|
+
response
|
|
52
|
+
);
|
|
53
|
+
assert.equal(result, response);
|
|
54
|
+
assert.equal(interceptor.getToken(TEST_LOCUS_ID), 'test-token');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('onResponse should not store token when header missing', async () => {
|
|
58
|
+
interceptor.updateToken(TEST_LOCUS_ID);
|
|
59
|
+
const response = {headers: {}};
|
|
60
|
+
|
|
61
|
+
await interceptor.onResponse({}, response);
|
|
62
|
+
assert.isUndefined(interceptor.getToken(TEST_LOCUS_ID));
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('onRequest should attach token to headers when token exists', async () => {
|
|
66
|
+
interceptor.updateToken(TEST_LOCUS_ID, 'abc123');
|
|
67
|
+
|
|
68
|
+
const options = {
|
|
69
|
+
headers: {},
|
|
70
|
+
uri: `https://locus-test.webex.com/locus/api/v1/loci/${TEST_LOCUS_ID}/foo`,
|
|
71
|
+
};
|
|
72
|
+
const result = await interceptor.onRequest(options);
|
|
73
|
+
assert.equal(result.headers[X_CISCO_PART_ROUTE_TOKEN], 'abc123');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('onRequest should not attach token if none is stored', async () => {
|
|
77
|
+
interceptor.updateToken(TEST_LOCUS_ID);
|
|
78
|
+
const options = {headers: {}};
|
|
79
|
+
const result = await interceptor.onRequest(options);
|
|
80
|
+
assert.isUndefined(result.headers[X_CISCO_PART_ROUTE_TOKEN]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('updateToken & getToken should work as pair', () => {
|
|
84
|
+
interceptor.updateToken(TEST_LOCUS_ID, 'abc456');
|
|
85
|
+
assert.equal(interceptor.getToken(TEST_LOCUS_ID), 'abc456');
|
|
86
|
+
});
|
|
87
|
+
});
|