@webex/plugin-meetings 3.12.0-next.55 → 3.12.0-next.57
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/aiEnableRequest/index.js +1 -1
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/hashTree/hashTreeParser.js +124 -47
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/meeting/index.js +1 -1
- package/dist/meeting/index.js.map +1 -1
- package/dist/meetings/index.js +3 -1
- package/dist/meetings/index.js.map +1 -1
- package/dist/meetings/util.js +14 -2
- package/dist/meetings/util.js.map +1 -1
- package/dist/types/hashTree/hashTreeParser.d.ts +9 -0
- package/dist/webinar/index.js +1 -1
- package/package.json +1 -1
- package/src/hashTree/hashTreeParser.ts +68 -0
- package/src/meeting/index.ts +2 -1
- package/src/meetings/index.ts +4 -1
- package/src/meetings/util.ts +17 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +253 -0
- package/test/unit/spec/meeting/index.js +16 -0
- package/test/unit/spec/meetings/index.js +24 -0
- package/test/unit/spec/meetings/utils.js +28 -0
package/dist/meetings/util.js
CHANGED
|
@@ -317,6 +317,18 @@ MeetingsUtil.isSelfMovedOrBreakoutEnded = function (locus) {
|
|
|
317
317
|
return isSelfLeftMoved || isBreakoutEnded;
|
|
318
318
|
};
|
|
319
319
|
|
|
320
|
+
/**
|
|
321
|
+
* Checks if a locus is a 1:1 call using locus.fullState.type.
|
|
322
|
+
* Returns true when fullState.type is CALL, SIP_BRIDGE, or SPACE_SHARE.
|
|
323
|
+
* @param {Object} locus locus data
|
|
324
|
+
* @returns {boolean}
|
|
325
|
+
*/
|
|
326
|
+
MeetingsUtil.isOneOnOneCall = function (locus) {
|
|
327
|
+
var _locus$fullState3;
|
|
328
|
+
var fullStateType = locus === null || locus === void 0 ? void 0 : (_locus$fullState3 = locus.fullState) === null || _locus$fullState3 === void 0 ? void 0 : _locus$fullState3.type;
|
|
329
|
+
return fullStateType === _constants._CALL_ || fullStateType === _constants._SIP_BRIDGE_ || fullStateType === _constants._SPACE_SHARE_;
|
|
330
|
+
};
|
|
331
|
+
|
|
320
332
|
/**
|
|
321
333
|
* get self device joined status from locus data
|
|
322
334
|
* @param {Object} meeting current meeting data
|
|
@@ -352,8 +364,8 @@ MeetingsUtil.isBreakoutLocusDTO = function (newLocus) {
|
|
|
352
364
|
* @private
|
|
353
365
|
*/
|
|
354
366
|
MeetingsUtil.isValidBreakoutLocus = function (locus) {
|
|
355
|
-
var _locus$
|
|
356
|
-
var inActiveStatus = (locus === null || locus === void 0 ? void 0 : (_locus$
|
|
367
|
+
var _locus$fullState4, _locus$self3;
|
|
368
|
+
var inActiveStatus = (locus === null || locus === void 0 ? void 0 : (_locus$fullState4 = locus.fullState) === null || _locus$fullState4 === void 0 ? void 0 : _locus$fullState4.state) === _constants.LOCUS.STATE.INACTIVE;
|
|
357
369
|
var isLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(locus);
|
|
358
370
|
var selfJoined = ((_locus$self3 = locus.self) === null || _locus$self3 === void 0 ? void 0 : _locus$self3.state) === _constants._JOINED_;
|
|
359
371
|
return isLocusAsBreakout && !inActiveStatus && selfJoined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_constants","require","_loggerProxy","_interopRequireDefault","_triggerProxy","_constants2","_metrics","_meetings","_types","MeetingsUtil","getMeetingAddedType","type","DESTINATION_TYPE","LOCUS_ID","_INCOMING_","_CREATED_","handleRoapMercury","envelope","meetingCollection","data","eventType","LOCUSEVENT","MESSAGE_ROAP","meeting","getByKey","MEETING_KEY","CORRELATION_ID","correlationId","_data$message","message","seq","messageType","tieBreaker","errorType","errorCause","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","ROAP_MERCURY_EVENT_RECEIVED","correlation_id","message_type","error_type","error_cause","ROAP","ROAP_TYPES","TURN_DISCOVERY_RESPONSE","roap","turnDiscovery","handleTurnDiscoveryResponse","_data$message$sdps","roapMessage","sdp","sdps","length","undefined","roapMessageReceived","getMediaServer","mediaServer","split","find","line","startsWith","shift","replace","toLowerCase","_unused","getMediaServerIp","mediaServerIp","_sdp$split$find$match","match","trim","_unused2","getCorrelationIdForDevice","deviceUrl","locusSelf","devices","foundDevice","device","url","parseDefaultSiteFromMeetingPreferences","userPreferences","_userPreferences$site","result","sites","defaultSite","site","default","siteUrl","getSiteName","multipartSitePrefixList","arguments","siteName","forEach","multipartSitePrefix","includes","secondDot","indexOf","substring","hasH264Codec","_asyncToGenerator2","_regenerator","mark","_callee","hasCodec","pc","offer","_t","wrap","_context","prev","next","window","RTCPeerConnection","createOffer","offerToReceiveVideo","sent","close","LoggerProxy","logger","warn","abrupt","stop","checkH264Support","_checkH264Support","_callee2","options","_this","_ref2","firstChecked","disableNotifications","delay","maxDuration","shouldTrigger","shouldStopChecking","_context2","_now","Trigger","trigger","file","function","EVENT_TRIGGERS","MEDIA_CODEC_LOADED","log","error","MEDIA_CODEC_MISSING","setTimeout","timestamp","call","_x","apply","getThisDevice","newLocus","_newLocus$self","_newLocus$self$device","self","isWholeMeetingEnded","fullState","state","LOCUS","STATE","INACTIVE","endMeetingReason","EndMeetingReason","breakoutEnded","isSelfMovedOrBreakoutEnded","locus","_locus$self","_locus$self2","_locus$fullState","_locus$fullState2","isSelfLeftMoved","_LEFT_","reason","_MOVED_","isBreakoutEnded","joinedOnThisDevice","thisDevice","_JOINED_","isBreakoutLocusDTO","_newLocus$controls","_newLocus$controls$br","_newLocus$info","controls","breakout","sessionType","BREAKOUTS","SESSION_TYPES","BREAKOUT","info","isBreakout","isValidBreakoutLocus","_locus$fullState3","_locus$self3","inActiveStatus","isLocusAsBreakout","selfJoined","isMainAssociatedWithBreakout","mainLocus","breakoutLocus","_mainLocus$controls","_mainLocus$controls$b","_mainLocus$controls2","_mainLocus$controls2$","_breakoutLocus$contro","_breakoutLocus$contro2","_breakoutLocus$self","_MeetingsUtil$getThis","_MeetingsUtil$getThis2","replaceInfo","replaces","locusUrl","_default","exports"],"sources":["util.ts"],"sourcesContent":["/* globals window */\n\nimport {\n _CREATED_,\n _INCOMING_,\n _JOINED_,\n _LEFT_,\n DESTINATION_TYPE,\n _MOVED_,\n BREAKOUTS,\n EVENT_TRIGGERS,\n LOCUS,\n LOCUSEVENT,\n ROAP,\n} from '../constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Trigger from '../common/events/trigger-proxy';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport Metrics from '../metrics';\nimport {MEETING_KEY} from './meetings.types';\nimport {EndMeetingReason, LocusFullState} from '../locus-info/types';\n\n/**\n * Meetings Media Codec Missing Event\n * Emitted when H.264 codec is not\n * found in the browser.\n * @event media:codec:missing\n * @instance\n * @memberof MeetingsUtil\n */\n\n/**\n * Meetings Media Codec Loaded Event\n * Emitted when H.264 codec has been\n * loaded in the browser.\n * @event media:codec:loaded\n * @instance\n * @memberof MeetingsUtil\n */\n\nconst MeetingsUtil: any = {};\n\nMeetingsUtil.getMeetingAddedType = (type: DESTINATION_TYPE) =>\n type === DESTINATION_TYPE.LOCUS_ID ? _INCOMING_ : _CREATED_;\n\nMeetingsUtil.handleRoapMercury = (envelope, meetingCollection) => {\n const {data} = envelope;\n const {eventType} = data;\n\n if (eventType === LOCUSEVENT.MESSAGE_ROAP) {\n const meeting = meetingCollection.getByKey(MEETING_KEY.CORRELATION_ID, data.correlationId);\n\n if (meeting) {\n const {seq, messageType, tieBreaker, errorType, errorCause} = data.message;\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_MERCURY_EVENT_RECEIVED, {\n correlation_id: data.correlationId,\n seq,\n message_type: messageType,\n error_type: errorType,\n error_cause: errorCause,\n });\n\n if (messageType === ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {\n // turn discovery is not part of normal roap protocol and so we are not handling it\n // through the usual roap state machine\n meeting.roap.turnDiscovery.handleTurnDiscoveryResponse(data.message, 'from mercury');\n } else {\n const roapMessage = {\n seq,\n messageType,\n sdp: data.message.sdps?.length > 0 ? data.message.sdps[0] : undefined,\n tieBreaker,\n errorType,\n errorCause,\n };\n\n meeting.roapMessageReceived(roapMessage);\n }\n }\n }\n};\n\nMeetingsUtil.getMediaServer = (sdp) => {\n let mediaServer;\n\n // Attempt to collect the media server from the roap message.\n try {\n mediaServer = sdp\n .split('\\r\\n')\n .find((line) => line.startsWith('o='))\n .split(' ')\n .shift()\n .replace('o=', '')\n .toLowerCase();\n } catch {\n mediaServer = undefined;\n }\n\n return mediaServer;\n};\n\nMeetingsUtil.getMediaServerIp = (sdp) => {\n let mediaServerIp;\n\n // Attempt to collect the media server from the roap message.\n try {\n mediaServerIp = sdp\n .split('\\r\\n')\n .find((line) => line.startsWith('o='))\n .match(/o=\\S+ \\d+ \\d+ IN IP4 ([\\d.]+)/)?.[1]\n .toLowerCase()\n .trim();\n } catch {\n mediaServerIp = undefined;\n }\n\n return mediaServerIp;\n};\n\n/**\n * Finds correlationId of a device from locus self devices array\n * that matches the given deviceUrl\n * @param {string} deviceUrl\n * @param {object} locusSelf\n * @returns {string|false} correlationId or false if not found\n */\nMeetingsUtil.getCorrelationIdForDevice = (deviceUrl: string, locusSelf: any) => {\n if (locusSelf?.devices) {\n const foundDevice = locusSelf?.devices.find((device) => device.url === deviceUrl);\n\n if (foundDevice && foundDevice.correlationId) {\n return foundDevice.correlationId;\n }\n }\n\n return false;\n};\n\nMeetingsUtil.parseDefaultSiteFromMeetingPreferences = (userPreferences) => {\n let result = '';\n\n if (userPreferences?.sites?.length) {\n const defaultSite = userPreferences.sites.find((site) => site.default);\n\n if (defaultSite) {\n result = defaultSite.siteUrl;\n } else {\n result = userPreferences.sites[0].siteUrl;\n }\n }\n\n return result;\n};\n\nMeetingsUtil.getSiteName = (site: string, multipartSitePrefixList: string[] = []) => {\n if (!site) {\n return null;\n }\n\n let siteName: string | undefined;\n\n multipartSitePrefixList.forEach((multipartSitePrefix) => {\n if (!siteName && site.includes(multipartSitePrefix)) {\n const secondDot = site.indexOf('.', site.indexOf('.') + 1);\n\n siteName = site.substring(0, secondDot);\n }\n });\n\n if (siteName) {\n return siteName;\n }\n\n siteName = site.substring(0, site.indexOf('.'));\n\n return siteName;\n};\n\n/**\n * Will check to see if the H.264 media codec is supported.\n * @async\n * @private\n * @returns {Promise<boolean>}\n */\nMeetingsUtil.hasH264Codec = async () => {\n let hasCodec = false;\n\n try {\n const pc = new window.RTCPeerConnection();\n const offer = await pc.createOffer({offerToReceiveVideo: true});\n\n if (offer.sdp.match(/^a=rtpmap:\\d+\\s+H264\\/\\d+/m)) {\n hasCodec = true;\n }\n pc.close();\n } catch (error) {\n LoggerProxy.logger.warn(\n 'Meetings:util#hasH264Codec --> Error creating peerConnection for H.264 test.'\n );\n }\n\n return hasCodec;\n};\n\n/**\n * Notifies the user whether or not the H.264\n * codec is present. Will continuously check\n * until max duration.\n * @async\n * @private\n * @param {object} options\n * @param {Number} options.firstChecked Timestamp in milliseconds\n * @param {boolean} options.disableNotifications Default is false. Boolean to enable/disable notification and events\n * @returns {undefined}\n */\nMeetingsUtil.checkH264Support = async function checkH264Support(options: {\n firstChecked: number;\n disableNotifications: boolean;\n}) {\n const {hasH264Codec} = MeetingsUtil;\n const {firstChecked, disableNotifications} = options || {};\n const delay = 5e3; // ms\n const maxDuration = 3e5; // ms\n const shouldTrigger = firstChecked === undefined;\n const shouldStopChecking = firstChecked && Date.now() - firstChecked >= maxDuration;\n\n // Disable notifications and start H.264 download only\n if (disableNotifications) {\n hasH264Codec();\n\n return;\n }\n\n // Codec loaded trigger event notification\n if (await hasH264Codec()) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_LOADED\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec loaded successfully.');\n\n return;\n }\n\n // Stop checking if past the timelimit\n if (shouldStopChecking) {\n LoggerProxy.logger.error(\n 'Meetings:util#checkH264Support --> Timed out waiting for H264 codec to load.'\n );\n\n return;\n }\n\n // Trigger only once\n if (shouldTrigger) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_MISSING\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec is missing.');\n }\n\n // Keep checking in intervals to see if codec loaded\n window.setTimeout(() => {\n const timestamp = firstChecked || Date.now();\n\n MeetingsUtil.checkH264Support.call(this, {firstChecked: timestamp});\n }, delay);\n};\n\n/**\n * get device from locus data\n * @param {Object} newLocus new locus data\n * @param {String} deviceUrl current device url\n * @returns {Object}\n */\nMeetingsUtil.getThisDevice = (newLocus: any, deviceUrl: string) => {\n if (newLocus?.self?.devices?.length > 0) {\n return newLocus.self.devices.find((device) => device.url === deviceUrl);\n }\n\n return null;\n};\n\n/**\n * Checks if the fullState indicates the meeting has fully ended (not just a breakout move).\n * @param {Object} fullState locus fullState data\n * @returns {boolean}\n */\nMeetingsUtil.isWholeMeetingEnded = (fullState: LocusFullState): boolean => {\n return (\n fullState.state === LOCUS.STATE.INACTIVE &&\n fullState.endMeetingReason !== EndMeetingReason.breakoutEnded\n );\n};\n\n/**\n * Checks if the self state in a locus indicates a breakout move or breakout end.\n * Returns true when:\n * - self state is LEFT with reason MOVED (regular breakout move), OR\n * - fullState is INACTIVE with endMeetingReason BREAKOUT_ENDED (breakout session ended)\n * @param {Object} locus locus data\n * @returns {boolean}\n */\nMeetingsUtil.isSelfMovedOrBreakoutEnded = (locus: any): boolean => {\n const isSelfLeftMoved = locus?.self?.state === _LEFT_ && locus?.self?.reason === _MOVED_;\n const isBreakoutEnded =\n locus?.fullState?.state === LOCUS.STATE.INACTIVE &&\n locus?.fullState?.endMeetingReason === EndMeetingReason.breakoutEnded;\n\n return isSelfLeftMoved || isBreakoutEnded;\n};\n\n/**\n * get self device joined status from locus data\n * @param {Object} meeting current meeting data\n * @param {Object} newLocus new locus data\n * @param {String} deviceUrl current device url\n * @returns {Object}\n */\nMeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any, deviceUrl: string) => {\n const thisDevice = MeetingsUtil.getThisDevice(newLocus, deviceUrl);\n if (thisDevice) {\n if (!thisDevice.correlationId || meeting?.correlationId === thisDevice.correlationId) {\n return (\n thisDevice.state === _JOINED_ ||\n (thisDevice.state === _LEFT_ && thisDevice.reason === _MOVED_)\n );\n }\n }\n\n return false;\n};\n\n/**\n * check the new locus is breakout session's one or not\n * @param {Object} newLocus new locus data\n * @returns {boolean}\n * @private\n */\nMeetingsUtil.isBreakoutLocusDTO = (newLocus: any) => {\n return (\n newLocus?.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT ||\n !!newLocus?.info?.isBreakout\n );\n};\n\n/**\n * check the locus is valid breakout locus or not\n * @param {Object} locus\n * @returns {boolean}\n * @private\n */\nMeetingsUtil.isValidBreakoutLocus = (locus: any) => {\n const inActiveStatus = locus?.fullState?.state === LOCUS.STATE.INACTIVE;\n const isLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(locus);\n const selfJoined = locus.self?.state === _JOINED_;\n\n return isLocusAsBreakout && !inActiveStatus && selfJoined;\n};\n/**\n * check if the breakout locus is associated with the main locus by comparing the breakout control url or the replaces info in self device\n * @param {Object} mainLocus main locus data\n * @param {Object} breakoutLocus breakout locus data\n * @returns {boolean}\n * @private\n */\nMeetingsUtil.isMainAssociatedWithBreakout = (mainLocus: any, breakoutLocus: any) => {\n if (\n mainLocus.controls?.breakout?.url &&\n mainLocus.controls?.breakout?.url === breakoutLocus.controls?.breakout?.url\n ) {\n return true;\n }\n const deviceUrl = breakoutLocus?.self?.deviceUrl;\n const replaceInfo = MeetingsUtil.getThisDevice(breakoutLocus, deviceUrl)?.replaces?.[0];\n if (replaceInfo?.locusUrl && replaceInfo.locusUrl === mainLocus.url) {\n return true;\n }\n\n return false;\n};\nexport default MeetingsUtil;\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_constants","require","_loggerProxy","_interopRequireDefault","_triggerProxy","_constants2","_metrics","_meetings","_types","MeetingsUtil","getMeetingAddedType","type","DESTINATION_TYPE","LOCUS_ID","_INCOMING_","_CREATED_","handleRoapMercury","envelope","meetingCollection","data","eventType","LOCUSEVENT","MESSAGE_ROAP","meeting","getByKey","MEETING_KEY","CORRELATION_ID","correlationId","_data$message","message","seq","messageType","tieBreaker","errorType","errorCause","Metrics","sendBehavioralMetric","BEHAVIORAL_METRICS","ROAP_MERCURY_EVENT_RECEIVED","correlation_id","message_type","error_type","error_cause","ROAP","ROAP_TYPES","TURN_DISCOVERY_RESPONSE","roap","turnDiscovery","handleTurnDiscoveryResponse","_data$message$sdps","roapMessage","sdp","sdps","length","undefined","roapMessageReceived","getMediaServer","mediaServer","split","find","line","startsWith","shift","replace","toLowerCase","_unused","getMediaServerIp","mediaServerIp","_sdp$split$find$match","match","trim","_unused2","getCorrelationIdForDevice","deviceUrl","locusSelf","devices","foundDevice","device","url","parseDefaultSiteFromMeetingPreferences","userPreferences","_userPreferences$site","result","sites","defaultSite","site","default","siteUrl","getSiteName","multipartSitePrefixList","arguments","siteName","forEach","multipartSitePrefix","includes","secondDot","indexOf","substring","hasH264Codec","_asyncToGenerator2","_regenerator","mark","_callee","hasCodec","pc","offer","_t","wrap","_context","prev","next","window","RTCPeerConnection","createOffer","offerToReceiveVideo","sent","close","LoggerProxy","logger","warn","abrupt","stop","checkH264Support","_checkH264Support","_callee2","options","_this","_ref2","firstChecked","disableNotifications","delay","maxDuration","shouldTrigger","shouldStopChecking","_context2","_now","Trigger","trigger","file","function","EVENT_TRIGGERS","MEDIA_CODEC_LOADED","log","error","MEDIA_CODEC_MISSING","setTimeout","timestamp","call","_x","apply","getThisDevice","newLocus","_newLocus$self","_newLocus$self$device","self","isWholeMeetingEnded","fullState","state","LOCUS","STATE","INACTIVE","endMeetingReason","EndMeetingReason","breakoutEnded","isSelfMovedOrBreakoutEnded","locus","_locus$self","_locus$self2","_locus$fullState","_locus$fullState2","isSelfLeftMoved","_LEFT_","reason","_MOVED_","isBreakoutEnded","isOneOnOneCall","_locus$fullState3","fullStateType","_CALL_","_SIP_BRIDGE_","_SPACE_SHARE_","joinedOnThisDevice","thisDevice","_JOINED_","isBreakoutLocusDTO","_newLocus$controls","_newLocus$controls$br","_newLocus$info","controls","breakout","sessionType","BREAKOUTS","SESSION_TYPES","BREAKOUT","info","isBreakout","isValidBreakoutLocus","_locus$fullState4","_locus$self3","inActiveStatus","isLocusAsBreakout","selfJoined","isMainAssociatedWithBreakout","mainLocus","breakoutLocus","_mainLocus$controls","_mainLocus$controls$b","_mainLocus$controls2","_mainLocus$controls2$","_breakoutLocus$contro","_breakoutLocus$contro2","_breakoutLocus$self","_MeetingsUtil$getThis","_MeetingsUtil$getThis2","replaceInfo","replaces","locusUrl","_default","exports"],"sources":["util.ts"],"sourcesContent":["/* globals window */\n\nimport {\n _CALL_,\n _CREATED_,\n _INCOMING_,\n _JOINED_,\n _LEFT_,\n DESTINATION_TYPE,\n _MOVED_,\n _SIP_BRIDGE_,\n _SPACE_SHARE_,\n BREAKOUTS,\n EVENT_TRIGGERS,\n LOCUS,\n LOCUSEVENT,\n ROAP,\n} from '../constants';\nimport LoggerProxy from '../common/logs/logger-proxy';\nimport Trigger from '../common/events/trigger-proxy';\nimport BEHAVIORAL_METRICS from '../metrics/constants';\nimport Metrics from '../metrics';\nimport {MEETING_KEY} from './meetings.types';\nimport {EndMeetingReason, LocusFullState} from '../locus-info/types';\n\n/**\n * Meetings Media Codec Missing Event\n * Emitted when H.264 codec is not\n * found in the browser.\n * @event media:codec:missing\n * @instance\n * @memberof MeetingsUtil\n */\n\n/**\n * Meetings Media Codec Loaded Event\n * Emitted when H.264 codec has been\n * loaded in the browser.\n * @event media:codec:loaded\n * @instance\n * @memberof MeetingsUtil\n */\n\nconst MeetingsUtil: any = {};\n\nMeetingsUtil.getMeetingAddedType = (type: DESTINATION_TYPE) =>\n type === DESTINATION_TYPE.LOCUS_ID ? _INCOMING_ : _CREATED_;\n\nMeetingsUtil.handleRoapMercury = (envelope, meetingCollection) => {\n const {data} = envelope;\n const {eventType} = data;\n\n if (eventType === LOCUSEVENT.MESSAGE_ROAP) {\n const meeting = meetingCollection.getByKey(MEETING_KEY.CORRELATION_ID, data.correlationId);\n\n if (meeting) {\n const {seq, messageType, tieBreaker, errorType, errorCause} = data.message;\n\n Metrics.sendBehavioralMetric(BEHAVIORAL_METRICS.ROAP_MERCURY_EVENT_RECEIVED, {\n correlation_id: data.correlationId,\n seq,\n message_type: messageType,\n error_type: errorType,\n error_cause: errorCause,\n });\n\n if (messageType === ROAP.ROAP_TYPES.TURN_DISCOVERY_RESPONSE) {\n // turn discovery is not part of normal roap protocol and so we are not handling it\n // through the usual roap state machine\n meeting.roap.turnDiscovery.handleTurnDiscoveryResponse(data.message, 'from mercury');\n } else {\n const roapMessage = {\n seq,\n messageType,\n sdp: data.message.sdps?.length > 0 ? data.message.sdps[0] : undefined,\n tieBreaker,\n errorType,\n errorCause,\n };\n\n meeting.roapMessageReceived(roapMessage);\n }\n }\n }\n};\n\nMeetingsUtil.getMediaServer = (sdp) => {\n let mediaServer;\n\n // Attempt to collect the media server from the roap message.\n try {\n mediaServer = sdp\n .split('\\r\\n')\n .find((line) => line.startsWith('o='))\n .split(' ')\n .shift()\n .replace('o=', '')\n .toLowerCase();\n } catch {\n mediaServer = undefined;\n }\n\n return mediaServer;\n};\n\nMeetingsUtil.getMediaServerIp = (sdp) => {\n let mediaServerIp;\n\n // Attempt to collect the media server from the roap message.\n try {\n mediaServerIp = sdp\n .split('\\r\\n')\n .find((line) => line.startsWith('o='))\n .match(/o=\\S+ \\d+ \\d+ IN IP4 ([\\d.]+)/)?.[1]\n .toLowerCase()\n .trim();\n } catch {\n mediaServerIp = undefined;\n }\n\n return mediaServerIp;\n};\n\n/**\n * Finds correlationId of a device from locus self devices array\n * that matches the given deviceUrl\n * @param {string} deviceUrl\n * @param {object} locusSelf\n * @returns {string|false} correlationId or false if not found\n */\nMeetingsUtil.getCorrelationIdForDevice = (deviceUrl: string, locusSelf: any) => {\n if (locusSelf?.devices) {\n const foundDevice = locusSelf?.devices.find((device) => device.url === deviceUrl);\n\n if (foundDevice && foundDevice.correlationId) {\n return foundDevice.correlationId;\n }\n }\n\n return false;\n};\n\nMeetingsUtil.parseDefaultSiteFromMeetingPreferences = (userPreferences) => {\n let result = '';\n\n if (userPreferences?.sites?.length) {\n const defaultSite = userPreferences.sites.find((site) => site.default);\n\n if (defaultSite) {\n result = defaultSite.siteUrl;\n } else {\n result = userPreferences.sites[0].siteUrl;\n }\n }\n\n return result;\n};\n\nMeetingsUtil.getSiteName = (site: string, multipartSitePrefixList: string[] = []) => {\n if (!site) {\n return null;\n }\n\n let siteName: string | undefined;\n\n multipartSitePrefixList.forEach((multipartSitePrefix) => {\n if (!siteName && site.includes(multipartSitePrefix)) {\n const secondDot = site.indexOf('.', site.indexOf('.') + 1);\n\n siteName = site.substring(0, secondDot);\n }\n });\n\n if (siteName) {\n return siteName;\n }\n\n siteName = site.substring(0, site.indexOf('.'));\n\n return siteName;\n};\n\n/**\n * Will check to see if the H.264 media codec is supported.\n * @async\n * @private\n * @returns {Promise<boolean>}\n */\nMeetingsUtil.hasH264Codec = async () => {\n let hasCodec = false;\n\n try {\n const pc = new window.RTCPeerConnection();\n const offer = await pc.createOffer({offerToReceiveVideo: true});\n\n if (offer.sdp.match(/^a=rtpmap:\\d+\\s+H264\\/\\d+/m)) {\n hasCodec = true;\n }\n pc.close();\n } catch (error) {\n LoggerProxy.logger.warn(\n 'Meetings:util#hasH264Codec --> Error creating peerConnection for H.264 test.'\n );\n }\n\n return hasCodec;\n};\n\n/**\n * Notifies the user whether or not the H.264\n * codec is present. Will continuously check\n * until max duration.\n * @async\n * @private\n * @param {object} options\n * @param {Number} options.firstChecked Timestamp in milliseconds\n * @param {boolean} options.disableNotifications Default is false. Boolean to enable/disable notification and events\n * @returns {undefined}\n */\nMeetingsUtil.checkH264Support = async function checkH264Support(options: {\n firstChecked: number;\n disableNotifications: boolean;\n}) {\n const {hasH264Codec} = MeetingsUtil;\n const {firstChecked, disableNotifications} = options || {};\n const delay = 5e3; // ms\n const maxDuration = 3e5; // ms\n const shouldTrigger = firstChecked === undefined;\n const shouldStopChecking = firstChecked && Date.now() - firstChecked >= maxDuration;\n\n // Disable notifications and start H.264 download only\n if (disableNotifications) {\n hasH264Codec();\n\n return;\n }\n\n // Codec loaded trigger event notification\n if (await hasH264Codec()) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_LOADED\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec loaded successfully.');\n\n return;\n }\n\n // Stop checking if past the timelimit\n if (shouldStopChecking) {\n LoggerProxy.logger.error(\n 'Meetings:util#checkH264Support --> Timed out waiting for H264 codec to load.'\n );\n\n return;\n }\n\n // Trigger only once\n if (shouldTrigger) {\n Trigger.trigger(\n this,\n {\n file: 'meetings/util',\n function: 'checkH264Support',\n },\n EVENT_TRIGGERS.MEDIA_CODEC_MISSING\n );\n LoggerProxy.logger.log('Meetings:util#checkH264Support --> H264 codec is missing.');\n }\n\n // Keep checking in intervals to see if codec loaded\n window.setTimeout(() => {\n const timestamp = firstChecked || Date.now();\n\n MeetingsUtil.checkH264Support.call(this, {firstChecked: timestamp});\n }, delay);\n};\n\n/**\n * get device from locus data\n * @param {Object} newLocus new locus data\n * @param {String} deviceUrl current device url\n * @returns {Object}\n */\nMeetingsUtil.getThisDevice = (newLocus: any, deviceUrl: string) => {\n if (newLocus?.self?.devices?.length > 0) {\n return newLocus.self.devices.find((device) => device.url === deviceUrl);\n }\n\n return null;\n};\n\n/**\n * Checks if the fullState indicates the meeting has fully ended (not just a breakout move).\n * @param {Object} fullState locus fullState data\n * @returns {boolean}\n */\nMeetingsUtil.isWholeMeetingEnded = (fullState: LocusFullState): boolean => {\n return (\n fullState.state === LOCUS.STATE.INACTIVE &&\n fullState.endMeetingReason !== EndMeetingReason.breakoutEnded\n );\n};\n\n/**\n * Checks if the self state in a locus indicates a breakout move or breakout end.\n * Returns true when:\n * - self state is LEFT with reason MOVED (regular breakout move), OR\n * - fullState is INACTIVE with endMeetingReason BREAKOUT_ENDED (breakout session ended)\n * @param {Object} locus locus data\n * @returns {boolean}\n */\nMeetingsUtil.isSelfMovedOrBreakoutEnded = (locus: any): boolean => {\n const isSelfLeftMoved = locus?.self?.state === _LEFT_ && locus?.self?.reason === _MOVED_;\n const isBreakoutEnded =\n locus?.fullState?.state === LOCUS.STATE.INACTIVE &&\n locus?.fullState?.endMeetingReason === EndMeetingReason.breakoutEnded;\n\n return isSelfLeftMoved || isBreakoutEnded;\n};\n\n/**\n * Checks if a locus is a 1:1 call using locus.fullState.type.\n * Returns true when fullState.type is CALL, SIP_BRIDGE, or SPACE_SHARE.\n * @param {Object} locus locus data\n * @returns {boolean}\n */\nMeetingsUtil.isOneOnOneCall = (locus: any): boolean => {\n const fullStateType = locus?.fullState?.type;\n\n return (\n fullStateType === _CALL_ || fullStateType === _SIP_BRIDGE_ || fullStateType === _SPACE_SHARE_\n );\n};\n\n/**\n * get self device joined status from locus data\n * @param {Object} meeting current meeting data\n * @param {Object} newLocus new locus data\n * @param {String} deviceUrl current device url\n * @returns {Object}\n */\nMeetingsUtil.joinedOnThisDevice = (meeting: any, newLocus: any, deviceUrl: string) => {\n const thisDevice = MeetingsUtil.getThisDevice(newLocus, deviceUrl);\n if (thisDevice) {\n if (!thisDevice.correlationId || meeting?.correlationId === thisDevice.correlationId) {\n return (\n thisDevice.state === _JOINED_ ||\n (thisDevice.state === _LEFT_ && thisDevice.reason === _MOVED_)\n );\n }\n }\n\n return false;\n};\n\n/**\n * check the new locus is breakout session's one or not\n * @param {Object} newLocus new locus data\n * @returns {boolean}\n * @private\n */\nMeetingsUtil.isBreakoutLocusDTO = (newLocus: any) => {\n return (\n newLocus?.controls?.breakout?.sessionType === BREAKOUTS.SESSION_TYPES.BREAKOUT ||\n !!newLocus?.info?.isBreakout\n );\n};\n\n/**\n * check the locus is valid breakout locus or not\n * @param {Object} locus\n * @returns {boolean}\n * @private\n */\nMeetingsUtil.isValidBreakoutLocus = (locus: any) => {\n const inActiveStatus = locus?.fullState?.state === LOCUS.STATE.INACTIVE;\n const isLocusAsBreakout = MeetingsUtil.isBreakoutLocusDTO(locus);\n const selfJoined = locus.self?.state === _JOINED_;\n\n return isLocusAsBreakout && !inActiveStatus && selfJoined;\n};\n/**\n * check if the breakout locus is associated with the main locus by comparing the breakout control url or the replaces info in self device\n * @param {Object} mainLocus main locus data\n * @param {Object} breakoutLocus breakout locus data\n * @returns {boolean}\n * @private\n */\nMeetingsUtil.isMainAssociatedWithBreakout = (mainLocus: any, breakoutLocus: any) => {\n if (\n mainLocus.controls?.breakout?.url &&\n mainLocus.controls?.breakout?.url === breakoutLocus.controls?.breakout?.url\n ) {\n return true;\n }\n const deviceUrl = breakoutLocus?.self?.deviceUrl;\n const replaceInfo = MeetingsUtil.getThisDevice(breakoutLocus, deviceUrl)?.replaces?.[0];\n if (replaceInfo?.locusUrl && replaceInfo.locusUrl === mainLocus.url) {\n return true;\n }\n\n return false;\n};\nexport default MeetingsUtil;\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -38,6 +38,7 @@ interface InternalDataSet extends DataSet {
|
|
|
38
38
|
hashTree?: HashTree;
|
|
39
39
|
timer?: ReturnType<typeof setTimeout>;
|
|
40
40
|
heartbeatWatchdogTimer?: ReturnType<typeof setTimeout>;
|
|
41
|
+
syncAbortController?: AbortController;
|
|
41
42
|
}
|
|
42
43
|
type WebexRequestMethod = (options: Record<string, any>) => Promise<any>;
|
|
43
44
|
export declare const LocusInfoUpdateType: {
|
|
@@ -332,6 +333,14 @@ declare class HashTreeParser {
|
|
|
332
333
|
* @returns {Promise<void>}
|
|
333
334
|
*/
|
|
334
335
|
private performSync;
|
|
336
|
+
/**
|
|
337
|
+
* Cancels any pending or in-flight syncs for the specified data sets.
|
|
338
|
+
* This removes matching entries from the sync queue and aborts any in-flight sync HTTP requests.
|
|
339
|
+
*
|
|
340
|
+
* @param {string[]} dataSetNames - The names of the data sets to cancel syncs for
|
|
341
|
+
* @returns {void}
|
|
342
|
+
*/
|
|
343
|
+
private cancelPendingSyncsForDataSets;
|
|
335
344
|
/**
|
|
336
345
|
* Enqueues a sync for the given data set. If the data set is already in the queue, the request is ignored.
|
|
337
346
|
* This ensures that all syncs are executed sequentially and no more than 1 sync runs at a time.
|
package/dist/webinar/index.js
CHANGED
package/package.json
CHANGED
|
@@ -49,6 +49,7 @@ interface InternalDataSet extends DataSet {
|
|
|
49
49
|
hashTree?: HashTree; // set only for visible data sets
|
|
50
50
|
timer?: ReturnType<typeof setTimeout>;
|
|
51
51
|
heartbeatWatchdogTimer?: ReturnType<typeof setTimeout>;
|
|
52
|
+
syncAbortController?: AbortController;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
type WebexRequestMethod = (options: Record<string, any>) => Promise<any>;
|
|
@@ -546,6 +547,21 @@ class HashTreeParser {
|
|
|
546
547
|
private handleRootHashHeartBeatMessage(message: RootHashMessage): void {
|
|
547
548
|
const {dataSets} = message;
|
|
548
549
|
|
|
550
|
+
LoggerProxy.logger.info(
|
|
551
|
+
`HashTreeParser#handleRootHashMessage --> ${
|
|
552
|
+
this.debugId
|
|
553
|
+
} Received heartbeat root hash message with data sets: ${JSON.stringify(
|
|
554
|
+
dataSets.map(({name, root, leafCount, version}) => ({
|
|
555
|
+
name,
|
|
556
|
+
root,
|
|
557
|
+
leafCount,
|
|
558
|
+
version,
|
|
559
|
+
}))
|
|
560
|
+
)}`
|
|
561
|
+
);
|
|
562
|
+
|
|
563
|
+
this.cancelPendingSyncsForDataSets(dataSets.map((ds) => ds.name));
|
|
564
|
+
|
|
549
565
|
dataSets.forEach((dataSet) => {
|
|
550
566
|
this.updateDataSetInfo(dataSet);
|
|
551
567
|
this.runSyncAlgorithm(dataSet);
|
|
@@ -845,6 +861,8 @@ class HashTreeParser {
|
|
|
845
861
|
*/
|
|
846
862
|
private deleteHashTree(dataSetName: string) {
|
|
847
863
|
this.dataSets[dataSetName].hashTree = undefined;
|
|
864
|
+
this.dataSets[dataSetName].syncAbortController?.abort();
|
|
865
|
+
this.dataSets[dataSetName].syncAbortController = undefined;
|
|
848
866
|
|
|
849
867
|
// we also need to stop the timers as there is no hash tree anymore to sync
|
|
850
868
|
if (this.dataSets[dataSetName].timer) {
|
|
@@ -1020,6 +1038,7 @@ class HashTreeParser {
|
|
|
1020
1038
|
// first, update our metadata about the datasets with info from the message
|
|
1021
1039
|
this.visibleDataSetsUrl = visibleDataSetsUrl;
|
|
1022
1040
|
dataSets.forEach((dataSet) => this.updateDataSetInfo(dataSet));
|
|
1041
|
+
this.cancelPendingSyncsForDataSets(dataSets.map((ds) => ds.name));
|
|
1023
1042
|
|
|
1024
1043
|
const updatedObjects: HashTreeObject[] = [];
|
|
1025
1044
|
|
|
@@ -1243,6 +1262,9 @@ class HashTreeParser {
|
|
|
1243
1262
|
return;
|
|
1244
1263
|
}
|
|
1245
1264
|
|
|
1265
|
+
const abortController = dataSet.syncAbortController ?? new AbortController();
|
|
1266
|
+
dataSet.syncAbortController = abortController;
|
|
1267
|
+
|
|
1246
1268
|
const {hashTree} = dataSet;
|
|
1247
1269
|
const rootHash = hashTree.getRootHash();
|
|
1248
1270
|
|
|
@@ -1291,6 +1313,14 @@ class HashTreeParser {
|
|
|
1291
1313
|
leavesData = {0: hashTree.getLeafData(0)};
|
|
1292
1314
|
}
|
|
1293
1315
|
}
|
|
1316
|
+
|
|
1317
|
+
if (abortController.signal.aborted) {
|
|
1318
|
+
LoggerProxy.logger.info(
|
|
1319
|
+
`HashTreeParser#performSync --> ${this.debugId} abandoning sync for "${dataSet.name}" before /sync - message received during sync`
|
|
1320
|
+
);
|
|
1321
|
+
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1294
1324
|
// request sync for mismatched leaves
|
|
1295
1325
|
let syncResponse: HashTreeMessage | null = null;
|
|
1296
1326
|
|
|
@@ -1308,6 +1338,10 @@ class HashTreeParser {
|
|
|
1308
1338
|
this.runSyncAlgorithm(dataSet);
|
|
1309
1339
|
|
|
1310
1340
|
if (syncResponse) {
|
|
1341
|
+
// clear the abort controller before processing the response so that
|
|
1342
|
+
// parseMessage() -> cancelPendingSyncsForDataSets() doesn't log a
|
|
1343
|
+
// misleading "aborting sync" message for this already-completed sync
|
|
1344
|
+
dataSet.syncAbortController = undefined;
|
|
1311
1345
|
// the format of sync response is the same as messages, so we can reuse the same handler
|
|
1312
1346
|
this.handleMessage(syncResponse, 'via sync API');
|
|
1313
1347
|
}
|
|
@@ -1318,6 +1352,38 @@ class HashTreeParser {
|
|
|
1318
1352
|
error
|
|
1319
1353
|
);
|
|
1320
1354
|
}
|
|
1355
|
+
} finally {
|
|
1356
|
+
dataSet.syncAbortController = undefined;
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
/**
|
|
1361
|
+
* Cancels any pending or in-flight syncs for the specified data sets.
|
|
1362
|
+
* This removes matching entries from the sync queue and aborts any in-flight sync HTTP requests.
|
|
1363
|
+
*
|
|
1364
|
+
* @param {string[]} dataSetNames - The names of the data sets to cancel syncs for
|
|
1365
|
+
* @returns {void}
|
|
1366
|
+
*/
|
|
1367
|
+
private cancelPendingSyncsForDataSets(dataSetNames: string[]): void {
|
|
1368
|
+
const previousLength = this.syncQueue.length;
|
|
1369
|
+
|
|
1370
|
+
this.syncQueue = this.syncQueue.filter((entry) => !dataSetNames.includes(entry.dataSetName));
|
|
1371
|
+
|
|
1372
|
+
if (previousLength !== this.syncQueue.length) {
|
|
1373
|
+
LoggerProxy.logger.info(
|
|
1374
|
+
`HashTreeParser#cancelPendingSyncsForDataSets --> ${this.debugId} removed ${
|
|
1375
|
+
previousLength - this.syncQueue.length
|
|
1376
|
+
} entries from sync queue for data sets: ${dataSetNames.join(', ')}`
|
|
1377
|
+
);
|
|
1378
|
+
}
|
|
1379
|
+
|
|
1380
|
+
for (const name of dataSetNames) {
|
|
1381
|
+
if (this.dataSets[name]?.syncAbortController) {
|
|
1382
|
+
LoggerProxy.logger.info(
|
|
1383
|
+
`HashTreeParser#cancelPendingSyncsForDataSets --> ${this.debugId} aborting in-flight sync for data set "${name}"`
|
|
1384
|
+
);
|
|
1385
|
+
this.dataSets[name].syncAbortController.abort();
|
|
1386
|
+
}
|
|
1321
1387
|
}
|
|
1322
1388
|
}
|
|
1323
1389
|
|
|
@@ -1558,6 +1624,8 @@ class HashTreeParser {
|
|
|
1558
1624
|
this.stopAllTimers();
|
|
1559
1625
|
this.syncQueue = [];
|
|
1560
1626
|
Object.values(this.dataSets).forEach((dataSet) => {
|
|
1627
|
+
dataSet.syncAbortController?.abort();
|
|
1628
|
+
dataSet.syncAbortController = undefined;
|
|
1561
1629
|
dataSet.hashTree = undefined;
|
|
1562
1630
|
});
|
|
1563
1631
|
this.visibleDataSets = [];
|
package/src/meeting/index.ts
CHANGED
|
@@ -4683,7 +4683,8 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
4683
4683
|
if (
|
|
4684
4684
|
(!this.meetingInfo || isEmpty(this.meetingInfo)) &&
|
|
4685
4685
|
(this.destination as LocusDTO)?.info &&
|
|
4686
|
-
!this.fetchMeetingInfoTimeoutId
|
|
4686
|
+
!this.fetchMeetingInfoTimeoutId &&
|
|
4687
|
+
!MeetingsUtil.isOneOnOneCall(locus)
|
|
4687
4688
|
) {
|
|
4688
4689
|
try {
|
|
4689
4690
|
await this.fetchMeetingInfo({});
|
package/src/meetings/index.ts
CHANGED
|
@@ -1796,9 +1796,12 @@ export default class Meetings extends WebexPlugin {
|
|
|
1796
1796
|
};
|
|
1797
1797
|
const shouldDeferMeetingInfoFetch = type === DESTINATION_TYPE.LOCUS_ID && !destination?.info;
|
|
1798
1798
|
|
|
1799
|
+
const isOneOnOneCallLocus =
|
|
1800
|
+
type === DESTINATION_TYPE.LOCUS_ID && MeetingsUtil.isOneOnOneCall(destination);
|
|
1801
|
+
|
|
1799
1802
|
if (meetingInfo) {
|
|
1800
1803
|
meeting.injectMeetingInfo(meetingInfo, meetingInfoOptions, meetingLookupUrl);
|
|
1801
|
-
} else if (type !== DESTINATION_TYPE.ONE_ON_ONE_CALL) {
|
|
1804
|
+
} else if (type !== DESTINATION_TYPE.ONE_ON_ONE_CALL && !isOneOnOneCallLocus) {
|
|
1802
1805
|
// ignore fetchMeetingInfo for 1:1 meetings
|
|
1803
1806
|
if (enableUnifiedMeetings && !isMeetingActive && useRandomDelayForInfo && waitingTime > 0) {
|
|
1804
1807
|
meeting.fetchMeetingInfoTimeoutId = setTimeout(
|
package/src/meetings/util.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
/* globals window */
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
+
_CALL_,
|
|
4
5
|
_CREATED_,
|
|
5
6
|
_INCOMING_,
|
|
6
7
|
_JOINED_,
|
|
7
8
|
_LEFT_,
|
|
8
9
|
DESTINATION_TYPE,
|
|
9
10
|
_MOVED_,
|
|
11
|
+
_SIP_BRIDGE_,
|
|
12
|
+
_SPACE_SHARE_,
|
|
10
13
|
BREAKOUTS,
|
|
11
14
|
EVENT_TRIGGERS,
|
|
12
15
|
LOCUS,
|
|
@@ -320,6 +323,20 @@ MeetingsUtil.isSelfMovedOrBreakoutEnded = (locus: any): boolean => {
|
|
|
320
323
|
return isSelfLeftMoved || isBreakoutEnded;
|
|
321
324
|
};
|
|
322
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Checks if a locus is a 1:1 call using locus.fullState.type.
|
|
328
|
+
* Returns true when fullState.type is CALL, SIP_BRIDGE, or SPACE_SHARE.
|
|
329
|
+
* @param {Object} locus locus data
|
|
330
|
+
* @returns {boolean}
|
|
331
|
+
*/
|
|
332
|
+
MeetingsUtil.isOneOnOneCall = (locus: any): boolean => {
|
|
333
|
+
const fullStateType = locus?.fullState?.type;
|
|
334
|
+
|
|
335
|
+
return (
|
|
336
|
+
fullStateType === _CALL_ || fullStateType === _SIP_BRIDGE_ || fullStateType === _SPACE_SHARE_
|
|
337
|
+
);
|
|
338
|
+
};
|
|
339
|
+
|
|
323
340
|
/**
|
|
324
341
|
* get self device joined status from locus data
|
|
325
342
|
* @param {Object} meeting current meeting data
|
|
@@ -8,6 +8,7 @@ import {expect} from '@webex/test-helper-chai';
|
|
|
8
8
|
import sinon from 'sinon';
|
|
9
9
|
import {assert} from '@webex/test-helper-chai';
|
|
10
10
|
import {EMPTY_HASH} from '@webex/plugin-meetings/src/hashTree/constants';
|
|
11
|
+
import testUtils from '@webex/plugin-meetings/test/utils/testUtils';
|
|
11
12
|
import { some } from 'lodash';
|
|
12
13
|
import Metrics from '@webex/plugin-meetings/src/metrics';
|
|
13
14
|
import BEHAVIORAL_METRICS from '@webex/plugin-meetings/src/metrics/constants';
|
|
@@ -4734,6 +4735,258 @@ describe('HashTreeParser', () => {
|
|
|
4734
4735
|
});
|
|
4735
4736
|
});
|
|
4736
4737
|
|
|
4738
|
+
describe('#performSync abort controller', () => {
|
|
4739
|
+
it('should reuse an existing syncAbortController if one is already set on the dataset', async () => {
|
|
4740
|
+
const parser = createHashTreeParser();
|
|
4741
|
+
const mainUrl = parser.dataSets.main.url;
|
|
4742
|
+
|
|
4743
|
+
// Pre-set an AbortController on the dataset before sync starts
|
|
4744
|
+
const existingController = new AbortController();
|
|
4745
|
+
parser.dataSets.main.syncAbortController = existingController;
|
|
4746
|
+
|
|
4747
|
+
// Use a deferred promise for GET hashtree so we can inspect the controller mid-sync
|
|
4748
|
+
let resolveGetHashtree;
|
|
4749
|
+
webexRequest.withArgs(sinon.match({method: 'GET', uri: `${mainUrl}/hashtree`})).callsFake(
|
|
4750
|
+
() =>
|
|
4751
|
+
new Promise((resolve) => {
|
|
4752
|
+
resolveGetHashtree = resolve;
|
|
4753
|
+
})
|
|
4754
|
+
);
|
|
4755
|
+
|
|
4756
|
+
// Trigger sync for main
|
|
4757
|
+
parser.handleMessage(
|
|
4758
|
+
createHeartbeatMessage('main', 16, 1100, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4759
|
+
'trigger main sync'
|
|
4760
|
+
);
|
|
4761
|
+
|
|
4762
|
+
await clock.tickAsync(1000);
|
|
4763
|
+
|
|
4764
|
+
// While sync is in-flight, verify the controller is the same one we pre-set
|
|
4765
|
+
expect(parser.dataSets.main.syncAbortController).to.equal(existingController);
|
|
4766
|
+
|
|
4767
|
+
// Resolve GET hashtree with matching hashes (no sync needed)
|
|
4768
|
+
resolveGetHashtree({body: {}});
|
|
4769
|
+
await testUtils.flushPromises();
|
|
4770
|
+
|
|
4771
|
+
// After sync completes, syncAbortController is cleared in finally
|
|
4772
|
+
expect(parser.dataSets.main.syncAbortController).to.be.undefined;
|
|
4773
|
+
});
|
|
4774
|
+
|
|
4775
|
+
it('should abort the sync before /sync request when the controller is aborted during getHashesFromLocus', async () => {
|
|
4776
|
+
const parser = createHashTreeParser();
|
|
4777
|
+
const mainUrl = parser.dataSets.main.url;
|
|
4778
|
+
|
|
4779
|
+
// Use a deferred promise for GET hashtree so we can abort while it's pending
|
|
4780
|
+
let resolveGetHashtree;
|
|
4781
|
+
webexRequest.withArgs(sinon.match({method: 'GET', uri: `${mainUrl}/hashtree`})).callsFake(
|
|
4782
|
+
() =>
|
|
4783
|
+
new Promise((resolve) => {
|
|
4784
|
+
resolveGetHashtree = resolve;
|
|
4785
|
+
})
|
|
4786
|
+
);
|
|
4787
|
+
|
|
4788
|
+
// Mock POST sync - should NOT be called if abort works
|
|
4789
|
+
mockSendSyncRequestResponse(mainUrl, null);
|
|
4790
|
+
|
|
4791
|
+
// Trigger sync for main via heartbeat with mismatched root hash
|
|
4792
|
+
parser.handleMessage(
|
|
4793
|
+
createHeartbeatMessage('main', 16, 1100, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4794
|
+
'trigger main sync'
|
|
4795
|
+
);
|
|
4796
|
+
|
|
4797
|
+
// Fire the timer to start the sync
|
|
4798
|
+
await clock.tickAsync(1000);
|
|
4799
|
+
|
|
4800
|
+
// Now abort the controller while getHashesFromLocus is pending
|
|
4801
|
+
expect(parser.dataSets.main.syncAbortController).to.not.be.undefined;
|
|
4802
|
+
parser.dataSets.main.syncAbortController.abort();
|
|
4803
|
+
|
|
4804
|
+
// Resolve GET hashtree with mismatched hashes so the code would normally proceed to /sync
|
|
4805
|
+
resolveGetHashtree({
|
|
4806
|
+
body: {
|
|
4807
|
+
hashes: new Array(16).fill('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4808
|
+
dataSet: createDataSet('main', 16, 1100),
|
|
4809
|
+
},
|
|
4810
|
+
});
|
|
4811
|
+
|
|
4812
|
+
await testUtils.flushPromises();
|
|
4813
|
+
|
|
4814
|
+
// POST sync should NOT have been called because the controller was aborted
|
|
4815
|
+
assert.neverCalledWith(webexRequest, sinon.match({method: 'POST', uri: `${mainUrl}/sync`}));
|
|
4816
|
+
});
|
|
4817
|
+
|
|
4818
|
+
it('should abort the sync before /sync request when the controller is aborted for leafCount === 1 datasets', async () => {
|
|
4819
|
+
const parser = createHashTreeParser();
|
|
4820
|
+
const selfUrl = parser.dataSets.self.url;
|
|
4821
|
+
|
|
4822
|
+
// Pre-set an already-aborted controller so performSync picks it up via ??
|
|
4823
|
+
const abortedController = new AbortController();
|
|
4824
|
+
abortedController.abort();
|
|
4825
|
+
parser.dataSets.self.syncAbortController = abortedController;
|
|
4826
|
+
|
|
4827
|
+
// Mock POST sync - should NOT be called
|
|
4828
|
+
mockSendSyncRequestResponse(selfUrl, null);
|
|
4829
|
+
|
|
4830
|
+
// Trigger sync for self via heartbeat with mismatched root hash
|
|
4831
|
+
parser.handleMessage(
|
|
4832
|
+
{
|
|
4833
|
+
dataSets: [
|
|
4834
|
+
{
|
|
4835
|
+
...createDataSet('self', 1, 2100),
|
|
4836
|
+
url: parser.dataSets.self.url,
|
|
4837
|
+
root: 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb1',
|
|
4838
|
+
},
|
|
4839
|
+
],
|
|
4840
|
+
visibleDataSetsUrl,
|
|
4841
|
+
locusUrl,
|
|
4842
|
+
},
|
|
4843
|
+
'trigger self sync'
|
|
4844
|
+
);
|
|
4845
|
+
|
|
4846
|
+
// Fire the timer to start the sync
|
|
4847
|
+
await clock.tickAsync(1000);
|
|
4848
|
+
|
|
4849
|
+
// GET hashtree should NOT have been called (leafCount === 1 skips it)
|
|
4850
|
+
assert.neverCalledWith(webexRequest, sinon.match({method: 'GET', uri: `${selfUrl}/hashtree`}));
|
|
4851
|
+
|
|
4852
|
+
// POST sync should NOT have been called because the controller was already aborted
|
|
4853
|
+
assert.neverCalledWith(webexRequest, sinon.match({method: 'POST', uri: `${selfUrl}/sync`}));
|
|
4854
|
+
});
|
|
4855
|
+
|
|
4856
|
+
it('should unconditionally clear syncAbortController in the finally block', async () => {
|
|
4857
|
+
const parser = createHashTreeParser();
|
|
4858
|
+
const mainUrl = parser.dataSets.main.url;
|
|
4859
|
+
|
|
4860
|
+
// Mock GET hashtree to return matching hashes (early return, no sync needed)
|
|
4861
|
+
webexRequest
|
|
4862
|
+
.withArgs(sinon.match({method: 'GET', uri: `${mainUrl}/hashtree`}))
|
|
4863
|
+
.resolves({body: {}});
|
|
4864
|
+
|
|
4865
|
+
// Trigger sync for main
|
|
4866
|
+
parser.handleMessage(
|
|
4867
|
+
createHeartbeatMessage('main', 16, 1100, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4868
|
+
'trigger main sync'
|
|
4869
|
+
);
|
|
4870
|
+
|
|
4871
|
+
await clock.tickAsync(1000);
|
|
4872
|
+
|
|
4873
|
+
// After sync completes (even via early return), syncAbortController should be cleared
|
|
4874
|
+
expect(parser.dataSets.main.syncAbortController).to.be.undefined;
|
|
4875
|
+
});
|
|
4876
|
+
|
|
4877
|
+
it('should unconditionally clear syncAbortController even when sync throws an error', async () => {
|
|
4878
|
+
const parser = createHashTreeParser();
|
|
4879
|
+
const mainUrl = parser.dataSets.main.url;
|
|
4880
|
+
|
|
4881
|
+
// Mock GET hashtree to reject with a non-409 error
|
|
4882
|
+
webexRequest
|
|
4883
|
+
.withArgs(sinon.match({method: 'GET', uri: `${mainUrl}/hashtree`}))
|
|
4884
|
+
.rejects({statusCode: 500, message: 'Internal Server Error'});
|
|
4885
|
+
|
|
4886
|
+
// Trigger sync for main
|
|
4887
|
+
parser.handleMessage(
|
|
4888
|
+
createHeartbeatMessage('main', 16, 1100, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4889
|
+
'trigger main sync'
|
|
4890
|
+
);
|
|
4891
|
+
|
|
4892
|
+
await clock.tickAsync(1000);
|
|
4893
|
+
|
|
4894
|
+
// After sync completes with error, syncAbortController should still be cleared
|
|
4895
|
+
expect(parser.dataSets.main.syncAbortController).to.be.undefined;
|
|
4896
|
+
});
|
|
4897
|
+
|
|
4898
|
+
it('should reuse a pre-existing abort controller and respect its aborted state', async () => {
|
|
4899
|
+
const parser = createHashTreeParser();
|
|
4900
|
+
const mainUrl = parser.dataSets.main.url;
|
|
4901
|
+
|
|
4902
|
+
// Pre-set an AbortController and abort it before sync starts
|
|
4903
|
+
const preAbortedController = new AbortController();
|
|
4904
|
+
preAbortedController.abort();
|
|
4905
|
+
parser.dataSets.main.syncAbortController = preAbortedController;
|
|
4906
|
+
|
|
4907
|
+
// Mock GET hashtree to return mismatched hashes
|
|
4908
|
+
mockGetHashesFromLocusResponse(
|
|
4909
|
+
mainUrl,
|
|
4910
|
+
new Array(16).fill('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4911
|
+
createDataSet('main', 16, 1100)
|
|
4912
|
+
);
|
|
4913
|
+
|
|
4914
|
+
// Mock POST sync - should NOT be called
|
|
4915
|
+
mockSendSyncRequestResponse(mainUrl, null);
|
|
4916
|
+
|
|
4917
|
+
// Trigger sync for main
|
|
4918
|
+
parser.handleMessage(
|
|
4919
|
+
createHeartbeatMessage('main', 16, 1100, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4920
|
+
'trigger main sync'
|
|
4921
|
+
);
|
|
4922
|
+
|
|
4923
|
+
await clock.tickAsync(1000);
|
|
4924
|
+
|
|
4925
|
+
// POST sync should NOT have been called because the reused controller was already aborted
|
|
4926
|
+
assert.neverCalledWith(webexRequest, sinon.match({method: 'POST', uri: `${mainUrl}/sync`}));
|
|
4927
|
+
|
|
4928
|
+
// syncAbortController should be cleaned up
|
|
4929
|
+
expect(parser.dataSets.main.syncAbortController).to.be.undefined;
|
|
4930
|
+
});
|
|
4931
|
+
|
|
4932
|
+
it('should allow cancelPendingSyncsForDataSets to abort an in-flight sync via the shared controller', async () => {
|
|
4933
|
+
const parser = createHashTreeParser();
|
|
4934
|
+
const mainUrl = parser.dataSets.main.url;
|
|
4935
|
+
|
|
4936
|
+
// Use a deferred promise for GET hashtree
|
|
4937
|
+
let resolveGetHashtree;
|
|
4938
|
+
webexRequest.withArgs(sinon.match({method: 'GET', uri: `${mainUrl}/hashtree`})).callsFake(
|
|
4939
|
+
() =>
|
|
4940
|
+
new Promise((resolve) => {
|
|
4941
|
+
resolveGetHashtree = resolve;
|
|
4942
|
+
})
|
|
4943
|
+
);
|
|
4944
|
+
|
|
4945
|
+
mockSendSyncRequestResponse(mainUrl, null);
|
|
4946
|
+
|
|
4947
|
+
// Trigger sync for main
|
|
4948
|
+
parser.handleMessage(
|
|
4949
|
+
createHeartbeatMessage('main', 16, 1100, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4950
|
+
'trigger main sync'
|
|
4951
|
+
);
|
|
4952
|
+
|
|
4953
|
+
// Fire the timer to start sync
|
|
4954
|
+
await clock.tickAsync(1000);
|
|
4955
|
+
|
|
4956
|
+
// Verify controller is set
|
|
4957
|
+
expect(parser.dataSets.main.syncAbortController).to.not.be.undefined;
|
|
4958
|
+
|
|
4959
|
+
// Simulate a new heartbeat arriving that cancels the in-flight sync
|
|
4960
|
+
// (this is what happens in production via parseMessage -> cancelPendingSyncsForDataSets)
|
|
4961
|
+
parser.handleMessage(
|
|
4962
|
+
{
|
|
4963
|
+
dataSets: [
|
|
4964
|
+
{
|
|
4965
|
+
...createDataSet('main', 16, 1101),
|
|
4966
|
+
root: parser.dataSets.main.hashTree.getRootHash(), // matching hash so no new sync
|
|
4967
|
+
},
|
|
4968
|
+
],
|
|
4969
|
+
visibleDataSetsUrl,
|
|
4970
|
+
locusUrl,
|
|
4971
|
+
},
|
|
4972
|
+
'new heartbeat cancels sync'
|
|
4973
|
+
);
|
|
4974
|
+
|
|
4975
|
+
// Resolve the pending GET hashtree with mismatched hashes
|
|
4976
|
+
resolveGetHashtree({
|
|
4977
|
+
body: {
|
|
4978
|
+
hashes: new Array(16).fill('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa1'),
|
|
4979
|
+
dataSet: createDataSet('main', 16, 1101),
|
|
4980
|
+
},
|
|
4981
|
+
});
|
|
4982
|
+
|
|
4983
|
+
await testUtils.flushPromises();
|
|
4984
|
+
|
|
4985
|
+
// POST sync should NOT have been called because cancelPendingSyncsForDataSets aborted the controller
|
|
4986
|
+
assert.neverCalledWith(webexRequest, sinon.match({method: 'POST', uri: `${mainUrl}/sync`}));
|
|
4987
|
+
});
|
|
4988
|
+
});
|
|
4989
|
+
|
|
4737
4990
|
describe('#cleanUp', () => {
|
|
4738
4991
|
it('should stop the parser, clear all timers and clear all dataSets', () => {
|
|
4739
4992
|
const parser = createHashTreeParser();
|