@webex/plugin-meetings 1.159.3 → 1.159.6
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/analyzer/analyzer.js.map +1 -1
- package/dist/analyzer/calculator.js.map +1 -1
- package/dist/common/browser-detection.js.map +1 -1
- package/dist/common/collection.js.map +1 -1
- package/dist/common/config.js.map +1 -1
- package/dist/common/constants.js.map +1 -1
- package/dist/common/errors/captcha-error.js +3 -1
- package/dist/common/errors/captcha-error.js.map +1 -1
- package/dist/common/errors/intent-to-join.js +3 -1
- package/dist/common/errors/intent-to-join.js.map +1 -1
- package/dist/common/errors/join-meeting.js +3 -1
- package/dist/common/errors/join-meeting.js.map +1 -1
- package/dist/common/errors/media.js +3 -1
- package/dist/common/errors/media.js.map +1 -1
- package/dist/common/errors/parameter.js +3 -1
- package/dist/common/errors/parameter.js.map +1 -1
- package/dist/common/errors/password-error.js +3 -1
- package/dist/common/errors/password-error.js.map +1 -1
- package/dist/common/errors/permission.js +3 -1
- package/dist/common/errors/permission.js.map +1 -1
- package/dist/common/errors/reconnection-in-progress.js +3 -1
- package/dist/common/errors/reconnection-in-progress.js.map +1 -1
- package/dist/common/errors/reconnection.js +3 -1
- package/dist/common/errors/reconnection.js.map +1 -1
- package/dist/common/errors/stats.js +3 -1
- package/dist/common/errors/stats.js.map +1 -1
- package/dist/common/errors/webex-errors.js +9 -7
- package/dist/common/errors/webex-errors.js.map +1 -1
- package/dist/common/errors/webex-meetings-error.js.map +1 -1
- package/dist/common/events/events-scope.js.map +1 -1
- package/dist/common/events/events.js.map +1 -1
- package/dist/common/events/trigger-proxy.js.map +1 -1
- package/dist/common/events/util.js.map +1 -1
- package/dist/common/logs/logger-config.js.map +1 -1
- package/dist/common/logs/logger-proxy.js.map +1 -1
- package/dist/common/logs/request.js.map +1 -1
- package/dist/common/queue.js.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/constants.js +2 -2
- package/dist/constants.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/locus-info/controlsUtils.js +4 -3
- package/dist/locus-info/controlsUtils.js.map +1 -1
- package/dist/locus-info/fullState.js.map +1 -1
- package/dist/locus-info/hostUtils.js.map +1 -1
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/infoUtils.js.map +1 -1
- package/dist/locus-info/mediaSharesUtils.js.map +1 -1
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/locus-info/selfUtils.js.map +1 -1
- package/dist/media/index.js +2 -2
- package/dist/media/index.js.map +1 -1
- package/dist/media/properties.js.map +1 -1
- package/dist/media/util.js.map +1 -1
- package/dist/mediaQualityMetrics/config.js.map +1 -1
- package/dist/meeting/in-meeting-actions.js.map +1 -1
- package/dist/meeting/index.js +2 -2
- package/dist/meeting/index.js.map +1 -1
- package/dist/meeting/muteState.js +3 -1
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +2 -2
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/state.js.map +1 -1
- package/dist/meeting/util.js +2 -2
- package/dist/meeting/util.js.map +1 -1
- package/dist/meeting-info/collection.js.map +1 -1
- package/dist/meeting-info/index.js.map +1 -1
- package/dist/meeting-info/meeting-info-v2.js +6 -6
- package/dist/meeting-info/meeting-info-v2.js.map +1 -1
- package/dist/meeting-info/request.js.map +1 -1
- package/dist/meeting-info/util.js.map +1 -1
- package/dist/meeting-info/utilv2.js +1 -1
- package/dist/meeting-info/utilv2.js.map +1 -1
- package/dist/meetings/collection.js.map +1 -1
- package/dist/meetings/index.js +222 -221
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/request.js.map +1 -1
- package/dist/meetings/util.js.map +1 -1
- package/dist/member/index.js.map +1 -1
- package/dist/member/util.js.map +1 -1
- package/dist/members/collection.js.map +1 -1
- package/dist/members/index.js.map +1 -1
- package/dist/members/request.js.map +1 -1
- package/dist/members/util.js.map +1 -1
- package/dist/metrics/config.js +1 -1
- package/dist/metrics/config.js.map +1 -1
- package/dist/metrics/constants.js.map +1 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/mqa-processor.js +2 -2
- package/dist/metrics/mqa-processor.js.map +1 -1
- package/dist/networkQualityMonitor/index.js.map +1 -1
- package/dist/peer-connection-manager/index.js.map +1 -1
- package/dist/peer-connection-manager/util.js.map +1 -1
- package/dist/personal-meeting-room/index.js.map +1 -1
- package/dist/personal-meeting-room/request.js.map +1 -1
- package/dist/personal-meeting-room/util.js.map +1 -1
- package/dist/reachability/index.js.map +1 -1
- package/dist/reachability/request.js +4 -3
- package/dist/reachability/request.js.map +1 -1
- package/dist/reconnection-manager/index.js +2 -2
- package/dist/reconnection-manager/index.js.map +1 -1
- package/dist/roap/collection.js.map +1 -1
- package/dist/roap/handler.js.map +1 -1
- package/dist/roap/index.js +7 -7
- package/dist/roap/index.js.map +1 -1
- package/dist/roap/request.js +2 -2
- package/dist/roap/request.js.map +1 -1
- package/dist/roap/state.js.map +1 -1
- package/dist/roap/util.js.map +1 -1
- package/dist/stats/data.js.map +1 -1
- package/dist/stats/events.js.map +1 -1
- package/dist/stats/filter.js.map +1 -1
- package/dist/stats/history.js.map +1 -1
- package/dist/stats/index.js +126 -126
- package/dist/stats/index.js.map +1 -1
- package/dist/stats/metrics.js.map +1 -1
- package/dist/stats/stats.js.map +1 -1
- package/dist/stats/stream.js.map +1 -1
- package/dist/stats/transformer.js.map +1 -1
- package/dist/stats/util.js.map +1 -1
- package/dist/statsAnalyzer/global.js.map +1 -1
- package/dist/statsAnalyzer/index.js +1 -1
- package/dist/statsAnalyzer/index.js.map +1 -1
- package/dist/statsAnalyzer/mqaUtil.js.map +1 -1
- package/dist/transcription/index.js.map +1 -1
- package/package.json +6 -6
- package/src/common/errors/webex-errors.js +1 -1
- package/src/locus-info/parser.js +2 -2
- package/src/meeting/index.js +1 -2
- package/src/meeting/util.js +2 -2
- package/src/meeting-info/utilv2.js +1 -1
- package/src/meetings/index.js +555 -558
- package/src/roap/index.js +48 -48
- package/src/stats/index.js +142 -142
- package/src/statsAnalyzer/index.js +1 -1
- package/test/unit/spec/meeting-info/utilv2.js +7 -0
- package/test/unit/spec/meetings/index.js +39 -4
package/src/meetings/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
1
|
|
|
5
2
|
import '@webex/internal-plugin-mercury';
|
|
6
3
|
import '@webex/internal-plugin-conversation';
|
|
@@ -109,43 +106,43 @@ import MeetingsUtil from './util';
|
|
|
109
106
|
* @class
|
|
110
107
|
*/
|
|
111
108
|
export default class Meetings extends WebexPlugin {
|
|
112
|
-
|
|
109
|
+
namespace = MEETINGS;
|
|
113
110
|
|
|
114
|
-
|
|
111
|
+
/**
|
|
115
112
|
* Initializes the Meetings Plugin
|
|
116
113
|
* @constructor
|
|
117
114
|
* @public
|
|
118
115
|
* @memberof Meetings
|
|
119
116
|
*/
|
|
120
|
-
|
|
121
|
-
|
|
117
|
+
constructor(...args) {
|
|
118
|
+
super(...args);
|
|
122
119
|
|
|
123
|
-
|
|
120
|
+
/**
|
|
124
121
|
* The Meetings request to interact with server
|
|
125
122
|
* @instance
|
|
126
123
|
* @type {Object}
|
|
127
124
|
* @private
|
|
128
125
|
* @memberof Meetings
|
|
129
126
|
*/
|
|
130
|
-
|
|
131
|
-
|
|
127
|
+
this.request = new Request({}, {parent: this.webex});
|
|
128
|
+
/**
|
|
132
129
|
* Log upload request helper
|
|
133
130
|
* @instance
|
|
134
131
|
* @type {Object}
|
|
135
132
|
* @private
|
|
136
133
|
* @memberof Meetings
|
|
137
134
|
*/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
this.loggerRequest = new LoggerRequest({webex: this.webex});
|
|
136
|
+
this.meetingCollection = new MeetingCollection();
|
|
137
|
+
/**
|
|
141
138
|
* The PersonalMeetingRoom object to interact with server
|
|
142
139
|
* @instance
|
|
143
140
|
* @type {Object}
|
|
144
141
|
* @public
|
|
145
142
|
* @memberof Meetings
|
|
146
143
|
*/
|
|
147
|
-
|
|
148
|
-
|
|
144
|
+
this.personalMeetingRoom = null;
|
|
145
|
+
/**
|
|
149
146
|
* The Reachability object to interact with server, starts as null until {@link Meeting#setReachability} is called
|
|
150
147
|
* starts as null
|
|
151
148
|
* @instance
|
|
@@ -153,27 +150,27 @@ export default class Meetings extends WebexPlugin {
|
|
|
153
150
|
* @private
|
|
154
151
|
* @memberof Meetings
|
|
155
152
|
*/
|
|
156
|
-
|
|
153
|
+
this.reachability = null;
|
|
157
154
|
|
|
158
|
-
|
|
155
|
+
/**
|
|
159
156
|
* If the meetings plugin has been registered and listening via {@link Meetings#register}
|
|
160
157
|
* @instance
|
|
161
158
|
* @type {Boolean}
|
|
162
159
|
* @public
|
|
163
160
|
* @memberof Meetings
|
|
164
161
|
*/
|
|
165
|
-
|
|
162
|
+
this.registered = false;
|
|
166
163
|
|
|
167
|
-
|
|
164
|
+
/**
|
|
168
165
|
* This values indicates the preferred webex site the user will start there meeting, getsits value from {@link Meetings#register}
|
|
169
166
|
* @instance
|
|
170
167
|
* @type {String}
|
|
171
168
|
* @private
|
|
172
169
|
* @memberof Meetings
|
|
173
170
|
*/
|
|
174
|
-
|
|
171
|
+
this.preferredWebexSite = '';
|
|
175
172
|
|
|
176
|
-
|
|
173
|
+
/**
|
|
177
174
|
* The public interface for the internal Media util files. These are helpful to expose outside the context
|
|
178
175
|
* of a meeting so that a user can access media without creating a meeting instance.
|
|
179
176
|
* @instance
|
|
@@ -181,17 +178,17 @@ export default class Meetings extends WebexPlugin {
|
|
|
181
178
|
* @private
|
|
182
179
|
* @memberof Meetings
|
|
183
180
|
*/
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
this.onReady();
|
|
190
|
-
MeetingsUtil.checkH264Support({disableNotifications: true});
|
|
191
|
-
Metrics.initialSetup(this.meetingCollection, this.webex);
|
|
192
|
-
}
|
|
181
|
+
this.media = {
|
|
182
|
+
getUserMedia: Media.getUserMedia,
|
|
183
|
+
getSupportedDevice: Media.getSupportedDevice
|
|
184
|
+
};
|
|
193
185
|
|
|
194
|
-
|
|
186
|
+
this.onReady();
|
|
187
|
+
MeetingsUtil.checkH264Support({disableNotifications: true});
|
|
188
|
+
Metrics.initialSetup(this.meetingCollection, this.webex);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
195
192
|
* handle locus events and takes meeting actions with them as they come in
|
|
196
193
|
* @param {Object} data a locus event
|
|
197
194
|
* @param {String} data.locusUrl
|
|
@@ -201,102 +198,102 @@ export default class Meetings extends WebexPlugin {
|
|
|
201
198
|
* @private
|
|
202
199
|
* @memberof Meetings
|
|
203
200
|
*/
|
|
204
|
-
|
|
205
|
-
|
|
201
|
+
handleLocusEvent(data) {
|
|
202
|
+
let meeting = null;
|
|
206
203
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
204
|
+
// getting meeting by correlationId. This will happen for the new event
|
|
205
|
+
// Either the locus
|
|
206
|
+
// TODO : Add check for the callBack Address
|
|
207
|
+
meeting = this.meetingCollection.getByKey(LOCUS_URL, data.locusUrl) ||
|
|
211
208
|
this.meetingCollection.getByKey(CORRELATION_ID, MeetingsUtil.checkForCorrelationId(this.webex.internal.device.url, data.locus)) ||
|
|
212
209
|
this.meetingCollection.getByKey(SIP_URI, data.locus.self && data.locus.self.callbackInfo && data.locus.self.callbackInfo.callbackAddress) ||
|
|
213
|
-
(
|
|
210
|
+
(data.locus.info?.isUnifiedSpaceMeeting ? undefined : this.meetingCollection.getByKey(CONVERSATION_URL, data.locus.conversationUrl));
|
|
214
211
|
|
|
215
|
-
|
|
216
|
-
|
|
212
|
+
// Special case when locus has got replaced, This only happend once if a replace locus exists
|
|
213
|
+
// https://sqbu-github.cisco.com/WebExSquared/locus/wiki/Locus-changing-mid-call
|
|
217
214
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
215
|
+
if (!meeting && data.locus?.replaces?.length > 0) {
|
|
216
|
+
// Always the last element in the replace is the active one
|
|
217
|
+
meeting = this.meetingCollection.getByKey(LOCUS_URL, data.locus.replaces[data.locus.replaces.length - 1].locusUrl);
|
|
218
|
+
}
|
|
222
219
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
220
|
+
if (!meeting) {
|
|
221
|
+
// TODO: create meeting when we get a meeting object
|
|
222
|
+
// const checkForEnded = (locus) => {
|
|
223
|
+
// TODO: you already ended the meeting but you got an event later
|
|
224
|
+
// Mainly for 1:1 Callsor meeting
|
|
225
|
+
// Happens mainly after refresh
|
|
229
226
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
227
|
+
// 1:1 Meeting
|
|
228
|
+
// 1) You ended a call before but you got a mercury event
|
|
229
|
+
// Make sure end the call and cleanup the meeting only if the mercury
|
|
230
|
+
// event says so
|
|
231
|
+
// 2) Maintain lastSync time in the meetings object which helps to compare
|
|
232
|
+
// If the meeting came befor or after the sync . ANy meeting start time before the sync time is invalid
|
|
236
233
|
|
|
237
|
-
|
|
238
|
-
|
|
234
|
+
// For space Meeting
|
|
235
|
+
// Check the locus object and see who has joined
|
|
239
236
|
|
|
240
|
-
|
|
241
|
-
|
|
237
|
+
// };
|
|
238
|
+
// rather then locus object change to locus url
|
|
242
239
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
240
|
+
if (data.locus && data.locus.fullState && data.locus.fullState.state === LOCUS.STATE.INACTIVE) {
|
|
241
|
+
// just ignore the event as its already ended and not active
|
|
242
|
+
LoggerProxy.logger.warn('Meetings:index#handleLocusEvent --> Locus event received for meeting, after it was ended.');
|
|
246
243
|
|
|
247
|
-
|
|
248
|
-
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
249
246
|
|
|
250
247
|
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
// When its wireless share or guest and user leaves the meeting we dont have to keep the meeting object
|
|
249
|
+
// Any future events will be neglected
|
|
253
250
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
251
|
+
if (data.locus && data.locus.self && (data.locus.self.state === _LEFT_ && data.locus.self.removed === true)) {
|
|
252
|
+
// just ignore the event as its already ended and not active
|
|
253
|
+
LoggerProxy.logger.warn('Meetings:index#handleLocusEvent --> Locus event received for meeting, after it was ended.');
|
|
257
254
|
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
this.create(data.locus, _LOCUS_ID_).then((newMeeting) => {
|
|
262
|
-
meeting = newMeeting;
|
|
263
|
-
|
|
264
|
-
// It's a new meeting so initialize the locus data
|
|
265
|
-
meeting.locusInfo.initialSetup(data.locus);
|
|
266
|
-
}).catch((e) => {
|
|
267
|
-
console.log(e);
|
|
268
|
-
})
|
|
269
|
-
.finally(() => {
|
|
270
|
-
// There will be cases where locus event comes in gets created and deleted because its a 1:1 and meeting gets deleted
|
|
271
|
-
// because the other user left so before sending 'added' event make sure it exists in the collection
|
|
272
|
-
|
|
273
|
-
if (this.getMeetingByType(_ID_, meeting.id)) {
|
|
274
|
-
Metrics.postEvent({event: eventType.REMOTE_STARTED, meeting, data: {trigger: trigger.MERCURY_EVENT}});
|
|
275
|
-
Trigger.trigger(
|
|
276
|
-
this,
|
|
277
|
-
{
|
|
278
|
-
file: 'meetings',
|
|
279
|
-
function: 'handleLocusEvent'
|
|
280
|
-
},
|
|
281
|
-
EVENT_TRIGGERS.MEETING_ADDED,
|
|
282
|
-
{
|
|
283
|
-
meeting,
|
|
284
|
-
type: meeting.type === _MEETING_ ? _JOIN_ : _INCOMING_
|
|
285
|
-
}
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
// Meeting got added but was not found in the collection. It might have got destroyed
|
|
290
|
-
LoggerProxy.logger.warn('Meetings:index#handleLocusEvent --> Created and destroyed meeting object before sending an event');
|
|
291
|
-
}
|
|
292
|
-
});
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
meeting.locusInfo.parse(meeting, data);
|
|
255
|
+
return;
|
|
296
256
|
}
|
|
257
|
+
|
|
258
|
+
this.create(data.locus, _LOCUS_ID_).then((newMeeting) => {
|
|
259
|
+
meeting = newMeeting;
|
|
260
|
+
|
|
261
|
+
// It's a new meeting so initialize the locus data
|
|
262
|
+
meeting.locusInfo.initialSetup(data.locus);
|
|
263
|
+
}).catch((e) => {
|
|
264
|
+
console.log(e);
|
|
265
|
+
})
|
|
266
|
+
.finally(() => {
|
|
267
|
+
// There will be cases where locus event comes in gets created and deleted because its a 1:1 and meeting gets deleted
|
|
268
|
+
// because the other user left so before sending 'added' event make sure it exists in the collection
|
|
269
|
+
|
|
270
|
+
if (this.getMeetingByType(_ID_, meeting.id)) {
|
|
271
|
+
Metrics.postEvent({event: eventType.REMOTE_STARTED, meeting, data: {trigger: trigger.MERCURY_EVENT}});
|
|
272
|
+
Trigger.trigger(
|
|
273
|
+
this,
|
|
274
|
+
{
|
|
275
|
+
file: 'meetings',
|
|
276
|
+
function: 'handleLocusEvent'
|
|
277
|
+
},
|
|
278
|
+
EVENT_TRIGGERS.MEETING_ADDED,
|
|
279
|
+
{
|
|
280
|
+
meeting,
|
|
281
|
+
type: meeting.type === _MEETING_ ? _JOIN_ : _INCOMING_
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
// Meeting got added but was not found in the collection. It might have got destroyed
|
|
287
|
+
LoggerProxy.logger.warn('Meetings:index#handleLocusEvent --> Created and destroyed meeting object before sending an event');
|
|
288
|
+
}
|
|
289
|
+
});
|
|
297
290
|
}
|
|
291
|
+
else {
|
|
292
|
+
meeting.locusInfo.parse(meeting, data);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
298
295
|
|
|
299
|
-
|
|
296
|
+
/**
|
|
300
297
|
* handles locus events through mercury that are not roap
|
|
301
298
|
* @param {Object} envelope
|
|
302
299
|
* @param {Object} envelope.data
|
|
@@ -305,135 +302,135 @@ export default class Meetings extends WebexPlugin {
|
|
|
305
302
|
* @private
|
|
306
303
|
* @memberof Meetings
|
|
307
304
|
*/
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
305
|
+
handleLocusMercury(envelope) {
|
|
306
|
+
const {data} = envelope;
|
|
307
|
+
const {eventType} = data;
|
|
311
308
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
309
|
+
if (eventType && eventType !== LOCUSEVENT.MESSAGE_ROAP) {
|
|
310
|
+
this.handleLocusEvent(data);
|
|
315
311
|
}
|
|
312
|
+
}
|
|
316
313
|
|
|
317
314
|
|
|
318
|
-
|
|
315
|
+
/**
|
|
319
316
|
* handles mecury offline event
|
|
320
317
|
* @returns {undefined}
|
|
321
318
|
* @private
|
|
322
319
|
* @memberof Meetings
|
|
323
320
|
*/
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
321
|
+
handleMercuryOffline() {
|
|
322
|
+
Trigger.trigger(
|
|
323
|
+
this,
|
|
324
|
+
{
|
|
325
|
+
file: 'meetings/index',
|
|
326
|
+
function: 'handleMercuryOffline'
|
|
327
|
+
},
|
|
328
|
+
EVENT_TRIGGERS.MEETINGS_NETWORK_DISCONNECTED,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
/**
|
|
337
334
|
* registers for locus and roap mercury events
|
|
338
335
|
* @returns {undefined}
|
|
339
336
|
* @private
|
|
340
337
|
* @memberof Meetings
|
|
341
338
|
*/
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
339
|
+
listenForEvents() {
|
|
340
|
+
this.webex.internal.mercury.on(LOCUSEVENT.LOCUS_MERCURY, (envelope) => {
|
|
341
|
+
this.handleLocusMercury(envelope);
|
|
342
|
+
});
|
|
343
|
+
this.webex.internal.mercury.on(ROAP.ROAP_MERCURY, (envelope) => {
|
|
344
|
+
MeetingsUtil.handleRoapMercury(envelope, this.meetingCollection);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
this.webex.internal.mercury.on(ONLINE, () => {
|
|
348
|
+
this.syncMeetings();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
this.webex.internal.mercury.on(OFFLINE, () => {
|
|
352
|
+
this.handleMercuryOffline();
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
360
357
|
* stops listening for locus and roap mercury events
|
|
361
358
|
* @returns {undefined}
|
|
362
359
|
* @private
|
|
363
360
|
* @memberof Meetings
|
|
364
361
|
*/
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
362
|
+
stopListeningForEvents() {
|
|
363
|
+
this.webex.internal.mercury.off(LOCUSEVENT.LOCUS_MERCURY);
|
|
364
|
+
this.webex.internal.mercury.off(ROAP.ROAP_MERCURY);
|
|
365
|
+
this.webex.internal.mercury.off(ONLINE);
|
|
366
|
+
}
|
|
370
367
|
|
|
371
|
-
|
|
368
|
+
/**
|
|
372
369
|
* @returns {undefined}
|
|
373
370
|
* @private
|
|
374
371
|
* @memberof Meetings
|
|
375
372
|
*/
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
373
|
+
onReady() {
|
|
374
|
+
this.webex.once(READY, () => {
|
|
375
|
+
StaticConfig.set(this.config);
|
|
376
|
+
LoggerProxy.set(this.webex.logger);
|
|
377
|
+
LoggerConfig.set(this.config.logging);
|
|
381
378
|
|
|
382
|
-
|
|
379
|
+
/**
|
|
383
380
|
* The MeetingInfo object to interact with server
|
|
384
381
|
* @instance
|
|
385
382
|
* @type {Object}
|
|
386
383
|
* @private
|
|
387
384
|
* @memberof Meetings
|
|
388
385
|
*/
|
|
389
|
-
|
|
390
|
-
|
|
386
|
+
this.meetingInfo = this.config.experimental.enableUnifiedMeetings ? new MeetingInfoV2(this.webex) : new MeetingInfo(this.webex);
|
|
387
|
+
this.personalMeetingRoom = new PersonalMeetingRoom({meetingInfo: this.meetingInfo}, {parent: this.webex});
|
|
391
388
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
389
|
+
Trigger.trigger(
|
|
390
|
+
this,
|
|
391
|
+
{
|
|
392
|
+
file: 'meetings',
|
|
393
|
+
function: 'onReady'
|
|
394
|
+
},
|
|
395
|
+
EVENT_TRIGGERS.MEETINGS_READY
|
|
396
|
+
);
|
|
397
|
+
});
|
|
398
|
+
}
|
|
402
399
|
|
|
403
|
-
|
|
400
|
+
/**
|
|
404
401
|
* API to toggle unified meetings
|
|
405
402
|
* @param {Boolean} changeState
|
|
406
403
|
* @private
|
|
407
404
|
* @memberof Meetings
|
|
408
405
|
* @returns {undefined}
|
|
409
406
|
*/
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
if (this.config?.experimental?.enableUnifiedMeetings !== changeState) {
|
|
415
|
-
this.config.experimental.enableUnifiedMeetings = changeState;
|
|
416
|
-
this.meetingInfo = changeState ? new MeetingInfoV2(this.webex) : new MeetingInfo(this.webex);
|
|
417
|
-
}
|
|
407
|
+
_toggleUnifiedMeetings(changeState) {
|
|
408
|
+
if (typeof changeState !== 'boolean') {
|
|
409
|
+
return;
|
|
418
410
|
}
|
|
411
|
+
if (this.config?.experimental?.enableUnifiedMeetings !== changeState) {
|
|
412
|
+
this.config.experimental.enableUnifiedMeetings = changeState;
|
|
413
|
+
this.meetingInfo = changeState ? new MeetingInfoV2(this.webex) : new MeetingInfo(this.webex);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
419
416
|
|
|
420
|
-
|
|
417
|
+
/**
|
|
421
418
|
* API to toggle starting adhoc meeting
|
|
422
419
|
* @param {Boolean} changeState
|
|
423
420
|
* @private
|
|
424
421
|
* @memberof Meetings
|
|
425
422
|
* @returns {undefined}
|
|
426
423
|
*/
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
424
|
+
_toggleAdhocMeetings(changeState) {
|
|
425
|
+
if (typeof changeState !== 'boolean') {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (this.config?.experimental?.enableAdhocMeetings !== changeState) {
|
|
429
|
+
this.config.experimental.enableAdhocMeetings = changeState;
|
|
434
430
|
}
|
|
431
|
+
}
|
|
435
432
|
|
|
436
|
-
|
|
433
|
+
/**
|
|
437
434
|
* Explicitly sets up the meetings plugin by registering
|
|
438
435
|
* the device, connecting to mercury, and listening for locus events.
|
|
439
436
|
*
|
|
@@ -441,61 +438,61 @@ export default class Meetings extends WebexPlugin {
|
|
|
441
438
|
* @public
|
|
442
439
|
* @memberof Meetings
|
|
443
440
|
*/
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
441
|
+
register() {
|
|
442
|
+
if (!this.webex.canAuthorize) {
|
|
443
|
+
LoggerProxy.logger.error('Meetings:index#register --> ERROR, Unable to register, SDK cannot authorize');
|
|
447
444
|
|
|
448
|
-
|
|
449
|
-
|
|
445
|
+
return Promise.reject(new Error('SDK cannot authorize'));
|
|
446
|
+
}
|
|
450
447
|
|
|
451
448
|
|
|
452
|
-
|
|
453
|
-
|
|
449
|
+
if (this.registered) {
|
|
450
|
+
LoggerProxy.logger.info('Meetings:index#register --> INFO, Meetings plugin already registered');
|
|
454
451
|
|
|
455
|
-
|
|
456
|
-
|
|
452
|
+
return Promise.resolve();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return Promise.all([
|
|
456
|
+
this.fetchUserPreferredWebexSite(),
|
|
457
|
+
this.getGeoHint(),
|
|
458
|
+
this.startReachability().catch((error) => {
|
|
459
|
+
LoggerProxy.logger.error(`Meetings:index#register --> GDM error, ${error.message}`);
|
|
460
|
+
}),
|
|
461
|
+
this.webex.internal.device.register()
|
|
462
|
+
.then(() => LoggerProxy.logger.info(`Meetings:index#register --> INFO, Device registered ${this.webex.internal.device.url}`))
|
|
463
|
+
.then(() => this.webex.internal.mercury.connect()),
|
|
464
|
+
MeetingsUtil.checkH264Support.call(this)
|
|
465
|
+
]).then(() => {
|
|
466
|
+
this.listenForEvents();
|
|
467
|
+
Trigger.trigger(
|
|
468
|
+
this,
|
|
469
|
+
{
|
|
470
|
+
file: 'meetings',
|
|
471
|
+
function: 'register'
|
|
472
|
+
},
|
|
473
|
+
EVENT_TRIGGERS.MEETINGS_REGISTERED
|
|
474
|
+
);
|
|
475
|
+
this.registered = true;
|
|
476
|
+
Metrics.sendBehavioralMetric(
|
|
477
|
+
BEHAVIORAL_METRICS.MEETINGS_REGISTRATION_SUCCESS,
|
|
478
|
+
);
|
|
479
|
+
})
|
|
480
|
+
.catch((error) => {
|
|
481
|
+
LoggerProxy.logger.error(`Meetings:index#register --> ERROR, Unable to register, ${error.message}`);
|
|
457
482
|
|
|
458
|
-
return Promise.all([
|
|
459
|
-
this.fetchUserPreferredWebexSite(),
|
|
460
|
-
this.getGeoHint(),
|
|
461
|
-
this.startReachability().catch((error) => {
|
|
462
|
-
LoggerProxy.logger.error(`Meetings:index#register --> GDM error, ${error.message}`);
|
|
463
|
-
}),
|
|
464
|
-
this.webex.internal.device.register()
|
|
465
|
-
.then(() => LoggerProxy.logger.info(`Meetings:index#register --> INFO, Device registered ${this.webex.internal.device.url}`))
|
|
466
|
-
.then(() => this.webex.internal.mercury.connect()),
|
|
467
|
-
MeetingsUtil.checkH264Support.call(this)
|
|
468
|
-
]).then(() => {
|
|
469
|
-
this.listenForEvents();
|
|
470
|
-
Trigger.trigger(
|
|
471
|
-
this,
|
|
472
|
-
{
|
|
473
|
-
file: 'meetings',
|
|
474
|
-
function: 'register'
|
|
475
|
-
},
|
|
476
|
-
EVENT_TRIGGERS.MEETINGS_REGISTERED
|
|
477
|
-
);
|
|
478
|
-
this.registered = true;
|
|
479
483
|
Metrics.sendBehavioralMetric(
|
|
480
|
-
BEHAVIORAL_METRICS.
|
|
484
|
+
BEHAVIORAL_METRICS.MEETINGS_REGISTRATION_FAILED,
|
|
485
|
+
{
|
|
486
|
+
reason: error.message,
|
|
487
|
+
stack: error.stack
|
|
488
|
+
}
|
|
481
489
|
);
|
|
482
|
-
})
|
|
483
|
-
.catch((error) => {
|
|
484
|
-
LoggerProxy.logger.error(`Meetings:index#register --> ERROR, Unable to register, ${error.message}`);
|
|
485
|
-
|
|
486
|
-
Metrics.sendBehavioralMetric(
|
|
487
|
-
BEHAVIORAL_METRICS.MEETINGS_REGISTRATION_FAILED,
|
|
488
|
-
{
|
|
489
|
-
reason: error.message,
|
|
490
|
-
stack: error.stack
|
|
491
|
-
}
|
|
492
|
-
);
|
|
493
490
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
491
|
+
return Promise.reject(error);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
497
494
|
|
|
498
|
-
|
|
495
|
+
/**
|
|
499
496
|
* Explicitly tears down the meetings plugin by deregistering
|
|
500
497
|
* the device, disconnecting from mercury, and stops listening to locus events
|
|
501
498
|
*
|
|
@@ -503,31 +500,31 @@ export default class Meetings extends WebexPlugin {
|
|
|
503
500
|
* @public
|
|
504
501
|
* @memberof Meetings
|
|
505
502
|
*/
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
503
|
+
unregister() {
|
|
504
|
+
if (!this.registered) {
|
|
505
|
+
LoggerProxy.logger.info('Meetings:index#unregister --> INFO, Meetings plugin already unregistered');
|
|
509
506
|
|
|
510
|
-
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
this.stopListeningForEvents();
|
|
514
|
-
|
|
515
|
-
return this.webex.internal.mercury.disconnect()
|
|
516
|
-
.then(() => this.webex.internal.device.unregister())
|
|
517
|
-
.then(() => {
|
|
518
|
-
Trigger.trigger(
|
|
519
|
-
this,
|
|
520
|
-
{
|
|
521
|
-
file: 'meetings',
|
|
522
|
-
function: 'unregister'
|
|
523
|
-
},
|
|
524
|
-
EVENT_TRIGGERS.MEETINGS_UNREGISTERED
|
|
525
|
-
);
|
|
526
|
-
this.registered = false;
|
|
527
|
-
});
|
|
507
|
+
return Promise.resolve();
|
|
528
508
|
}
|
|
529
509
|
|
|
530
|
-
|
|
510
|
+
this.stopListeningForEvents();
|
|
511
|
+
|
|
512
|
+
return this.webex.internal.mercury.disconnect()
|
|
513
|
+
.then(() => this.webex.internal.device.unregister())
|
|
514
|
+
.then(() => {
|
|
515
|
+
Trigger.trigger(
|
|
516
|
+
this,
|
|
517
|
+
{
|
|
518
|
+
file: 'meetings',
|
|
519
|
+
function: 'unregister'
|
|
520
|
+
},
|
|
521
|
+
EVENT_TRIGGERS.MEETINGS_UNREGISTERED
|
|
522
|
+
);
|
|
523
|
+
this.registered = false;
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
531
528
|
* Uploads logs to the webex services for tracking
|
|
532
529
|
* @param {Object} [options={}]
|
|
533
530
|
* @param {String} [options.callStart] Call Start Time
|
|
@@ -539,126 +536,126 @@ export default class Meetings extends WebexPlugin {
|
|
|
539
536
|
* @param {String} [options.orgId] org id
|
|
540
537
|
* @returns {String} feedback ID logs were submitted under
|
|
541
538
|
*/
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
return this.loggerRequest.uploadLogs(options)
|
|
546
|
-
.then((uploadResult) => {
|
|
547
|
-
LoggerProxy.logger.info('Meetings:index#uploadLogs --> Upload logs for meeting completed.', uploadResult);
|
|
548
|
-
Trigger.trigger(
|
|
549
|
-
this,
|
|
550
|
-
{
|
|
551
|
-
file: 'meetings',
|
|
552
|
-
function: 'uploadLogs'
|
|
553
|
-
},
|
|
554
|
-
EVENT_TRIGGERS.MEETING_LOG_UPLOAD_SUCCESS,
|
|
555
|
-
{
|
|
556
|
-
meetingId: options.meetingId,
|
|
557
|
-
details: uploadResult
|
|
558
|
-
}
|
|
559
|
-
);
|
|
560
|
-
})
|
|
561
|
-
.catch((uploadError) => {
|
|
562
|
-
LoggerProxy.logger.error('Meetings:index#uploadLogs --> Unable to upload logs for meeting', uploadError);
|
|
563
|
-
Trigger.trigger(
|
|
564
|
-
this,
|
|
565
|
-
{
|
|
566
|
-
file: 'meetings',
|
|
567
|
-
function: 'uploadLogs'
|
|
568
|
-
},
|
|
569
|
-
EVENT_TRIGGERS.MEETING_LOG_UPLOAD_FAILURE,
|
|
570
|
-
{
|
|
571
|
-
meetingId: options.meetingId,
|
|
572
|
-
reason: uploadError
|
|
573
|
-
}
|
|
574
|
-
);
|
|
575
|
-
|
|
576
|
-
Metrics.sendBehavioralMetric(
|
|
577
|
-
BEHAVIORAL_METRICS.UPLOAD_LOGS_FAILURE,
|
|
578
|
-
{
|
|
579
|
-
meetingId: options.meetingsId,
|
|
580
|
-
reason: uploadError.message,
|
|
581
|
-
stack: uploadError.stack,
|
|
582
|
-
code: uploadError.code
|
|
583
|
-
}
|
|
584
|
-
);
|
|
585
|
-
});
|
|
586
|
-
}
|
|
539
|
+
uploadLogs(options = {}) {
|
|
540
|
+
LoggerProxy.logger.info('Meetings:index#uploadLogs --> uploading logs');
|
|
587
541
|
|
|
588
|
-
|
|
542
|
+
return this.loggerRequest.uploadLogs(options)
|
|
543
|
+
.then((uploadResult) => {
|
|
544
|
+
LoggerProxy.logger.info('Meetings:index#uploadLogs --> Upload logs for meeting completed.', uploadResult);
|
|
545
|
+
Trigger.trigger(
|
|
546
|
+
this,
|
|
547
|
+
{
|
|
548
|
+
file: 'meetings',
|
|
549
|
+
function: 'uploadLogs'
|
|
550
|
+
},
|
|
551
|
+
EVENT_TRIGGERS.MEETING_LOG_UPLOAD_SUCCESS,
|
|
552
|
+
{
|
|
553
|
+
meetingId: options.meetingId,
|
|
554
|
+
details: uploadResult
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
})
|
|
558
|
+
.catch((uploadError) => {
|
|
559
|
+
LoggerProxy.logger.error('Meetings:index#uploadLogs --> Unable to upload logs for meeting', uploadError);
|
|
560
|
+
Trigger.trigger(
|
|
561
|
+
this,
|
|
562
|
+
{
|
|
563
|
+
file: 'meetings',
|
|
564
|
+
function: 'uploadLogs'
|
|
565
|
+
},
|
|
566
|
+
EVENT_TRIGGERS.MEETING_LOG_UPLOAD_FAILURE,
|
|
567
|
+
{
|
|
568
|
+
meetingId: options.meetingId,
|
|
569
|
+
reason: uploadError
|
|
570
|
+
}
|
|
571
|
+
);
|
|
572
|
+
|
|
573
|
+
Metrics.sendBehavioralMetric(
|
|
574
|
+
BEHAVIORAL_METRICS.UPLOAD_LOGS_FAILURE,
|
|
575
|
+
{
|
|
576
|
+
meetingId: options.meetingsId,
|
|
577
|
+
reason: uploadError.message,
|
|
578
|
+
stack: uploadError.stack,
|
|
579
|
+
code: uploadError.code
|
|
580
|
+
}
|
|
581
|
+
);
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
589
586
|
* initializes the reachability instance for Meetings
|
|
590
587
|
* @returns {undefined}
|
|
591
588
|
* @public
|
|
592
589
|
* @memberof Meetings
|
|
593
590
|
*/
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
591
|
+
setReachability() {
|
|
592
|
+
this.reachability = new Reachability(this.webex);
|
|
593
|
+
}
|
|
597
594
|
|
|
598
|
-
|
|
595
|
+
/**
|
|
599
596
|
* gets the reachability instance for Meetings
|
|
600
597
|
* @returns {Reachability}
|
|
601
598
|
* @public
|
|
602
599
|
* @memberof Meetings
|
|
603
600
|
*/
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
601
|
+
getReachability() {
|
|
602
|
+
return this.reachability;
|
|
603
|
+
}
|
|
607
604
|
|
|
608
|
-
|
|
605
|
+
/**
|
|
609
606
|
* initializes and starts gathering reachability for Meetings
|
|
610
607
|
* @returns {Promise}
|
|
611
608
|
* @public
|
|
612
609
|
* @memberof Meetings
|
|
613
610
|
*/
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
return this.getReachability().gatherReachability();
|
|
611
|
+
startReachability() {
|
|
612
|
+
if (!this.reachability) {
|
|
613
|
+
this.setReachability();
|
|
620
614
|
}
|
|
621
615
|
|
|
622
|
-
|
|
616
|
+
return this.getReachability().gatherReachability();
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
623
620
|
* Get geoHint for info for meetings
|
|
624
621
|
* @returns {Promise}
|
|
625
622
|
* @private
|
|
626
623
|
* @memberof Meetings
|
|
627
624
|
*/
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
625
|
+
getGeoHint() {
|
|
626
|
+
return this.request.fetchGeoHint().then((res) => {
|
|
627
|
+
this.geoHintInfo = res;
|
|
628
|
+
});
|
|
629
|
+
}
|
|
633
630
|
|
|
634
|
-
|
|
631
|
+
/**
|
|
635
632
|
* Fetch user preferred webex site information
|
|
636
633
|
* This also has other infomation about the user
|
|
637
634
|
* @returns {Promise}
|
|
638
635
|
* @private
|
|
639
636
|
* @memberof Meetings
|
|
640
637
|
*/
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
638
|
+
fetchUserPreferredWebexSite() {
|
|
639
|
+
return this.request.fetchLoginUserInformation().then((res) => {
|
|
640
|
+
if (res && res.userPreferences) {
|
|
641
|
+
this.preferredWebexSite = MeetingsUtil.parseUserPreferences(res?.userPreferences);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
}
|
|
648
645
|
|
|
649
646
|
|
|
650
|
-
|
|
647
|
+
/**
|
|
651
648
|
* gets the personal meeting room instance, for saved PMR values for this user
|
|
652
649
|
* @returns {PersonalMeetingRoom}
|
|
653
650
|
* @public
|
|
654
651
|
* @memberof Meetings
|
|
655
652
|
*/
|
|
656
653
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
654
|
+
getPersonalMeetingRoom() {
|
|
655
|
+
return this.personalMeetingRoom;
|
|
656
|
+
}
|
|
660
657
|
|
|
661
|
-
|
|
658
|
+
/**
|
|
662
659
|
* @param {Meeting} meeting
|
|
663
660
|
* @param {Object} reason
|
|
664
661
|
* @param {String} type
|
|
@@ -666,24 +663,24 @@ export default class Meetings extends WebexPlugin {
|
|
|
666
663
|
* @private
|
|
667
664
|
* @memberof Meetings
|
|
668
665
|
*/
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
666
|
+
destroy(meeting, reason) {
|
|
667
|
+
MeetingUtil.cleanUp(meeting);
|
|
668
|
+
this.meetingCollection.delete(meeting.id);
|
|
669
|
+
Trigger.trigger(
|
|
670
|
+
this,
|
|
671
|
+
{
|
|
672
|
+
file: 'meetings',
|
|
673
|
+
function: 'destroy'
|
|
674
|
+
},
|
|
675
|
+
EVENT_TRIGGERS.MEETING_REMOVED,
|
|
676
|
+
{
|
|
677
|
+
meetingId: meeting.id,
|
|
678
|
+
reason
|
|
679
|
+
}
|
|
680
|
+
);
|
|
681
|
+
}
|
|
685
682
|
|
|
686
|
-
|
|
683
|
+
/**
|
|
687
684
|
* Create a meeting.
|
|
688
685
|
* @param {string} destination - sipURL, spaceId, phonenumber, or locus object}
|
|
689
686
|
* @param {string} [type] - the optional specified type, such as locusId
|
|
@@ -691,182 +688,182 @@ export default class Meetings extends WebexPlugin {
|
|
|
691
688
|
* @public
|
|
692
689
|
* @memberof Meetings
|
|
693
690
|
*/
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
}
|
|
691
|
+
create(destination, type = null) {
|
|
692
|
+
// TODO: type should be from a dictionary
|
|
693
|
+
|
|
694
|
+
// Validate meeting information based on the provided destination and
|
|
695
|
+
// type. This must be performed prior to determining if the meeting is
|
|
696
|
+
// found in the collection, as we mutate the destination for hydra person
|
|
697
|
+
// id values.
|
|
698
|
+
return this.meetingInfo.fetchInfoOptions(destination, type)
|
|
699
|
+
// Catch a failure to fetch info options.
|
|
700
|
+
.catch((error) => {
|
|
701
|
+
LoggerProxy.logger.info(`Meetings:index#create --> INFO, unable to determine info options: ${error.message}`);
|
|
702
|
+
})
|
|
703
|
+
.then((options = {}) => {
|
|
704
|
+
// Normalize the destination.
|
|
705
|
+
const targetDest = options.destination || destination;
|
|
706
|
+
|
|
707
|
+
// check for the conversation URL then sip Url
|
|
708
|
+
let meeting = null;
|
|
709
|
+
|
|
710
|
+
if (type === _CONVERSATION_URL_ || options.type === _CONVERSATION_URL_) {
|
|
711
|
+
const foundMeeting = this.meetingCollection.getByKey(CONVERSATION_URL, targetDest);
|
|
712
|
+
|
|
713
|
+
if (foundMeeting) {
|
|
714
|
+
const foundMeetingIsNotCalendarMeeting = !foundMeeting.locusInfo.scheduledMeeting;
|
|
715
|
+
|
|
716
|
+
// If the found meeting is not a calendar meeting, return that meeting.
|
|
717
|
+
// This allows for the creation of instant-meetings when calendar meetings are present.
|
|
718
|
+
if (foundMeetingIsNotCalendarMeeting) {
|
|
719
|
+
meeting = foundMeeting;
|
|
724
720
|
}
|
|
725
721
|
}
|
|
722
|
+
}
|
|
726
723
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
724
|
+
// Attempt to collect the meeting if it exists.
|
|
725
|
+
if (!meeting) {
|
|
726
|
+
meeting = this.meetingCollection.getByKey(SIP_URI, targetDest);
|
|
727
|
+
}
|
|
731
728
|
|
|
732
729
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
// Return the newly created meeting.
|
|
773
|
-
return Promise.resolve(createdMeeting);
|
|
774
|
-
});
|
|
775
|
-
}
|
|
730
|
+
// Validate if a meeting was found.
|
|
731
|
+
if (!meeting) {
|
|
732
|
+
// Create a meeting based on the normalized destination and type.
|
|
733
|
+
return this.createMeeting(targetDest, type)
|
|
734
|
+
.then((createdMeeting) => {
|
|
735
|
+
// If the meeting was successfully created.
|
|
736
|
+
if (createdMeeting && createdMeeting.on) {
|
|
737
|
+
// Create a destruction event for the meeting.
|
|
738
|
+
createdMeeting.on(EVENTS.DESTROY_MEETING, (payload) => {
|
|
739
|
+
if (this.config.autoUploadLogs) {
|
|
740
|
+
this.uploadLogs({
|
|
741
|
+
callStart: createdMeeting.locusInfo?.fullState?.lastActive,
|
|
742
|
+
correlationId: createdMeeting.correlationId,
|
|
743
|
+
feedbackId: createdMeeting.correlationId,
|
|
744
|
+
locusId: createdMeeting.locusId,
|
|
745
|
+
meetingId: createdMeeting.locusInfo?.info?.webExMeetingId
|
|
746
|
+
}).then(() => this.destroy(createdMeeting, payload.reason));
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
this.destroy(createdMeeting, payload.reason);
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
createdMeeting.on(EVENTS.REQUEST_UPLOAD_LOGS, (meetingInstance) => {
|
|
754
|
+
if (this.config.autoUploadLogs) {
|
|
755
|
+
this.uploadLogs({
|
|
756
|
+
callStart: meetingInstance?.locusInfo?.fullState?.lastActive,
|
|
757
|
+
correlationId: meetingInstance.correlationId,
|
|
758
|
+
feedbackId: meetingInstance.correlationId,
|
|
759
|
+
locusId: meetingInstance.locusId,
|
|
760
|
+
meetingId: meetingInstance.locusInfo?.info?.webExMeetingId
|
|
761
|
+
});
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
LoggerProxy.logger.error(`Meetings:index#create --> ERROR, meeting does not have on method, will not be destroyed, meeting cleanup impossible for meeting: ${meeting}`);
|
|
767
|
+
}
|
|
776
768
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
769
|
+
// Return the newly created meeting.
|
|
770
|
+
return Promise.resolve(createdMeeting);
|
|
771
|
+
});
|
|
772
|
+
}
|
|
781
773
|
|
|
782
|
-
|
|
774
|
+
// Return the existing meeting.
|
|
775
|
+
return Promise.resolve(meeting);
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/**
|
|
783
780
|
* @param {String} destination see create()
|
|
784
781
|
* @param {String} type see create()
|
|
785
782
|
* @returns {Promise} a new meeting instance complete with meeting info and destination
|
|
786
783
|
* @private
|
|
787
784
|
* @memberof Meetings
|
|
788
785
|
*/
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
786
|
+
async createMeeting(destination, type = null) {
|
|
787
|
+
const meeting = new Meeting(
|
|
788
|
+
{
|
|
789
|
+
userId: this.webex.internal.device.userId,
|
|
790
|
+
deviceUrl: this.webex.internal.device.url,
|
|
791
|
+
orgId: this.webex.internal.device.orgId,
|
|
792
|
+
roapSeq: 0,
|
|
793
|
+
locus: type === _LOCUS_ID_ ? destination : null, // pass the locus object if present
|
|
794
|
+
meetingInfoProvider: this.meetingInfo,
|
|
795
|
+
destination,
|
|
796
|
+
destinationType: type,
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
parent: this.webex
|
|
800
|
+
}
|
|
801
|
+
);
|
|
805
802
|
|
|
806
|
-
|
|
803
|
+
this.meetingCollection.set(meeting);
|
|
807
804
|
|
|
808
|
-
|
|
809
|
-
|
|
805
|
+
try {
|
|
806
|
+
await meeting.fetchMeetingInfo({});
|
|
807
|
+
}
|
|
808
|
+
catch (err) {
|
|
809
|
+
if (!(err instanceof CaptchaError) && !(err instanceof PasswordError)) {
|
|
810
|
+
// if there is no meeting info we assume its a 1:1 call or wireless share
|
|
811
|
+
LoggerProxy.logger.info(`Meetings:index#createMeeting --> Info Unable to fetch meeting info for ${destination}.`);
|
|
812
|
+
LoggerProxy.logger.info('Meetings:index#createMeeting --> Info assuming this destination is a 1:1 or wireless share');
|
|
810
813
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
814
|
+
LoggerProxy.logger.debug(`Meetings:index#createMeeting --> Debug ${err} fetching /meetingInfo for creation.`);
|
|
815
|
+
}
|
|
816
|
+
finally {
|
|
817
|
+
// For type LOCUS_ID we need to parse the locus object to get the information
|
|
818
|
+
// about the caller and callee
|
|
819
|
+
// Meeting Added event will be created in `handleLocusEvent`
|
|
820
|
+
if (type !== _LOCUS_ID_) {
|
|
821
|
+
if (!meeting.sipUri) {
|
|
822
|
+
meeting.setSipUri(destination);
|
|
816
823
|
}
|
|
817
|
-
LoggerProxy.logger.debug(`Meetings:index#createMeeting --> Debug ${err} fetching /meetingInfo for creation.`);
|
|
818
|
-
}
|
|
819
|
-
finally {
|
|
820
|
-
// For type LOCUS_ID we need to parse the locus object to get the information
|
|
821
|
-
// about the caller and callee
|
|
822
|
-
// Meeting Added event will be created in `handleLocusEvent`
|
|
823
|
-
if (type !== _LOCUS_ID_) {
|
|
824
|
-
if (!meeting.sipUri) {
|
|
825
|
-
meeting.setSipUri(destination);
|
|
826
|
-
}
|
|
827
824
|
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
// We typically shouldn't need to trigger both and event and return a promise.
|
|
832
|
-
// Is this a special case? We want to make the public API usage as simple as possible.
|
|
833
|
-
Trigger.trigger(
|
|
834
|
-
this,
|
|
835
|
-
{
|
|
836
|
-
file: 'meetings',
|
|
837
|
-
function: 'createMeeting'
|
|
838
|
-
},
|
|
839
|
-
EVENT_TRIGGERS.MEETING_ADDED,
|
|
840
|
-
{
|
|
841
|
-
meeting,
|
|
842
|
-
type: meetingAddedType
|
|
843
|
-
}
|
|
844
|
-
);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
825
|
+
// TODO: check if we have to move this to parser
|
|
826
|
+
const meetingAddedType = MeetingsUtil.getMeetingAddedType(type);
|
|
847
827
|
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
// and its corresponding service so that developers
|
|
864
|
-
// need only sipURL or spaceID to get a meeting
|
|
865
|
-
// and its ID, but have the option to use createWithType()
|
|
866
|
-
// and specify those types to get meetingInfo
|
|
828
|
+
// We typically shouldn't need to trigger both and event and return a promise.
|
|
829
|
+
// Is this a special case? We want to make the public API usage as simple as possible.
|
|
830
|
+
Trigger.trigger(
|
|
831
|
+
this,
|
|
832
|
+
{
|
|
833
|
+
file: 'meetings',
|
|
834
|
+
function: 'createMeeting'
|
|
835
|
+
},
|
|
836
|
+
EVENT_TRIGGERS.MEETING_ADDED,
|
|
837
|
+
{
|
|
838
|
+
meeting,
|
|
839
|
+
type: meetingAddedType
|
|
840
|
+
}
|
|
841
|
+
);
|
|
842
|
+
}
|
|
867
843
|
}
|
|
868
844
|
|
|
869
|
-
|
|
845
|
+
return meeting;
|
|
846
|
+
|
|
847
|
+
// Create the meeting calling the necessary service endpoints.
|
|
848
|
+
|
|
849
|
+
// Internally, there are many more destinations:
|
|
850
|
+
//
|
|
851
|
+
// - locusID
|
|
852
|
+
// - meetingURL
|
|
853
|
+
// - globalMeetingID, e.g, *00*meetingID
|
|
854
|
+
// - meetingID
|
|
855
|
+
// - meetingURL
|
|
856
|
+
// - PSTN
|
|
857
|
+
// - phone number
|
|
858
|
+
//
|
|
859
|
+
// Our job is to determine the appropriate one
|
|
860
|
+
// and its corresponding service so that developers
|
|
861
|
+
// need only sipURL or spaceID to get a meeting
|
|
862
|
+
// and its ID, but have the option to use createWithType()
|
|
863
|
+
// and specify those types to get meetingInfo
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/**
|
|
870
867
|
* get a specifc meeting given it's type matched to the value, i.e., locus url
|
|
871
868
|
* @param {String} type
|
|
872
869
|
* @param {Object} value
|
|
@@ -874,11 +871,11 @@ export default class Meetings extends WebexPlugin {
|
|
|
874
871
|
* @public
|
|
875
872
|
* @memberof Meetings
|
|
876
873
|
*/
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
874
|
+
getMeetingByType(type, value) {
|
|
875
|
+
return this.meetingCollection.getByKey(type, value);
|
|
876
|
+
}
|
|
880
877
|
|
|
881
|
-
|
|
878
|
+
/**
|
|
882
879
|
* Get all meetings.
|
|
883
880
|
* @param {object} options
|
|
884
881
|
* @param {object} options.startDate - get meetings after this start date
|
|
@@ -887,47 +884,47 @@ export default class Meetings extends WebexPlugin {
|
|
|
887
884
|
* @public
|
|
888
885
|
* @memberof Meetings
|
|
889
886
|
*/
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
887
|
+
getAllMeetings(options = {}) {
|
|
888
|
+
// Options may include other parameters to filter this collection
|
|
889
|
+
// of meetings.
|
|
890
|
+
return this.meetingCollection.getAll(options);
|
|
891
|
+
}
|
|
895
892
|
|
|
896
|
-
|
|
893
|
+
/**
|
|
897
894
|
* syncs all the meeting from server
|
|
898
895
|
* @returns {undefined}
|
|
899
896
|
* @public
|
|
900
897
|
* @memberof Meetings
|
|
901
898
|
*/
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
});
|
|
899
|
+
syncMeetings() {
|
|
900
|
+
return this.request.getActiveMeetings().then((locusArray) => {
|
|
901
|
+
const activeLocusUrl = [];
|
|
902
|
+
|
|
903
|
+
if (locusArray?.loci && locusArray.loci.length > 0) {
|
|
904
|
+
locusArray.loci.forEach((locus) => {
|
|
905
|
+
activeLocusUrl.push(locus.url);
|
|
906
|
+
this.handleLocusEvent({
|
|
907
|
+
locus,
|
|
908
|
+
locusUrl: locus.url
|
|
913
909
|
});
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
const meetingsCollection = this.meetingCollection.getAll();
|
|
913
|
+
|
|
914
|
+
if (Object.keys(meetingsCollection).length > 0) {
|
|
915
|
+
// Some time the mercury event is missed after mercury reconnect
|
|
916
|
+
// if sync returns no locus then clear all the meetings
|
|
917
|
+
for (const meeting of Object.values(meetingsCollection)) {
|
|
918
|
+
if (!activeLocusUrl.includes(meeting.locusUrl)) {
|
|
919
|
+
// destroy function also uploads logs
|
|
920
|
+
this.destroy(meeting, MEETING_REMOVED_REASON.NO_MEETINGS_TO_SYNC);
|
|
925
921
|
}
|
|
926
922
|
}
|
|
927
|
-
}
|
|
928
|
-
}
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
}
|
|
929
926
|
|
|
930
|
-
|
|
927
|
+
/**
|
|
931
928
|
* Get all scheduled meetings.
|
|
932
929
|
* @param {object} options
|
|
933
930
|
* @param {object} options.startDate - get meetings after this start date
|
|
@@ -935,35 +932,35 @@ export default class Meetings extends WebexPlugin {
|
|
|
935
932
|
* @returns {Object} All scheduled meetings.
|
|
936
933
|
* @memberof Meetings
|
|
937
934
|
*/
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
935
|
+
getScheduledMeetings() {
|
|
936
|
+
return this.meetingCollection.getAll({scheduled: true});
|
|
937
|
+
}
|
|
941
938
|
|
|
942
|
-
|
|
939
|
+
/**
|
|
943
940
|
* Get the logger instance for plugin-meetings
|
|
944
941
|
* @returns {Logger}
|
|
945
942
|
*/
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
943
|
+
getLogger() {
|
|
944
|
+
return LoggerProxy.get();
|
|
945
|
+
}
|
|
949
946
|
|
|
950
|
-
|
|
947
|
+
/**
|
|
951
948
|
* Get the Stats Analyzer singleton
|
|
952
949
|
* @returns {StatsAnalyzer}
|
|
953
950
|
* @public
|
|
954
951
|
* @memberof Meetings
|
|
955
952
|
*/
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
953
|
+
getAnalyzer() {
|
|
954
|
+
return StatsAnalyzer;
|
|
955
|
+
}
|
|
959
956
|
|
|
960
|
-
|
|
957
|
+
/**
|
|
961
958
|
* Get the Stats Calculator singleton
|
|
962
959
|
* @returns {StatsCalculator}
|
|
963
960
|
* @public
|
|
964
961
|
* @memberof Meetings
|
|
965
962
|
*/
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
963
|
+
getCalculator() {
|
|
964
|
+
return StatsCalculator;
|
|
965
|
+
}
|
|
969
966
|
}
|