@webex/plugin-meetings 3.0.0-beta.162 → 3.0.0-beta.164
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 +7 -3
- package/dist/breakouts/breakout.js.map +1 -1
- package/dist/breakouts/events.js +31 -29
- package/dist/breakouts/events.js.map +1 -1
- package/dist/breakouts/index.js +4 -2
- package/dist/breakouts/index.js.map +1 -1
- package/dist/constants.js +2 -4
- package/dist/constants.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +33 -17
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +699 -682
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/util.js +47 -25
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/index.js +48 -7
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +24 -10
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meetings/index.js +12 -9
- package/dist/meetings/index.js.map +1 -1
- package/dist/metrics/index.js +1 -487
- package/dist/metrics/index.js.map +1 -1
- package/dist/reconnection-manager/index.js +27 -17
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/request.js +20 -14
- package/dist/roap/request.js.map +1 -1
- package/dist/types/breakouts/events.d.ts +7 -1
- package/dist/types/constants.d.ts +0 -1
- package/dist/types/meeting/index.d.ts +31 -133
- package/dist/types/meeting-info/index.d.ts +6 -1
- package/dist/types/meetings/index.d.ts +1 -0
- package/dist/types/metrics/index.d.ts +4 -128
- package/package.json +19 -19
- package/src/breakouts/breakout.ts +10 -2
- package/src/breakouts/events.ts +51 -32
- package/src/breakouts/index.ts +9 -5
- package/src/constants.ts +0 -2
- package/src/locus-info/index.ts +35 -17
- package/src/meeting/index.ts +474 -536
- package/src/meeting/util.ts +42 -19
- package/src/meeting-info/index.ts +54 -8
- package/src/meeting-info/meeting-info-v2.ts +24 -9
- package/src/meetings/index.ts +11 -6
- package/src/metrics/index.ts +1 -506
- package/src/reconnection-manager/index.ts +27 -17
- package/src/roap/request.ts +21 -9
- package/test/unit/spec/breakouts/breakout.ts +4 -2
- package/test/unit/spec/breakouts/events.ts +24 -18
- package/test/unit/spec/locus-info/index.js +112 -0
- package/test/unit/spec/meeting/index.js +178 -145
- package/test/unit/spec/meeting/utils.js +93 -7
- package/test/unit/spec/meeting-info/index.js +181 -0
- package/test/unit/spec/meeting-info/meetinginfov2.js +68 -68
- package/test/unit/spec/meetings/index.js +35 -55
- package/test/unit/spec/metrics/index.js +1 -148
- package/test/unit/spec/reconnection-manager/index.js +51 -2
- package/test/unit/spec/roap/index.ts +8 -2
- package/test/unit/spec/roap/request.ts +43 -5
- package/dist/metrics/config.js +0 -335
- package/dist/metrics/config.js.map +0 -1
- package/dist/types/metrics/config.d.ts +0 -195
- package/src/metrics/config.ts +0 -534
package/src/metrics/index.ts
CHANGED
|
@@ -1,66 +1,6 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
3
|
*/
|
|
4
|
-
import util from 'util';
|
|
5
|
-
|
|
6
|
-
import {includes} from 'lodash';
|
|
7
|
-
import uuid from 'uuid';
|
|
8
|
-
import window from 'global/window';
|
|
9
|
-
import anonymize from 'ip-anonymize';
|
|
10
|
-
|
|
11
|
-
import {getOSNameInternal} from '@webex/internal-plugin-metrics';
|
|
12
|
-
import LoggerProxy from '../common/logs/logger-proxy';
|
|
13
|
-
import {MEETING_ERRORS} from '../constants';
|
|
14
|
-
import BrowserDetection from '../common/browser-detection';
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
error,
|
|
18
|
-
eventType,
|
|
19
|
-
errorCodes as ERROR_CODE,
|
|
20
|
-
UNKNOWN,
|
|
21
|
-
CLIENT_NAME,
|
|
22
|
-
mediaType,
|
|
23
|
-
WebexAPIServiceErrorCodes,
|
|
24
|
-
} from './config';
|
|
25
|
-
|
|
26
|
-
const {getOSName, getOSVersion, getBrowserName, getBrowserVersion} = BrowserDetection();
|
|
27
|
-
|
|
28
|
-
// Apply a CIDR /28 format to the IPV4 and /96 to the IPV6 addresses
|
|
29
|
-
// For reference : https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing
|
|
30
|
-
const anonymizeIPAddress = (localIp) => anonymize(localIp, 28, 96);
|
|
31
|
-
|
|
32
|
-
const triggerTimers = ({event, meeting, data}) => {
|
|
33
|
-
switch (event) {
|
|
34
|
-
case eventType.CALL_INITIATED:
|
|
35
|
-
meeting.setStartCallInitJoinReq();
|
|
36
|
-
break;
|
|
37
|
-
case eventType.LOCUS_JOIN_REQUEST:
|
|
38
|
-
meeting.setEndCallInitJoinReq();
|
|
39
|
-
meeting.setStartJoinReqResp();
|
|
40
|
-
break;
|
|
41
|
-
case eventType.LOCUS_JOIN_RESPONSE:
|
|
42
|
-
meeting.setEndJoinReqResp();
|
|
43
|
-
meeting.setStartSetupDelay(mediaType.AUDIO);
|
|
44
|
-
meeting.setStartSetupDelay(mediaType.VIDEO);
|
|
45
|
-
meeting.setStartSendingMediaDelay(mediaType.AUDIO);
|
|
46
|
-
meeting.setStartSendingMediaDelay(mediaType.VIDEO);
|
|
47
|
-
break;
|
|
48
|
-
case eventType.RECEIVING_MEDIA_START:
|
|
49
|
-
meeting.setEndSetupDelay(data.mediaType);
|
|
50
|
-
break;
|
|
51
|
-
case eventType.SENDING_MEDIA_START:
|
|
52
|
-
meeting.setEndSendingMediaDelay(data.mediaType);
|
|
53
|
-
break;
|
|
54
|
-
case eventType.LOCAL_SDP_GENERATED:
|
|
55
|
-
meeting.setStartLocalSDPGenRemoteSDPRecvDelay();
|
|
56
|
-
break;
|
|
57
|
-
case eventType.REMOTE_SDP_RECEIVED:
|
|
58
|
-
meeting.setEndLocalSDPGenRemoteSDPRecvDelay();
|
|
59
|
-
break;
|
|
60
|
-
default:
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
4
|
|
|
65
5
|
/**
|
|
66
6
|
* @description Metrics handles all the call metrics events
|
|
@@ -69,10 +9,6 @@ const triggerTimers = ({event, meeting, data}) => {
|
|
|
69
9
|
*/
|
|
70
10
|
class Metrics {
|
|
71
11
|
static instance: Metrics;
|
|
72
|
-
|
|
73
|
-
_events: any;
|
|
74
|
-
keys: any;
|
|
75
|
-
meetingCollection: any;
|
|
76
12
|
webex: any;
|
|
77
13
|
|
|
78
14
|
/**
|
|
@@ -83,27 +19,6 @@ class Metrics {
|
|
|
83
19
|
*/
|
|
84
20
|
constructor() {
|
|
85
21
|
if (!Metrics.instance) {
|
|
86
|
-
/**
|
|
87
|
-
* @instance
|
|
88
|
-
* @type {Array}
|
|
89
|
-
* @private
|
|
90
|
-
* @memberof Metrics
|
|
91
|
-
*/
|
|
92
|
-
this._events = [];
|
|
93
|
-
/**
|
|
94
|
-
* @instance
|
|
95
|
-
* @type {MeetingCollection}
|
|
96
|
-
* @private
|
|
97
|
-
* @memberof Metrics
|
|
98
|
-
*/
|
|
99
|
-
this.meetingCollection = null;
|
|
100
|
-
/**
|
|
101
|
-
* @instance
|
|
102
|
-
* @type {MeetingCollection}
|
|
103
|
-
* @private
|
|
104
|
-
* @memberof Metrics
|
|
105
|
-
*/
|
|
106
|
-
this.keys = Object.values(eventType);
|
|
107
22
|
/**
|
|
108
23
|
* @instance
|
|
109
24
|
* @type {Metrics}
|
|
@@ -120,434 +35,14 @@ class Metrics {
|
|
|
120
35
|
/**
|
|
121
36
|
* Initializes the Metrics singleton with a meeting Collection.
|
|
122
37
|
*
|
|
123
|
-
* @param {Object} meetingCollection meetings object
|
|
124
38
|
* @param {Object} webex webex SDK object
|
|
125
39
|
*
|
|
126
40
|
* @returns {void}
|
|
127
41
|
*/
|
|
128
|
-
initialSetup(
|
|
129
|
-
this.meetingCollection = meetingCollection;
|
|
42
|
+
initialSetup(webex: object) {
|
|
130
43
|
this.webex = webex;
|
|
131
44
|
}
|
|
132
45
|
|
|
133
|
-
/**
|
|
134
|
-
* poste Meeting event metrics
|
|
135
|
-
* @param {object} options {meetingId/meeting} as a json object
|
|
136
|
-
* @param {Meeting} options.meeting Meeting object
|
|
137
|
-
* @param {String} options.meetingId
|
|
138
|
-
* @param {object} options.data
|
|
139
|
-
* @param {object} options.event
|
|
140
|
-
* @returns {object} null
|
|
141
|
-
*/
|
|
142
|
-
postEvent(options: {meeting?: any; meetingId?: string; data?: object; event?: any} | any) {
|
|
143
|
-
const {meetingId, data = {}, event} = options;
|
|
144
|
-
let {meeting} = options;
|
|
145
|
-
|
|
146
|
-
if (this.keys.indexOf(event) === -1) {
|
|
147
|
-
LoggerProxy.logger.error(
|
|
148
|
-
`Metrics:index#postEvent --> Event ${event} doesn't exist in dictionary`
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (!meeting && meetingId) {
|
|
153
|
-
meeting = this.meetingCollection.get(meetingId);
|
|
154
|
-
options.meeting = meeting;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (meeting) {
|
|
158
|
-
triggerTimers(options);
|
|
159
|
-
|
|
160
|
-
if (!meeting.callEvents) {
|
|
161
|
-
meeting.callEvents = [];
|
|
162
|
-
}
|
|
163
|
-
if (event === eventType.MEDIA_QUALITY) {
|
|
164
|
-
data.event = event;
|
|
165
|
-
meeting.sendMediaQualityAnalyzerMetrics(data);
|
|
166
|
-
} else {
|
|
167
|
-
meeting.callEvents.push(event);
|
|
168
|
-
data.event = event;
|
|
169
|
-
meeting.sendCallAnalyzerMetrics(data);
|
|
170
|
-
}
|
|
171
|
-
} else {
|
|
172
|
-
LoggerProxy.logger.info(
|
|
173
|
-
`Metrics:index#postEvent --> Event received for meetingId:${meetingId}, but meeting not found in collection.`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Docs for Call analyzer metrics
|
|
180
|
-
* https://sqbu-github.cisco.com/WebExSquared/call-analyzer/wiki
|
|
181
|
-
* https://sqbu-github.cisco.com/WebExSquared/event-dictionary/blob/master/diagnostic-events.raml
|
|
182
|
-
*/
|
|
183
|
-
|
|
184
|
-
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
185
|
-
initPayload(eventType, identifiers, options) {
|
|
186
|
-
const payload: any = {
|
|
187
|
-
eventId: uuid.v4(),
|
|
188
|
-
version: 1,
|
|
189
|
-
origin: {
|
|
190
|
-
name: 'endpoint',
|
|
191
|
-
networkType: 'unknown',
|
|
192
|
-
userAgent: this.userAgentToString(),
|
|
193
|
-
userType: options.userType,
|
|
194
|
-
loginType: options.loginType,
|
|
195
|
-
channel: options.channel,
|
|
196
|
-
clientInfo: {
|
|
197
|
-
clientType: options.clientType,
|
|
198
|
-
clientVersion: `${CLIENT_NAME}/${this.webex.version}`,
|
|
199
|
-
localNetworkPrefix: anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress),
|
|
200
|
-
osVersion: getOSVersion() || 'unknown',
|
|
201
|
-
subClientType: options.subClientType,
|
|
202
|
-
os: getOSNameInternal(),
|
|
203
|
-
browser: getBrowserName(),
|
|
204
|
-
browserVersion: getBrowserVersion(),
|
|
205
|
-
},
|
|
206
|
-
},
|
|
207
|
-
originTime: {
|
|
208
|
-
triggered: new Date().toISOString(),
|
|
209
|
-
},
|
|
210
|
-
senderCountryCode: this.webex.meetings.geoHintInfo?.countryCode,
|
|
211
|
-
event: {
|
|
212
|
-
name: eventType,
|
|
213
|
-
canProceed: true,
|
|
214
|
-
identifiers,
|
|
215
|
-
eventData: {webClientDomain: window.location.hostname},
|
|
216
|
-
},
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
// TODO: more options should be checked and some of them should be mandatory in certain conditions
|
|
220
|
-
if (options) {
|
|
221
|
-
if (Object.prototype.hasOwnProperty.call(options, 'canProceed')) {
|
|
222
|
-
payload.event.canProceed = options.canProceed;
|
|
223
|
-
}
|
|
224
|
-
if (options.errors) {
|
|
225
|
-
payload.event.errors = options.errors;
|
|
226
|
-
}
|
|
227
|
-
if (options.mediaType) {
|
|
228
|
-
payload.event.mediaType = options.mediaType;
|
|
229
|
-
}
|
|
230
|
-
if (options.trigger) {
|
|
231
|
-
payload.event.trigger = options.trigger;
|
|
232
|
-
}
|
|
233
|
-
if (options.pstnAudioType) {
|
|
234
|
-
payload.event.pstnAudioType = options.pstnAudioType;
|
|
235
|
-
}
|
|
236
|
-
if (options.mediaCapabilities) {
|
|
237
|
-
payload.event.mediaCapabilities = options.mediaCapabilities;
|
|
238
|
-
}
|
|
239
|
-
if (options.recoveredBy) {
|
|
240
|
-
payload.event.recoveredBy = options.recoveredBy;
|
|
241
|
-
}
|
|
242
|
-
if (options.joinTimes) {
|
|
243
|
-
payload.event.joinTimes = options.joinTimes;
|
|
244
|
-
}
|
|
245
|
-
if (options.isRoapCallEnabled) {
|
|
246
|
-
payload.event.isRoapCallEnabled = options.isRoapCallEnabled;
|
|
247
|
-
}
|
|
248
|
-
['breakoutMoveId', 'breakoutSessionId', 'breakoutGroupId'].forEach((item) => {
|
|
249
|
-
if (options[item]) {
|
|
250
|
-
payload.event.identifiers[item] = options[item];
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return payload;
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* get the payload specific for a media quality event through call analyzer
|
|
260
|
-
* @param {String} eventType the event name
|
|
261
|
-
* @param {Object} identifiers contains the identifiers needed for CA
|
|
262
|
-
* @param {String} identifiers.correlationId
|
|
263
|
-
* @param {String} identifiers.locusUrl
|
|
264
|
-
* @param {String} identifiers.locusId
|
|
265
|
-
* @param {Object} options
|
|
266
|
-
* @param {Object} options.intervalData
|
|
267
|
-
* @param {String} options.clientType
|
|
268
|
-
* @returns {Object}
|
|
269
|
-
* @public
|
|
270
|
-
* @memberof Metrics
|
|
271
|
-
*/
|
|
272
|
-
public initMediaPayload(
|
|
273
|
-
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
274
|
-
eventType: string,
|
|
275
|
-
identifiers: {
|
|
276
|
-
correlationId: string;
|
|
277
|
-
locusUrl: string;
|
|
278
|
-
locusId: string;
|
|
279
|
-
},
|
|
280
|
-
options:
|
|
281
|
-
| {
|
|
282
|
-
intervalData: object;
|
|
283
|
-
clientType: string;
|
|
284
|
-
}
|
|
285
|
-
| any = {}
|
|
286
|
-
) {
|
|
287
|
-
const {audioSetupDelay, videoSetupDelay, joinTimes} = options;
|
|
288
|
-
|
|
289
|
-
const payload = {
|
|
290
|
-
eventId: uuid.v4(),
|
|
291
|
-
version: 1,
|
|
292
|
-
origin: {
|
|
293
|
-
audioSetupDelay,
|
|
294
|
-
videoSetupDelay,
|
|
295
|
-
name: 'endpoint',
|
|
296
|
-
networkType: options.networkType || UNKNOWN,
|
|
297
|
-
userAgent: this.userAgentToString(),
|
|
298
|
-
clientInfo: {
|
|
299
|
-
clientType: options.clientType, // TODO: Only clientType: 'TEAMS_CLIENT' is whitelisted
|
|
300
|
-
clientVersion: `${CLIENT_NAME}/${this.webex.version}`,
|
|
301
|
-
localNetworkPrefix: anonymizeIPAddress(this.webex.meetings.geoHintInfo?.clientAddress),
|
|
302
|
-
os: getOSNameInternal(),
|
|
303
|
-
osVersion: getOSVersion() || UNKNOWN,
|
|
304
|
-
subClientType: options.subClientType,
|
|
305
|
-
browser: getBrowserName(),
|
|
306
|
-
browserVersion: getBrowserVersion(),
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
originTime: {
|
|
310
|
-
triggered: new Date().toISOString(),
|
|
311
|
-
},
|
|
312
|
-
senderCountryCode: this.webex.meetings.geoHintInfo?.countryCode,
|
|
313
|
-
event: {
|
|
314
|
-
name: eventType,
|
|
315
|
-
canProceed: true,
|
|
316
|
-
identifiers,
|
|
317
|
-
intervals: [options.intervalData],
|
|
318
|
-
joinTimes,
|
|
319
|
-
eventData: {
|
|
320
|
-
webClientDomain: window.location.hostname,
|
|
321
|
-
},
|
|
322
|
-
sourceMetadata: {
|
|
323
|
-
applicationSoftwareType: CLIENT_NAME,
|
|
324
|
-
applicationSoftwareVersion: this.webex.version,
|
|
325
|
-
mediaEngineSoftwareType: getBrowserName() || 'browser',
|
|
326
|
-
mediaEngineSoftwareVersion: getOSVersion() || UNKNOWN,
|
|
327
|
-
startTime: new Date().toISOString(),
|
|
328
|
-
},
|
|
329
|
-
},
|
|
330
|
-
};
|
|
331
|
-
|
|
332
|
-
return payload;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* This function Parses a Locus error and returns a diagnostic event payload.
|
|
337
|
-
* It should keep updating from:
|
|
338
|
-
* https://sqbu-github.cisco.com/WebExSquared/spark-client-framework/blob/master/spark-client-framework/Adapters/TelephonyAdapter/TelephonyAdapter.cpp#L920
|
|
339
|
-
*
|
|
340
|
-
* @param {Object} err the error Object from Locus response
|
|
341
|
-
* @param {boolean} showToUser true if a toast is shown to user
|
|
342
|
-
* @returns {{showToUser: boolean, category: string, errorDescription: string,
|
|
343
|
-
* errorCode: number, errorData: *, fatal: boolean, name: string}}
|
|
344
|
-
*/
|
|
345
|
-
parseLocusError(err: any, showToUser: boolean) {
|
|
346
|
-
let errorCode;
|
|
347
|
-
|
|
348
|
-
if (err && err.statusCode && err.statusCode >= 500) {
|
|
349
|
-
errorCode = 1003;
|
|
350
|
-
} else if (err && err.body && err.body.errorCode) {
|
|
351
|
-
// locus error codes: https://sqbu-github.cisco.com/WebExSquared/locus/blob/master/server/src/main/resources/locus-error-codes.properties
|
|
352
|
-
switch (ERROR_CODE[err.body.errorCode]) {
|
|
353
|
-
case MEETING_ERRORS.FREE_USER_MAX_PARTICIPANTS_EXCEEDED:
|
|
354
|
-
errorCode = 3007;
|
|
355
|
-
break;
|
|
356
|
-
case MEETING_ERRORS.PAID_USER_MAX_PARTICIPANTS_EXCEEDED:
|
|
357
|
-
case MEETING_ERRORS.SERVICE_MAX_PARTICIPANTS_EXCEEDED:
|
|
358
|
-
errorCode = 3002;
|
|
359
|
-
break;
|
|
360
|
-
case MEETING_ERRORS.INACTIVE:
|
|
361
|
-
errorCode = 4001;
|
|
362
|
-
break;
|
|
363
|
-
case MEETING_ERRORS.EXCEEDED_MAX_JOINED_PARTICIPANTS:
|
|
364
|
-
case MEETING_ERRORS.EXCEEDED_SERVICE_MAX_PARTICIPANTS:
|
|
365
|
-
errorCode = 3001;
|
|
366
|
-
break;
|
|
367
|
-
case MEETING_ERRORS.MEETING_IS_LOCKED:
|
|
368
|
-
errorCode = 4002;
|
|
369
|
-
break;
|
|
370
|
-
case MEETING_ERRORS.MEETING_IS_TERMINATING:
|
|
371
|
-
errorCode = 4003;
|
|
372
|
-
break;
|
|
373
|
-
case MEETING_ERRORS.MEETING_REQUIRE_MODERATOR_PIN_INTENT:
|
|
374
|
-
errorCode = 4004;
|
|
375
|
-
break;
|
|
376
|
-
case MEETING_ERRORS.MEETING_REQUIRE_MODERATOR_PIN:
|
|
377
|
-
errorCode = 4005;
|
|
378
|
-
break;
|
|
379
|
-
case MEETING_ERRORS.MEETING_REQUIRE_MODERATOR_ROLE:
|
|
380
|
-
errorCode = 4006;
|
|
381
|
-
break;
|
|
382
|
-
case MEETING_ERRORS.JOIN_RESTRICTED_USER:
|
|
383
|
-
case MEETING_ERRORS.GET_RESTRICTED_USER:
|
|
384
|
-
case MEETING_ERRORS.CREATE_MEDIA_RESTRICTED_USER:
|
|
385
|
-
errorCode = 3005;
|
|
386
|
-
break;
|
|
387
|
-
case MEETING_ERRORS.JOIN_RESTRICTED_USER_NOT_IN_ROOM:
|
|
388
|
-
errorCode = 4007;
|
|
389
|
-
break;
|
|
390
|
-
case MEETING_ERRORS.MEETING_NOT_FOUND:
|
|
391
|
-
errorCode = 4011;
|
|
392
|
-
break;
|
|
393
|
-
case MEETING_ERRORS.NOT_WEBEX_SITE:
|
|
394
|
-
errorCode = 4012;
|
|
395
|
-
break;
|
|
396
|
-
case MEETING_ERRORS.INVALID_JOIN_TIME:
|
|
397
|
-
errorCode = 4013;
|
|
398
|
-
break;
|
|
399
|
-
case MEETING_ERRORS.PHONE_NUMBER_NOT_A_NUMBER:
|
|
400
|
-
errorCode = 4016;
|
|
401
|
-
break;
|
|
402
|
-
case MEETING_ERRORS.PHONE_NUMBER_TOO_LONG:
|
|
403
|
-
errorCode = 4017;
|
|
404
|
-
break;
|
|
405
|
-
case MEETING_ERRORS.INVALID_DIALABLE_KEY:
|
|
406
|
-
errorCode = 4018;
|
|
407
|
-
break;
|
|
408
|
-
case MEETING_ERRORS.ONE_ON_ONE_TO_SELF_NOT_ALLOWED:
|
|
409
|
-
errorCode = 4019;
|
|
410
|
-
break;
|
|
411
|
-
case MEETING_ERRORS.REMOVED_PARTICIPANT:
|
|
412
|
-
errorCode = 4020;
|
|
413
|
-
break;
|
|
414
|
-
case MEETING_ERRORS.MEETING_LINK_NOT_FOUND:
|
|
415
|
-
errorCode = 4021;
|
|
416
|
-
break;
|
|
417
|
-
case MEETING_ERRORS.PHONE_NUMBER_TOO_SHORT_AFTER_IDD:
|
|
418
|
-
errorCode = 4022;
|
|
419
|
-
break;
|
|
420
|
-
case MEETING_ERRORS.INVALID_INVITEE_ADDRESS:
|
|
421
|
-
errorCode = 4023;
|
|
422
|
-
break;
|
|
423
|
-
case MEETING_ERRORS.PMR_ACCOUNT_LOCKED:
|
|
424
|
-
errorCode = 4024;
|
|
425
|
-
break;
|
|
426
|
-
case MEETING_ERRORS.RESOURCE_GUEST_FORBIDDEN:
|
|
427
|
-
errorCode = 4025;
|
|
428
|
-
break;
|
|
429
|
-
case MEETING_ERRORS.PMR_ACCOUNT_SUSPENDED:
|
|
430
|
-
errorCode = 4026;
|
|
431
|
-
break;
|
|
432
|
-
case MEETING_ERRORS.EMPTY_PHONE_NUMBER_OR_COUNTRY_CODE:
|
|
433
|
-
errorCode = 4027;
|
|
434
|
-
break;
|
|
435
|
-
case MEETING_ERRORS.INVALID_SINCE_OR_SEQUENCE_HASH_IN_REQUEST:
|
|
436
|
-
errorCode = 1006;
|
|
437
|
-
break;
|
|
438
|
-
case MEETING_ERRORS.CONVERSATION_NOT_FOUND:
|
|
439
|
-
errorCode = 4028;
|
|
440
|
-
break;
|
|
441
|
-
case MEETING_ERRORS.RECORDING_CONTROL_NOT_SUPPORTED:
|
|
442
|
-
case MEETING_ERRORS.RECORDING_NOT_STARTED:
|
|
443
|
-
case MEETING_ERRORS.RECORDING_NOT_ENABLED:
|
|
444
|
-
errorCode = 4029;
|
|
445
|
-
break;
|
|
446
|
-
default:
|
|
447
|
-
errorCode = 4008;
|
|
448
|
-
}
|
|
449
|
-
} else {
|
|
450
|
-
errorCode = 4008;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
return this.generateErrorPayload(errorCode, showToUser, error.name.LOCUS_RESPONSE, err);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Pareses webex api error.
|
|
458
|
-
*
|
|
459
|
-
* @param {object} err
|
|
460
|
-
* @param {boolean} showToUser
|
|
461
|
-
* @returns {object | null}
|
|
462
|
-
*/
|
|
463
|
-
parseWebexApiError(err: any, showToUser: boolean) {
|
|
464
|
-
const serviceErrorCode = err?.body?.code;
|
|
465
|
-
const clientCodeError = WebexAPIServiceErrorCodes[serviceErrorCode];
|
|
466
|
-
|
|
467
|
-
if (clientCodeError) {
|
|
468
|
-
return this.generateErrorPayload(clientCodeError, showToUser, error.name.OTHER, err);
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return this.generateErrorPayload(4100, showToUser, error.name.OTHER, err);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* Generates Error for the CA event
|
|
476
|
-
*
|
|
477
|
-
* @param {integer} errorCode
|
|
478
|
-
* @param {boolean} shownToUser
|
|
479
|
-
* @param {string} name
|
|
480
|
-
* @param {any} err
|
|
481
|
-
* @returns {any}
|
|
482
|
-
*/
|
|
483
|
-
generateErrorPayload(errorCode, shownToUser, name, err) {
|
|
484
|
-
if (error.errors[errorCode]) {
|
|
485
|
-
const errorPayload: any = {
|
|
486
|
-
shownToUser: shownToUser || false,
|
|
487
|
-
category: error.errors[errorCode][2],
|
|
488
|
-
errorDescription: error.errors[errorCode][0],
|
|
489
|
-
errorCode,
|
|
490
|
-
fatal: !includes(error.notFatalErrorList, errorCode),
|
|
491
|
-
name: name || error.name.OTHER,
|
|
492
|
-
serviceErrorCode: err?.body?.code,
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
if (err && err.body) {
|
|
496
|
-
errorPayload.errorData = {error: err.body};
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
if (err && err.statusCode) {
|
|
500
|
-
errorPayload.httpCode = err.statusCode;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
return errorPayload;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return null;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Returns a formated string of the user agent.
|
|
511
|
-
*
|
|
512
|
-
* @returns {string} formatted user agent information
|
|
513
|
-
*/
|
|
514
|
-
userAgentToString() {
|
|
515
|
-
let userAgentOption;
|
|
516
|
-
let browserInfo;
|
|
517
|
-
const clientInfo = util.format('client=%s', `${this.webex.meetings?.metrics?.clientName}`);
|
|
518
|
-
|
|
519
|
-
if (
|
|
520
|
-
['chrome', 'firefox', 'msie', 'msedge', 'safari'].indexOf(getBrowserName().toLowerCase()) !==
|
|
521
|
-
-1
|
|
522
|
-
) {
|
|
523
|
-
browserInfo = util.format(
|
|
524
|
-
'browser=%s',
|
|
525
|
-
`${getBrowserName().toLowerCase()}/${getBrowserVersion().split('.')[0]}`
|
|
526
|
-
);
|
|
527
|
-
}
|
|
528
|
-
const osInfo = util.format('os=%s', `${getOSName()}/${getOSVersion().split('.')[0]}`);
|
|
529
|
-
|
|
530
|
-
if (browserInfo) {
|
|
531
|
-
userAgentOption = `(${browserInfo}`;
|
|
532
|
-
}
|
|
533
|
-
if (osInfo) {
|
|
534
|
-
userAgentOption = userAgentOption
|
|
535
|
-
? `${userAgentOption}; ${clientInfo}; ${osInfo}`
|
|
536
|
-
: `${clientInfo}; (${osInfo}`;
|
|
537
|
-
}
|
|
538
|
-
if (userAgentOption) {
|
|
539
|
-
userAgentOption += ')';
|
|
540
|
-
|
|
541
|
-
return util.format(
|
|
542
|
-
'webex-js-sdk/%s %s',
|
|
543
|
-
`${process.env.NODE_ENV}-${this.webex.version}`,
|
|
544
|
-
userAgentOption
|
|
545
|
-
);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
return util.format('webex-js-sdk/%s', `${process.env.NODE_ENV}-${this.webex.version}`);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
46
|
/**
|
|
552
47
|
* Uploads given metric to the Metrics service as an Behavioral metric.
|
|
553
48
|
* Metadata about the environment such as browser, OS, SDK and their versions
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
19
19
|
import ReconnectionError from '../common/errors/reconnection';
|
|
20
20
|
import ReconnectInProgress from '../common/errors/reconnection-in-progress';
|
|
21
|
-
import {eventType, reconnection, errorObjects} from '../metrics/config';
|
|
22
21
|
import Metrics from '../metrics';
|
|
23
22
|
import Meeting from '../meeting';
|
|
24
23
|
import {MediaRequestManager} from '../multistream/mediaRequestManager';
|
|
@@ -325,9 +324,13 @@ export default class ReconnectionManager {
|
|
|
325
324
|
LoggerProxy.logger.info(
|
|
326
325
|
'ReconnectionManager:index#reconnect --> Sending reconnect start metric.'
|
|
327
326
|
);
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
327
|
+
|
|
328
|
+
// @ts-ignore
|
|
329
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
330
|
+
name: 'client.media.reconnecting',
|
|
331
|
+
options: {
|
|
332
|
+
meetingId: this.meeting.id,
|
|
333
|
+
},
|
|
331
334
|
});
|
|
332
335
|
}
|
|
333
336
|
|
|
@@ -337,10 +340,16 @@ export default class ReconnectionManager {
|
|
|
337
340
|
LoggerProxy.logger.info(
|
|
338
341
|
'ReconnectionManager:index#reconnect --> Sending reconnect success metric.'
|
|
339
342
|
);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
343
|
+
|
|
344
|
+
// @ts-ignore
|
|
345
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
346
|
+
name: 'client.media.recovered',
|
|
347
|
+
payload: {
|
|
348
|
+
recoveredBy: 'new',
|
|
349
|
+
},
|
|
350
|
+
options: {
|
|
351
|
+
meetingId: this.meeting.id,
|
|
352
|
+
},
|
|
344
353
|
});
|
|
345
354
|
})
|
|
346
355
|
.catch((reconnectError) => {
|
|
@@ -364,23 +373,24 @@ export default class ReconnectionManager {
|
|
|
364
373
|
'ReconnectionManager:index#reconnect --> Sending reconnect abort metric.'
|
|
365
374
|
);
|
|
366
375
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
376
|
+
// @ts-ignore
|
|
377
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
378
|
+
name: 'client.call.aborted',
|
|
379
|
+
payload: {
|
|
371
380
|
errors: [
|
|
372
381
|
{
|
|
373
|
-
category:
|
|
382
|
+
category: 'expected',
|
|
374
383
|
errorCode: 2008,
|
|
375
384
|
fatal: true,
|
|
376
|
-
name:
|
|
385
|
+
name: 'media-engine',
|
|
377
386
|
shownToUser: false,
|
|
378
387
|
},
|
|
379
388
|
],
|
|
380
389
|
},
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
390
|
+
options: {
|
|
391
|
+
meetingId: this.meeting.id,
|
|
392
|
+
},
|
|
393
|
+
});
|
|
384
394
|
if (reconnectError instanceof NeedsRejoinError) {
|
|
385
395
|
// send call aborded event with catogery as expected as we are trying to rejoin
|
|
386
396
|
|
package/src/roap/request.ts
CHANGED
|
@@ -3,8 +3,6 @@ import {StatelessWebexPlugin} from '@webex/webex-core';
|
|
|
3
3
|
|
|
4
4
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
5
5
|
import {REACHABILITY} from '../constants';
|
|
6
|
-
import Metrics from '../metrics';
|
|
7
|
-
import {eventType} from '../metrics/config';
|
|
8
6
|
import {LocusMediaRequest} from '../meeting/locusMediaRequest';
|
|
9
7
|
|
|
10
8
|
/**
|
|
@@ -95,7 +93,13 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
95
93
|
`Roap:request#sendRoap --> ${locusSelfUrl} \n ${roapMessage.messageType} \n seq:${roapMessage.seq}`
|
|
96
94
|
);
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
98
|
+
name: 'client.locus.media.request',
|
|
99
|
+
options: {
|
|
100
|
+
meetingId,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
99
103
|
|
|
100
104
|
return locusMediaRequest
|
|
101
105
|
.send({
|
|
@@ -107,8 +111,13 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
107
111
|
reachability: localSdpWithReachabilityData.reachability,
|
|
108
112
|
})
|
|
109
113
|
.then((res) => {
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
// @ts-ignore
|
|
115
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
116
|
+
name: 'client.locus.media.response',
|
|
117
|
+
options: {
|
|
118
|
+
meetingId,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
112
121
|
// always it will be the first mediaConnection Object
|
|
113
122
|
const mediaConnections =
|
|
114
123
|
res.body.mediaConnections &&
|
|
@@ -132,10 +141,13 @@ export default class RoapRequest extends StatelessWebexPlugin {
|
|
|
132
141
|
};
|
|
133
142
|
})
|
|
134
143
|
.catch((err) => {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
144
|
+
// @ts-ignore
|
|
145
|
+
this.webex.internal.newMetrics.submitClientEvent({
|
|
146
|
+
name: 'client.locus.media.response',
|
|
147
|
+
options: {
|
|
148
|
+
meetingId,
|
|
149
|
+
rawError: err,
|
|
150
|
+
},
|
|
139
151
|
});
|
|
140
152
|
LoggerProxy.logger.error(`Roap:request#sendRoap --> Error:${JSON.stringify(err, null, 2)}`);
|
|
141
153
|
LoggerProxy.logger.error(
|
|
@@ -93,10 +93,12 @@ describe('plugin-meetings', () => {
|
|
|
93
93
|
let onBreakoutMoveResponseStub = sinon.stub(breakoutEvent, 'onBreakoutMoveResponse');
|
|
94
94
|
await breakout.join();
|
|
95
95
|
assert.calledOnceWithExactly(breakoutEvent.onBreakoutMoveRequest,
|
|
96
|
-
{currentSession: breakout, meeting: {id: 'meeting-id'}, breakoutMoveId: 'breakoutMoveId'}
|
|
96
|
+
{currentSession: breakout, meeting: {id: 'meeting-id'}, breakoutMoveId: 'breakoutMoveId'},
|
|
97
|
+
webex.internal.newMetrics.submitClientEvent
|
|
97
98
|
);
|
|
98
99
|
assert.calledOnceWithExactly(breakoutEvent.onBreakoutMoveResponse,
|
|
99
|
-
{currentSession: breakout, meeting: {id: 'meeting-id'}, breakoutMoveId: 'breakoutMoveId'}
|
|
100
|
+
{currentSession: breakout, meeting: {id: 'meeting-id'}, breakoutMoveId: 'breakoutMoveId'},
|
|
101
|
+
webex.internal.newMetrics.submitClientEvent
|
|
100
102
|
);
|
|
101
103
|
|
|
102
104
|
onBreakoutMoveRequestStub.restore();
|