@webex/internal-plugin-device 3.12.0-next.8 → 3.12.0-task-refactor.1

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/src/device.js CHANGED
@@ -6,13 +6,7 @@ import {orderBy} from 'lodash';
6
6
  import uuid from 'uuid';
7
7
 
8
8
  import METRICS from './metrics';
9
- import {
10
- FEATURE_COLLECTION_NAMES,
11
- DEVICE_EVENT_REGISTRATION_SUCCESS,
12
- MIN_DEVICES_FOR_CLEANUP,
13
- MAX_DELETION_CONFIRMATION_ATTEMPTS,
14
- DELETION_CONFIRMATION_DELAY_MS,
15
- } from './constants';
9
+ import {FEATURE_COLLECTION_NAMES, DEVICE_EVENT_REGISTRATION_SUCCESS} from './constants';
16
10
  import FeaturesModel from './features/features-model';
17
11
  import IpNetworkDetector from './ipNetworkDetector';
18
12
  import {CatalogDetails} from './types';
@@ -460,117 +454,46 @@ const Device = WebexPlugin.extend({
460
454
  });
461
455
  },
462
456
  /**
463
- * Fetches devices matching the current device type.
464
- * @returns {Promise<Array>} filtered device list
457
+ * Fetches the web devices and deletes the third of them which are not recent devices in use
458
+ * @returns {Promise<void, Error>}
465
459
  */
