@webex/plugin-meetings 3.12.0-next.60 → 3.12.0-next.62
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/constants.js +4 -1
- package/dist/hashTree/constants.js.map +1 -1
- package/dist/hashTree/hashTreeParser.js +197 -49
- package/dist/hashTree/hashTreeParser.js.map +1 -1
- package/dist/hashTree/utils.js +20 -0
- package/dist/hashTree/utils.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +11 -2
- package/dist/locus-info/index.js.map +1 -1
- package/dist/meeting/index.js +6 -0
- package/dist/meeting/index.js.map +1 -1
- package/dist/types/hashTree/constants.d.ts +1 -0
- package/dist/types/hashTree/hashTreeParser.d.ts +55 -4
- package/dist/types/hashTree/utils.d.ts +7 -0
- package/dist/types/locus-info/index.d.ts +5 -1
- package/dist/webinar/index.js +1 -1
- package/package.json +3 -3
- package/src/hashTree/constants.ts +7 -0
- package/src/hashTree/hashTreeParser.ts +156 -23
- package/src/hashTree/utils.ts +19 -0
- package/src/locus-info/index.ts +4 -2
- package/src/meeting/index.ts +2 -0
- package/test/unit/spec/hashTree/hashTreeParser.ts +197 -2
- package/test/unit/spec/hashTree/utils.ts +37 -0
- package/test/unit/spec/locus-info/index.js +12 -0
- package/test/unit/spec/meeting/index.js +25 -5
|
@@ -2,6 +2,11 @@ import HashTree from './hashTree';
|
|
|
2
2
|
import { Enum } from '../constants';
|
|
3
3
|
import { HtMeta, HashTreeObject } from './types';
|
|
4
4
|
import { LocusDTO } from '../locus-info/types';
|
|
5
|
+
export declare enum SyncAllBackoffType {
|
|
6
|
+
NONE = "none",
|
|
7
|
+
ONLY_LLM = "onlyLLM",
|
|
8
|
+
ALL = "all"
|
|
9
|
+
}
|
|
5
10
|
export interface DataSet {
|
|
6
11
|
url: string;
|
|
7
12
|
root: string;
|
|
@@ -88,7 +93,8 @@ declare class HashTreeParser {
|
|
|
88
93
|
state: 'active' | 'stopped';
|
|
89
94
|
private syncQueue;
|
|
90
95
|
private isSyncInProgress;
|
|
91
|
-
private
|
|
96
|
+
private syncAllBackoffType;
|
|
97
|
+
private dataSetsSyncedDuringBackoff;
|
|
92
98
|
private syncQueueProcessingPromise;
|
|
93
99
|
/**
|
|
94
100
|
* Constructor for HashTreeParser
|
|
@@ -341,6 +347,21 @@ declare class HashTreeParser {
|
|
|
341
347
|
* @returns {void}
|
|
342
348
|
*/
|
|
343
349
|
private cancelPendingSyncsForDataSets;
|
|
350
|
+
/**
|
|
351
|
+
* If a syncAllDatasets backoff sleep is in progress, marks the given data sets to be skipped
|
|
352
|
+
* after the sleep completes.
|
|
353
|
+
*
|
|
354
|
+
* @param {string[]} dataSetNames - The names of the data sets to mark
|
|
355
|
+
* @returns {void}
|
|
356
|
+
*/
|
|
357
|
+
private markDataSetsForSyncAllBackoffSkip;
|
|
358
|
+
/**
|
|
359
|
+
* Aborts any in-flight sync HTTP requests for the specified data sets.
|
|
360
|
+
*
|
|
361
|
+
* @param {string[]} dataSetNames - The names of the data sets whose syncs should be aborted
|
|
362
|
+
* @returns {void}
|
|
363
|
+
*/
|
|
364
|
+
private abortInFlightSyncs;
|
|
344
365
|
/**
|
|
345
366
|
* Enqueues a sync for the given data set. If the data set is already in the queue, the request is ignored.
|
|
346
367
|
* This ensures that all syncs are executed sequentially and no more than 1 sync runs at a time.
|
|
@@ -357,14 +378,44 @@ declare class HashTreeParser {
|
|
|
357
378
|
* @returns {Promise<void>}
|
|
358
379
|
*/
|
|
359
380
|
private processSyncQueue;
|
|
381
|
+
/**
|
|
382
|
+
* sets the backoff type for syncAllDatasets calls, which determines the scope of datasets that will be synced after the backoff delay.
|
|
383
|
+
*
|
|
384
|
+
* @param {boolean} onlyLLM - Whether the backoff is for a syncAllDatasets call that is syncing only LLM datasets
|
|
385
|
+
* @returns {void}
|
|
386
|
+
*/
|
|
387
|
+
private setSyncAllBackoffType;
|
|
388
|
+
/**
|
|
389
|
+
* Checks if a syncAll backoff is already in progress. If so, upgrades the scope from
|
|
390
|
+
* onlyLLM to all datasets when the new call has a broader scope.
|
|
391
|
+
*
|
|
392
|
+
* @param {boolean} onlyLLM - Whether the current call is for LLM datasets only
|
|
393
|
+
* @returns {boolean} true if a backoff is already pending (caller should return early)
|
|
394
|
+
*/
|
|
395
|
+
private tryUpgradePendingBackoff;
|
|
360
396
|
/**
|
|
361
397
|
* Syncs all data sets that have hash trees, one by one in sequence, using the priority order
|
|
362
|
-
* provided by sortByInitPriority().
|
|
363
|
-
*
|
|
398
|
+
* provided by sortByInitPriority().
|
|
399
|
+
*
|
|
400
|
+
* If a call is already waiting in the backoff delay phase, a new call with a broader scope
|
|
401
|
+
* (onlyLLM=false) will upgrade the pending scope, and the dataset list will be computed after
|
|
402
|
+
* the backoff using the upgraded scope. After the backoff, the sync queue handles deduplication
|
|
403
|
+
* so no guard is needed.
|
|
364
404
|
*
|
|
405
|
+
* @param {Object} [options={}] - Options for syncing
|
|
406
|
+
* @param {boolean} [options.onlyLLM=false] - Whether to sync only LLM based data sets
|
|
365
407
|
* @returns {Promise<void>}
|
|
366
408
|
*/
|
|
367
|
-
syncAllDatasets(
|
|
409
|
+
syncAllDatasets(options?: {
|
|
410
|
+
onlyLLM?: boolean;
|
|
411
|
+
}): Promise<void>;
|
|
412
|
+
/**
|
|
413
|
+
* Returns the list of data sets that have hash trees, sorted by the priority order provided by sortByInitPriority().
|
|
414
|
+
*
|
|
415
|
+
* @param {boolean} onlyLLM - Whether to include only LLM based data sets
|
|
416
|
+
* @returns {Array<{name: string, backoff: {maxMs: number, exponent: number}}>} The sorted list of data sets with their backoff configurations
|
|
417
|
+
*/
|
|
418
|
+
private getSortedDataSetsWithHashTrees;
|
|
368
419
|
/**
|
|
369
420
|
* Runs the sync algorithm for the given data set.
|
|
370
421
|
*
|
|
@@ -31,3 +31,10 @@ export declare const deleteNestedObjectsWithHtMeta: (currentLocusPart: any, pare
|
|
|
31
31
|
export declare function sortByInitPriority<T extends {
|
|
32
32
|
name: string;
|
|
33
33
|
}>(items: T[], priority: string[]): T[];
|
|
34
|
+
/**
|
|
35
|
+
* Sleeps for the specified amount of milliseconds
|
|
36
|
+
*
|
|
37
|
+
* @param {number} ms amount of milliseconds to sleep
|
|
38
|
+
* @returns {Promise<void>} A promise that resolves after the specified delay
|
|
39
|
+
*/
|
|
40
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
@@ -215,9 +215,13 @@ export default class LocusInfo extends EventsScope {
|
|
|
215
215
|
* Triggers a sync of all hash tree datasets for all hash tree parsers associated with this meeting.
|
|
216
216
|
* The syncs are executed sequentially within each parser.
|
|
217
217
|
*
|
|
218
|
+
* @param {Object} [options={}] - Options for syncing
|
|
219
|
+
* @param {boolean} [options.onlyLLM=false] - Whether to sync only LLM based data sets
|
|
218
220
|
* @returns {Promise<void>}
|
|
219
221
|
*/
|
|
220
|
-
syncAllHashTreeDatasets(
|
|
222
|
+
syncAllHashTreeDatasets(options?: {
|
|
223
|
+
onlyLLM?: boolean;
|
|
224
|
+
}): Promise<void>;
|
|
221
225
|
/**
|
|
222
226
|
* Callback registered with HashTreeParser to receive locus info updates.
|
|
223
227
|
* Updates our locus info based on the data parsed by the hash tree parser.
|
package/dist/webinar/index.js
CHANGED
package/package.json
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@webex/common": "3.12.0-next.1",
|
|
65
|
-
"@webex/internal-media-core": "2.
|
|
65
|
+
"@webex/internal-media-core": "2.25.1",
|
|
66
66
|
"@webex/internal-plugin-conversation": "3.12.0-next.17",
|
|
67
67
|
"@webex/internal-plugin-device": "3.12.0-next.15",
|
|
68
68
|
"@webex/internal-plugin-llm": "3.12.0-next.18",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@webex/internal-plugin-support": "3.12.0-next.17",
|
|
72
72
|
"@webex/internal-plugin-user": "3.12.0-next.16",
|
|
73
73
|
"@webex/internal-plugin-voicea": "3.12.0-next.18",
|
|
74
|
-
"@webex/media-helpers": "3.12.0-next.
|
|
74
|
+
"@webex/media-helpers": "3.12.0-next.4",
|
|
75
75
|
"@webex/plugin-people": "3.12.0-next.16",
|
|
76
76
|
"@webex/plugin-rooms": "3.12.0-next.17",
|
|
77
77
|
"@webex/ts-sdp": "^1.8.1",
|
|
@@ -94,5 +94,5 @@
|
|
|
94
94
|
"//": [
|
|
95
95
|
"TODO: upgrade jwt-decode when moving to node 18"
|
|
96
96
|
],
|
|
97
|
-
"version": "3.12.0-next.
|
|
97
|
+
"version": "3.12.0-next.62"
|
|
98
98
|
}
|
|
@@ -17,3 +17,10 @@ export const DataSetNames = {
|
|
|
17
17
|
// participant object for webinar attendees. If SELF were initialized first, locus.info
|
|
18
18
|
// would not yet be populated and the attendee participant would be skipped.
|
|
19
19
|
export const DATA_SET_INIT_PRIORITY: string[] = [DataSetNames.MAIN, DataSetNames.SELF];
|
|
20
|
+
|
|
21
|
+
// Data sets for which we normally receive events over LLM connection
|
|
22
|
+
export const LLM_DATASET_NAMES = [
|
|
23
|
+
DataSetNames.MAIN,
|
|
24
|
+
DataSetNames.ATD_ACTIVE,
|
|
25
|
+
DataSetNames.ATD_UNMUTED,
|
|
26
|
+
];
|
|
@@ -4,10 +4,16 @@ import LoggerProxy from '../common/logs/logger-proxy';
|
|
|
4
4
|
import Metrics from '../metrics';
|
|
5
5
|
import BEHAVIORAL_METRICS from '../metrics/constants';
|
|
6
6
|
import {Enum, HTTP_VERBS} from '../constants';
|
|
7
|
-
import {DataSetNames, DATA_SET_INIT_PRIORITY, EMPTY_HASH} from './constants';
|
|
7
|
+
import {DataSetNames, DATA_SET_INIT_PRIORITY, EMPTY_HASH, LLM_DATASET_NAMES} from './constants';
|
|
8
8
|
import {ObjectType, HtMeta, HashTreeObject} from './types';
|
|
9
9
|
import {LocusDTO, LocusErrorCodes} from '../locus-info/types';
|
|
10
|
-
import {deleteNestedObjectsWithHtMeta, isMetadata, sortByInitPriority} from './utils';
|
|
10
|
+
import {deleteNestedObjectsWithHtMeta, isMetadata, sleep, sortByInitPriority} from './utils';
|
|
11
|
+
|
|
12
|
+
export enum SyncAllBackoffType {
|
|
13
|
+
NONE = 'none',
|
|
14
|
+
ONLY_LLM = 'onlyLLM',
|
|
15
|
+
ALL = 'all',
|
|
16
|
+
}
|
|
11
17
|
|
|
12
18
|
export interface DataSet {
|
|
13
19
|
url: string;
|
|
@@ -122,7 +128,10 @@ class HashTreeParser {
|
|
|
122
128
|
state: 'active' | 'stopped';
|
|
123
129
|
private syncQueue: Array<{dataSetName: string; reason: string; isInitialization?: boolean}> = [];
|
|
124
130
|
private isSyncInProgress = false;
|
|
125
|
-
|
|
131
|
+
// tracks whether syncAllDatasets is currently in its backoff delay phase and with what scope
|
|
132
|
+
private syncAllBackoffType: SyncAllBackoffType = SyncAllBackoffType.NONE;
|
|
133
|
+
// datasets that received messages during the syncAllDatasets backoff sleep and should be skipped
|
|
134
|
+
private dataSetsSyncedDuringBackoff: Set<string> = new Set();
|
|
126
135
|
private syncQueueProcessingPromise: Promise<void> = Promise.resolve();
|
|
127
136
|
|
|
128
137
|
/**
|
|
@@ -1342,8 +1351,14 @@ class HashTreeParser {
|
|
|
1342
1351
|
// parseMessage() -> cancelPendingSyncsForDataSets() doesn't log a
|
|
1343
1352
|
// misleading "aborting sync" message for this already-completed sync
|
|
1344
1353
|
dataSet.syncAbortController = undefined;
|
|
1354
|
+
|
|
1345
1355
|
// the format of sync response is the same as messages, so we can reuse the same handler
|
|
1346
|
-
this.handleMessage(
|
|
1356
|
+
this.handleMessage(
|
|
1357
|
+
syncResponse,
|
|
1358
|
+
`via sync API (${
|
|
1359
|
+
isInitialization ? 'init' : `${Object.keys(leavesData).length} mismatched leaves`
|
|
1360
|
+
})`
|
|
1361
|
+
);
|
|
1347
1362
|
}
|
|
1348
1363
|
} catch (error) {
|
|
1349
1364
|
if (!this.handleSyncErrors(error)) {
|
|
@@ -1377,6 +1392,32 @@ class HashTreeParser {
|
|
|
1377
1392
|
);
|
|
1378
1393
|
}
|
|
1379
1394
|
|
|
1395
|
+
this.markDataSetsForSyncAllBackoffSkip(dataSetNames);
|
|
1396
|
+
this.abortInFlightSyncs(dataSetNames);
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* If a syncAllDatasets backoff sleep is in progress, marks the given data sets to be skipped
|
|
1401
|
+
* after the sleep completes.
|
|
1402
|
+
*
|
|
1403
|
+
* @param {string[]} dataSetNames - The names of the data sets to mark
|
|
1404
|
+
* @returns {void}
|
|
1405
|
+
*/
|
|
1406
|
+
private markDataSetsForSyncAllBackoffSkip(dataSetNames: string[]): void {
|
|
1407
|
+
if (this.syncAllBackoffType !== SyncAllBackoffType.NONE) {
|
|
1408
|
+
for (const name of dataSetNames) {
|
|
1409
|
+
this.dataSetsSyncedDuringBackoff.add(name);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
/**
|
|
1415
|
+
* Aborts any in-flight sync HTTP requests for the specified data sets.
|
|
1416
|
+
*
|
|
1417
|
+
* @param {string[]} dataSetNames - The names of the data sets whose syncs should be aborted
|
|
1418
|
+
* @returns {void}
|
|
1419
|
+
*/
|
|
1420
|
+
private abortInFlightSyncs(dataSetNames: string[]): void {
|
|
1380
1421
|
for (const name of dataSetNames) {
|
|
1381
1422
|
if (this.dataSets[name]?.syncAbortController) {
|
|
1382
1423
|
LoggerProxy.logger.info(
|
|
@@ -1451,39 +1492,129 @@ class HashTreeParser {
|
|
|
1451
1492
|
}
|
|
1452
1493
|
}
|
|
1453
1494
|
|
|
1495
|
+
/**
|
|
1496
|
+
* sets the backoff type for syncAllDatasets calls, which determines the scope of datasets that will be synced after the backoff delay.
|
|
1497
|
+
*
|
|
1498
|
+
* @param {boolean} onlyLLM - Whether the backoff is for a syncAllDatasets call that is syncing only LLM datasets
|
|
1499
|
+
* @returns {void}
|
|
1500
|
+
*/
|
|
1501
|
+
private setSyncAllBackoffType(onlyLLM: boolean): void {
|
|
1502
|
+
this.syncAllBackoffType = onlyLLM ? SyncAllBackoffType.ONLY_LLM : SyncAllBackoffType.ALL;
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/**
|
|
1506
|
+
* Checks if a syncAll backoff is already in progress. If so, upgrades the scope from
|
|
1507
|
+
* onlyLLM to all datasets when the new call has a broader scope.
|
|
1508
|
+
*
|
|
1509
|
+
* @param {boolean} onlyLLM - Whether the current call is for LLM datasets only
|
|
1510
|
+
* @returns {boolean} true if a backoff is already pending (caller should return early)
|
|
1511
|
+
*/
|
|
1512
|
+
private tryUpgradePendingBackoff(onlyLLM: boolean): boolean {
|
|
1513
|
+
if (this.syncAllBackoffType !== SyncAllBackoffType.NONE) {
|
|
1514
|
+
if (!onlyLLM && this.syncAllBackoffType === SyncAllBackoffType.ONLY_LLM) {
|
|
1515
|
+
this.setSyncAllBackoffType(false);
|
|
1516
|
+
LoggerProxy.logger.info(
|
|
1517
|
+
`HashTreeParser#syncAllDatasets --> ${this.debugId} upgraded pending syncAll from onlyLLM to all datasets`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
return true;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
return false;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1454
1527
|
/**
|
|
1455
1528
|
* Syncs all data sets that have hash trees, one by one in sequence, using the priority order
|
|
1456
|
-
* provided by sortByInitPriority().
|
|
1457
|
-
* call is already in progress.
|
|
1529
|
+
* provided by sortByInitPriority().
|
|
1458
1530
|
*
|
|
1531
|
+
* If a call is already waiting in the backoff delay phase, a new call with a broader scope
|
|
1532
|
+
* (onlyLLM=false) will upgrade the pending scope, and the dataset list will be computed after
|
|
1533
|
+
* the backoff using the upgraded scope. After the backoff, the sync queue handles deduplication
|
|
1534
|
+
* so no guard is needed.
|
|
1535
|
+
*
|
|
1536
|
+
* @param {Object} [options={}] - Options for syncing
|
|
1537
|
+
* @param {boolean} [options.onlyLLM=false] - Whether to sync only LLM based data sets
|
|
1459
1538
|
* @returns {Promise<void>}
|
|
1460
1539
|
*/
|
|
1461
|
-
public async syncAllDatasets(): Promise<void> {
|
|
1540
|
+
public async syncAllDatasets(options: {onlyLLM?: boolean} = {}): Promise<void> {
|
|
1541
|
+
const {onlyLLM = false} = options;
|
|
1462
1542
|
if (this.state === 'stopped') return;
|
|
1463
|
-
if (this.isSyncAllInProgress) return;
|
|
1464
1543
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1544
|
+
// if we're already in the backoff delay phase, try to upgrade the scope instead of starting a new one
|
|
1545
|
+
if (this.tryUpgradePendingBackoff(onlyLLM)) {
|
|
1546
|
+
return;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
const dataSetsToSync = this.getSortedDataSetsWithHashTrees(onlyLLM);
|
|
1550
|
+
|
|
1551
|
+
if (dataSetsToSync.length === 0) return;
|
|
1552
|
+
|
|
1553
|
+
this.setSyncAllBackoffType(onlyLLM);
|
|
1554
|
+
|
|
1555
|
+
const delay = this.getWeightedBackoffTime(dataSetsToSync[0].backoff);
|
|
1556
|
+
|
|
1557
|
+
LoggerProxy.logger.info(
|
|
1558
|
+
`HashTreeParser#syncAllDatasets --> ${this.debugId} starting backoff delay of ${delay}ms (onlyLLM=${onlyLLM})`
|
|
1559
|
+
);
|
|
1560
|
+
|
|
1561
|
+
// delay the start of the syncs - this is a Locus requirement to avoid thundering herd issues
|
|
1562
|
+
await sleep(delay);
|
|
1563
|
+
|
|
1564
|
+
// read the (possibly upgraded) scope and clear the backoff flag
|
|
1565
|
+
const effectiveBackoffType = this.syncAllBackoffType;
|
|
1566
|
+
const skippedDataSets = this.dataSetsSyncedDuringBackoff;
|
|
1567
|
+
|
|
1568
|
+
this.syncAllBackoffType = SyncAllBackoffType.NONE;
|
|
1569
|
+
this.dataSetsSyncedDuringBackoff = new Set();
|
|
1470
1570
|
|
|
1471
|
-
|
|
1571
|
+
if ((this.state as string) === 'stopped') return;
|
|
1472
1572
|
|
|
1573
|
+
// re-evaluate the dataset list after the sleep, since the scope may have been upgraded
|
|
1574
|
+
// and exclude datasets that received messages during the backoff sleep
|
|
1575
|
+
const effectiveDataSetsToSync = this.getSortedDataSetsWithHashTrees(
|
|
1576
|
+
effectiveBackoffType === SyncAllBackoffType.ONLY_LLM
|
|
1577
|
+
).filter((ds) => !skippedDataSets.has(ds.name));
|
|
1578
|
+
|
|
1579
|
+
if (skippedDataSets.size > 0) {
|
|
1473
1580
|
LoggerProxy.logger.info(
|
|
1474
|
-
`HashTreeParser#syncAllDatasets --> ${
|
|
1475
|
-
.
|
|
1476
|
-
|
|
1581
|
+
`HashTreeParser#syncAllDatasets --> ${
|
|
1582
|
+
this.debugId
|
|
1583
|
+
} skipping datasets that received messages during backoff: ${[...skippedDataSets].join(
|
|
1584
|
+
', '
|
|
1585
|
+
)}`
|
|
1477
1586
|
);
|
|
1587
|
+
}
|
|
1478
1588
|
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1589
|
+
LoggerProxy.logger.info(
|
|
1590
|
+
`HashTreeParser#syncAllDatasets --> ${this.debugId} syncing ${
|
|
1591
|
+
effectiveBackoffType === SyncAllBackoffType.ONLY_LLM ? 'only LLM' : 'all'
|
|
1592
|
+
} datasets: ${effectiveDataSetsToSync.map((ds) => ds.name).join(', ')}`
|
|
1593
|
+
);
|
|
1482
1594
|
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1595
|
+
for (const ds of effectiveDataSetsToSync) {
|
|
1596
|
+
this.enqueueSyncForDataset(ds.name, 'syncAllDatasets');
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
await this.syncQueueProcessingPromise;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
/**
|
|
1603
|
+
* Returns the list of data sets that have hash trees, sorted by the priority order provided by sortByInitPriority().
|
|
1604
|
+
*
|
|
1605
|
+
* @param {boolean} onlyLLM - Whether to include only LLM based data sets
|
|
1606
|
+
* @returns {Array<{name: string, backoff: {maxMs: number, exponent: number}}>} The sorted list of data sets with their backoff configurations
|
|
1607
|
+
*/
|
|
1608
|
+
private getSortedDataSetsWithHashTrees(onlyLLM: boolean) {
|
|
1609
|
+
let dataSets = Object.values(this.dataSets)
|
|
1610
|
+
.filter((dataSet) => dataSet?.hashTree)
|
|
1611
|
+
.map((dataSet) => ({name: dataSet.name, backoff: dataSet.backoff}));
|
|
1612
|
+
|
|
1613
|
+
if (onlyLLM) {
|
|
1614
|
+
dataSets = dataSets.filter((ds) => LLM_DATASET_NAMES.includes(ds.name));
|
|
1486
1615
|
}
|
|
1616
|
+
|
|
1617
|
+
return sortByInitPriority(dataSets, DATA_SET_INIT_PRIORITY);
|
|
1487
1618
|
}
|
|
1488
1619
|
|
|
1489
1620
|
/**
|
|
@@ -1623,6 +1754,8 @@ class HashTreeParser {
|
|
|
1623
1754
|
);
|
|
1624
1755
|
this.stopAllTimers();
|
|
1625
1756
|
this.syncQueue = [];
|
|
1757
|
+
this.syncAllBackoffType = SyncAllBackoffType.NONE;
|
|
1758
|
+
this.dataSetsSyncedDuringBackoff = new Set();
|
|
1626
1759
|
Object.values(this.dataSets).forEach((dataSet) => {
|
|
1627
1760
|
dataSet.syncAbortController?.abort();
|
|
1628
1761
|
dataSet.syncAbortController = undefined;
|
package/src/hashTree/utils.ts
CHANGED
|
@@ -77,3 +77,22 @@ export function sortByInitPriority<T extends {name: string}>(items: T[], priorit
|
|
|
77
77
|
|
|
78
78
|
return [...prioritized, ...rest];
|
|
79
79
|
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Sleeps for the specified amount of milliseconds
|
|
83
|
+
*
|
|
84
|
+
* @param {number} ms amount of milliseconds to sleep
|
|
85
|
+
* @returns {Promise<void>} A promise that resolves after the specified delay
|
|
86
|
+
*/
|
|
87
|
+
export function sleep(ms: number): Promise<void> {
|
|
88
|
+
if (ms <= 0) {
|
|
89
|
+
return Promise.resolve();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
// start a timer that will resolve the promise after the specified delay
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
resolve();
|
|
96
|
+
}, ms);
|
|
97
|
+
});
|
|
98
|
+
}
|
package/src/locus-info/index.ts
CHANGED
|
@@ -1203,13 +1203,15 @@ export default class LocusInfo extends EventsScope {
|
|
|
1203
1203
|
* Triggers a sync of all hash tree datasets for all hash tree parsers associated with this meeting.
|
|
1204
1204
|
* The syncs are executed sequentially within each parser.
|
|
1205
1205
|
*
|
|
1206
|
+
* @param {Object} [options={}] - Options for syncing
|
|
1207
|
+
* @param {boolean} [options.onlyLLM=false] - Whether to sync only LLM based data sets
|
|
1206
1208
|
* @returns {Promise<void>}
|
|
1207
1209
|
*/
|
|
1208
|
-
async syncAllHashTreeDatasets(): Promise<void> {
|
|
1210
|
+
async syncAllHashTreeDatasets(options: {onlyLLM?: boolean} = {}): Promise<void> {
|
|
1209
1211
|
for (const [, entry] of this.hashTreeParsers) {
|
|
1210
1212
|
if (entry.parser) {
|
|
1211
1213
|
// eslint-disable-next-line no-await-in-loop
|
|
1212
|
-
await entry.parser.syncAllDatasets();
|
|
1214
|
+
await entry.parser.syncAllDatasets(options);
|
|
1213
1215
|
}
|
|
1214
1216
|
}
|
|
1215
1217
|
}
|
package/src/meeting/index.ts
CHANGED
|
@@ -6135,6 +6135,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6135
6135
|
*/
|
|
6136
6136
|
private handleLLMOnline = (): void => {
|
|
6137
6137
|
this.restoreLLMSubscriptionsIfNeeded();
|
|
6138
|
+
this.locusInfo.syncAllHashTreeDatasets({onlyLLM: true});
|
|
6138
6139
|
|
|
6139
6140
|
Trigger.trigger(
|
|
6140
6141
|
this,
|
|
@@ -6687,6 +6688,7 @@ export default class Meeting extends StatelessWebexPlugin {
|
|
|
6687
6688
|
return this.webex.internal.llm
|
|
6688
6689
|
.registerAndConnect(url, dataChannelUrl, datachannelToken)
|
|
6689
6690
|
.then((registerAndConnectResult) => {
|
|
6691
|
+
this.locusInfo.syncAllHashTreeDatasets({onlyLLM: true});
|
|
6690
6692
|
// Record ownership of the default LLM session for this meeting so
|
|
6691
6693
|
// subsequent cross-meeting `updateLLMConnection` / `cleanupLLMConneciton`
|
|
6692
6694
|
// calls can detect and skip work that doesn't belong to them.
|