466
- _getDevicesOfCurrentType() {
467
- const {deviceType} = this._getBody();
468
-
460
+ deleteDevices() {
461
+ // Fetch devices with a GET request
469
462
  return this.request({
470
463
  method: 'GET',
471
464
  service: 'wdm',
472
465
  resource: 'devices',
473
- }).then((response) => response.body.devices.filter((item) => item.deviceType === deviceType));
474
- },
475
-
476
- /**
477
- * Waits until the server-side device count drops to or below targetCount,
478
- * polling up to maxAttempts times with a delay between each check.
479
- * @param {number} targetCount - resolve when device count drops to this value or below
480
- * @param {number} [attempt=0]
481
- * @returns {Promise<void>}
482
- */
483
- _waitForDeviceCountBelowLimit(targetCount, attempt = 0) {
484
- if (attempt >= MAX_DELETION_CONFIRMATION_ATTEMPTS) {
485
- this.logger.warn('device: max confirmation attempts reached, proceeding anyway');
486
-
487
- return Promise.resolve();
488
- }
489
-
490
- return new Promise((resolve) => setTimeout(resolve, DELETION_CONFIRMATION_DELAY_MS))
491
- .then(() => this._getDevicesOfCurrentType())
492
- .then((devices) => {
493
- this.logger.info(
494
- `device: confirmation check ${attempt + 1}/${MAX_DELETION_CONFIRMATION_ATTEMPTS}, ` +
495
- `${devices.length} devices remaining (target: ≤ ${targetCount})`
496
- );
497
-
498
- if (devices.length <= targetCount) {
499
- this.logger.info('device: device count is now safely below limit');
500
-
501
- return Promise.resolve();
502
- }
503
-
504
- return this._waitForDeviceCountBelowLimit(targetCount, attempt + 1);
505
- })
506
- .catch((error) => {
507
- this.logger.warn(
508
- `device: confirmation check ${attempt + 1} failed, proceeding anyway:`,
509
- error
510
- );
466
+ })
467
+ .then((response) => {
468
+ const {devices} = response.body;
511
469
 
512
- return Promise.resolve();
513
- });
514
- },
470
+ const {deviceType} = this._getBody();
515
471
 
516
- /**
517
- * Fetches the web devices and deletes the oldest third, then waits
518
- * for the server to confirm the count is below the limit.
519
- * @returns {Promise<void>}
520
- */
521
- deleteDevices() {
522
- let targetCount;
472
+ // Filter devices of type deviceType
473
+ const webDevices = devices.filter((item) => item.deviceType === deviceType);
523
474
 
524
- return this._getDevicesOfCurrentType()
525
- .then((webDevices) => {
526
475
  const sortedDevices = orderBy(webDevices, [(item) => new Date(item.modificationTime)]);
527
476
 
528
- if (sortedDevices.length <= MIN_DEVICES_FOR_CLEANUP) {
529
- this.logger.info(
530
- `device: only ${sortedDevices.length} devices found (minimum ${MIN_DEVICES_FOR_CLEANUP}), skipping cleanup`
477
+ // If there are more than two devices, delete the last third
478
+ if (sortedDevices.length > 2) {
479
+ const totalItems = sortedDevices.length;
480
+ const countToDelete = Math.ceil(totalItems / 3);
481
+ const urlsToDelete = sortedDevices.slice(0, countToDelete).map((item) => item.url);
482
+
483
+ return Promise.race(
484
+ urlsToDelete.map((url) => {
485
+ return this.request({
486
+ uri: url,
487
+ method: 'DELETE',
488
+ });
489
+ })
531
490
  );
532
-
533
- return Promise.resolve();
534
491
  }
535
492
 
536
- const devicesToDelete = sortedDevices.slice(0, Math.ceil(sortedDevices.length / 3));
537
- targetCount = sortedDevices.length - Math.min(5, devicesToDelete.length);
538
-
539
- this.logger.info(
540
- `device: deleting ${devicesToDelete.length} of ${webDevices.length} devices`
541
- );
542
-
543
- return Promise.all(
544
- devicesToDelete.map((device) =>
545
- this.request({uri: device.url, method: 'DELETE'})
546
- .then(() => ({status: 'fulfilled'}))
547
- .catch((reason) => ({status: 'rejected', reason}))
548
- )
549
- ).then((results) => {
550
- const failed = results.filter((r) => r.status === 'rejected');
551
-
552
- if (failed.length > 0) {
553
- this.logger.warn(
554
- `device: ${failed.length} of ${devicesToDelete.length} deletions failed (best-effort, continuing)`
555
- );
556
- }
557
- this.logger.info(
558
- `device: deleted ${devicesToDelete.length - failed.length} of ${
559
- devicesToDelete.length
560
- } devices`
561
- );
562
- });
563
- })
564
- .then(() =>
565
- targetCount !== undefined
566
- ? this._waitForDeviceCountBelowLimit(targetCount, 0)
567
- : Promise.resolve()
568
- )
569
- .then(() => {
570
- this.logger.info('device: device count confirmed below limit, cleanup successful');
493
+ return Promise.resolve();
571
494
  })
572
495
  .catch((error) => {
573
- this.logger.error('device: failed to delete devices:', error);
496
+ this.logger.error('Failed to retrieve devices:', error);
574
497
 
575
498
  return Promise.reject(error);
576
499
  });
@@ -596,11 +519,7 @@ const Device = WebexPlugin.extend({
596
519
 
597
520
  return this._registerInternal(deviceRegistrationOptions).catch((error) => {
598
521
  if (error?.body?.message === 'User has excessive device registrations') {
599
- this.logger.info('device: excessive device registrations detected, initiating cleanup');
600
-
601
522
  return this.deleteDevices().then(() => {
602
- this.logger.info('device: device cleanup complete, retrying registration');
603
-
604
523
  return this._registerInternal(deviceRegistrationOptions);
605
524
  });
606
525
  }
@@ -867,34 +786,6 @@ const Device = WebexPlugin.extend({
867
786
  return Promise.reject(new Error('device: failed to get the current websocket url'));
868
787
  },
869
788
 
870
- /**
871
- * Get sanitized processed debug features from session storage
872
- * these should be JSON encoded and in the form {feature1: true, feature2: false}
873
- *
874
- * @returns {Array<Object>} - Array of sanitized debug feature toggles
875
- */
876
- getDebugFeatures() {
877
- const sanitizedDebugFeatures = [];
878
- if (this.config.debugFeatureTogglesKey) {
879
- const debugFeaturesString = this.webex
880
- .getWindow()
881
- .sessionStorage.getItem(this.config.debugFeatureTogglesKey);
882
- if (debugFeaturesString) {
883
- const debugFeatures = JSON.parse(debugFeaturesString);
884
- Object.entries(debugFeatures).forEach(([key, value]) => {
885
- sanitizedDebugFeatures.push({
886
- key,
887
- val: value ? 'true' : 'false',
888
- mutable: true,
889
- lastModified: new Date().toISOString(),
890
- });
891
- });
892
- }
893
- }
894
-
895
- return sanitizedDebugFeatures;
896
- },
897
-
898
789
  /**
899
790
  * Process a successful device registration.
900
791
  *
@@ -923,14 +814,6 @@ const Device = WebexPlugin.extend({
923
814
  // When using the etag feature cache, user and entitlement features are still returned
924
815
  this.features.user.reset(features.user);
925
816
  this.features.entitlement.reset(features.entitlement);
926
- } else if (this.config.debugFeatureTogglesKey && body?.features?.developer) {
927
- // Add the debug feature toggles from session storage if available
928
- try {
929
- const debugFeatures = this.getDebugFeatures();
930
- body.features.developer.push(...debugFeatures);
931
- } catch (error) {
932
- this.logger.error('Failed to parse debug feature toggles from session storage:', error);
933
- }
934
817
  }
935
818
 
936
819
  // Assign the recieved DTO from **WDM** to this device.
@@ -1063,13 +946,6 @@ const Device = WebexPlugin.extend({
1063
946
  // Prototype the extended class in order to preserve the parent member.
1064
947
  Reflect.apply(WebexPlugin.prototype.initialize, this, args);
1065
948
 
1066
- this.listenToOnce(this.webex, 'change:config', () => {
1067
- // If debug feature toggles exist, clear the etag to ensure developer feature toggles are fetched
1068
- if (this.getDebugFeatures(this.config.debugFeatureTogglesKey).length > 0) {
1069
- this.set('etag', undefined);
1070
- }
1071
- });
1072
-
1073
949
  // Initialize feature events and listeners.
1074
950
  FEATURE_COLLECTION_NAMES.forEach((collectionName) => {
1075
951
  this.features.on(`change:${collectionName}`, (model, value, options) => {
@@ -188,7 +188,7 @@ const IpNetworkDetector = WebexPlugin.extend({
188
188
 
189
189
  results = await this.gatherLocalCandidates(pc);
190
190
  } finally {
191
- pc?.close();
191
+ pc.close();
192
192
  this.state = STATE.IDLE;
193
193
  }
194
194