@webex/plugin-meetings 3.0.0-beta.185 → 3.0.0-beta.187
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/breakouts/breakout.js +1 -1
- package/dist/breakouts/index.js +1 -1
- package/dist/common/queue.js +24 -9
- package/dist/common/queue.js.map +1 -1
- package/dist/interpretation/index.js +1 -1
- package/dist/interpretation/siLanguage.js +1 -1
- package/dist/locus-info/index.js +50 -16
- package/dist/locus-info/index.js.map +1 -1
- package/dist/locus-info/parser.js +174 -59
- package/dist/locus-info/parser.js.map +1 -1
- package/dist/meeting/muteState.js +1 -1
- package/dist/meeting/muteState.js.map +1 -1
- package/dist/meeting/request.js +7 -44
- package/dist/meeting/request.js.map +1 -1
- package/dist/meeting/util.js +1 -1
- package/dist/meeting/util.js.map +1 -1
- package/dist/types/common/queue.d.ts +9 -7
- package/dist/types/locus-info/index.d.ts +7 -0
- package/dist/types/locus-info/parser.d.ts +50 -6
- package/dist/types/meeting/request.d.ts +3 -16
- package/package.json +19 -19
- package/src/common/queue.ts +22 -8
- package/src/locus-info/index.ts +53 -15
- package/src/locus-info/parser.ts +180 -38
- package/src/meeting/muteState.ts +1 -1
- package/src/meeting/request.ts +6 -47
- package/src/meeting/util.ts +1 -1
- package/test/unit/spec/common/queue.js +31 -2
- package/test/unit/spec/locus-info/index.js +352 -15
- package/test/unit/spec/locus-info/parser.js +0 -22
- package/test/unit/spec/meeting/muteState.js +1 -1
- package/test/unit/spec/meeting/utils.js +5 -5
package/src/locus-info/parser.ts
CHANGED
|
@@ -1,8 +1,26 @@
|
|
|
1
1
|
import {difference} from 'lodash';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import SortedQueue from '../common/queue';
|
|
4
4
|
import LoggerProxy from '../common/logs/logger-proxy';
|
|
5
5
|
|
|
6
|
+
const MAX_OOO_DELTA_COUNT = 5; // when we receive an out-of-order delta and the queue builds up to MAX_OOO_DELTA_COUNT, we do a sync with Locus
|
|
7
|
+
const OOO_DELTA_WAIT_TIME = 10000; // [ms] minimum wait time before we do a sync if we get out-of-order deltas
|
|
8
|
+
const OOO_DELTA_WAIT_TIME_RANDOM_DELAY = 5000; // [ms] max random delay added to OOO_DELTA_WAIT_TIME
|
|
9
|
+
|
|
10
|
+
type LocusDeltaDto = {
|
|
11
|
+
baseSequence: {
|
|
12
|
+
rangeStart: number;
|
|
13
|
+
rangeEnd: number;
|
|
14
|
+
entries: number[];
|
|
15
|
+
};
|
|
16
|
+
sequence: {
|
|
17
|
+
rangeStart: number;
|
|
18
|
+
rangeEnd: number;
|
|
19
|
+
entries: number[];
|
|
20
|
+
};
|
|
21
|
+
syncUrl: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
6
24
|
/**
|
|
7
25
|
* Locus Delta Parser
|
|
8
26
|
* @private
|
|
@@ -10,11 +28,11 @@ import LoggerProxy from '../common/logs/logger-proxy';
|
|
|
10
28
|
*/
|
|
11
29
|
export default class Parser {
|
|
12
30
|
// processing status
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
status:
|
|
32
|
+
| 'IDLE' // not doing anything
|
|
33
|
+
| 'PAUSED' // paused, because we are doing a sync
|
|
34
|
+
| 'WORKING' // processing a delta event
|
|
35
|
+
| 'BLOCKED'; // received an out-of-order delta, so waiting for the missing one
|
|
18
36
|
|
|
19
37
|
// loci comparison states
|
|
20
38
|
static loci = {
|
|
@@ -24,21 +42,59 @@ export default class Parser {
|
|
|
24
42
|
DESYNC: 'DESYNC',
|
|
25
43
|
USE_INCOMING: 'USE_INCOMING',
|
|
26
44
|
USE_CURRENT: 'USE_CURRENT',
|
|
45
|
+
WAIT: 'WAIT',
|
|
27
46
|
ERROR: 'ERROR',
|
|
28
47
|
};
|
|
29
48
|
|
|
30
|
-
queue:
|
|
49
|
+
queue: SortedQueue<LocusDeltaDto>;
|
|
31
50
|
workingCopy: any;
|
|
51
|
+
syncTimer: null | number | NodeJS.Timeout;
|
|
32
52
|
|
|
33
53
|
/**
|
|
34
54
|
* @constructs Parser
|
|
35
55
|
*/
|
|
36
56
|
constructor() {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
const deltaCompareFunc = (left: LocusDeltaDto, right: LocusDeltaDto) => {
|
|
58
|
+
const {LT, GT} = Parser.loci;
|
|
59
|
+
const {extractComparisonState: extract} = Parser;
|
|
60
|
+
|
|
61
|
+
if (Parser.isSequenceEmpty(left)) {
|
|
62
|
+
return -1;
|
|
63
|
+
}
|
|
64
|
+
if (Parser.isSequenceEmpty(right)) {
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
const result = extract(Parser.compareSequence(left.baseSequence, right.baseSequence));
|
|
68
|
+
|
|
69
|
+
if (result === LT) {
|
|
70
|
+
return -1;
|
|
71
|
+
}
|
|
72
|
+
if (result === GT) {
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return 0;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
this.queue = new SortedQueue<LocusDeltaDto>(deltaCompareFunc);
|
|
80
|
+
this.status = 'IDLE';
|
|
40
81
|
this.onDeltaAction = null;
|
|
41
82
|
this.workingCopy = null;
|
|
83
|
+
this.syncTimer = null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Returns a debug string representing a locus delta - useful for logging
|
|
88
|
+
*
|
|
89
|
+
* @param {LocusDeltaDto} locus Locus delta
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
static locus2string(locus: LocusDeltaDto) {
|
|
93
|
+
if (!locus.sequence?.entries) {
|
|
94
|
+
return 'invalid';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return locus.sequence.entries.length ? `seq=${locus.sequence.entries.at(-1)}` : 'empty';
|
|
42
98
|
}
|
|
43
99
|
|
|
44
100
|
/**
|
|
@@ -208,7 +264,7 @@ export default class Parser {
|
|
|
208
264
|
* @returns {string} loci comparison state
|
|
209
265
|
*/
|
|
210
266
|
private static compareDelta(current, incoming) {
|
|
211
|
-
const {LT, GT, EQ, DESYNC, USE_INCOMING} = Parser.loci;
|
|
267
|
+
const {LT, GT, EQ, DESYNC, USE_INCOMING, WAIT} = Parser.loci;
|
|
212
268
|
|
|
213
269
|
const {extractComparisonState: extract} = Parser;
|
|
214
270
|
const {packComparisonResult: pack} = Parser;
|
|
@@ -228,6 +284,17 @@ export default class Parser {
|
|
|
228
284
|
comparison = USE_INCOMING;
|
|
229
285
|
break;
|
|
230
286
|
|
|
287
|
+
case LT:
|
|
288
|
+
if (extract(Parser.compareSequence(incoming.baseSequence, incoming.sequence)) === EQ) {
|
|
289
|
+
// special case where Locus sends a delta with baseSequence === sequence to trigger a sync,
|
|
290
|
+
// because the delta event is too large to be sent over mercury connection
|
|
291
|
+
comparison = DESYNC;
|
|
292
|
+
} else {
|
|
293
|
+
// the incoming locus has baseSequence from the future, so it is out-of-order,
|
|
294
|
+
// we are missing 1 or more locus that should be in front of it, we need to wait for it
|
|
295
|
+
comparison = WAIT;
|
|
296
|
+
}
|
|
297
|
+
break;
|
|
231
298
|
default:
|
|
232
299
|
comparison = DESYNC;
|
|
233
300
|
}
|
|
@@ -436,17 +503,10 @@ export default class Parser {
|
|
|
436
503
|
*/
|
|
437
504
|
isValidLocus(newLoci) {
|
|
438
505
|
let isValid = false;
|
|
439
|
-
const {IDLE} = Parser.status;
|
|
440
506
|
const {isLoci} = Parser;
|
|
441
|
-
// @ts-ignore
|
|
442
|
-
const setStatus = (status) => {
|
|
443
|
-
// @ts-ignore
|
|
444
|
-
this.status = status;
|
|
445
|
-
};
|
|
446
507
|
|
|
447
508
|
// one or both objects are not locus delta events
|
|
448
509
|
if (!isLoci(this.workingCopy) || !isLoci(newLoci)) {
|
|
449
|
-
setStatus(IDLE);
|
|
450
510
|
LoggerProxy.logger.info(
|
|
451
511
|
'Locus-info:parser#processDeltaEvent --> Ignoring non-locus object. workingCopy:',
|
|
452
512
|
this.workingCopy,
|
|
@@ -498,19 +558,25 @@ export default class Parser {
|
|
|
498
558
|
* @returns {undefined}
|
|
499
559
|
*/
|
|
500
560
|
nextEvent() {
|
|
501
|
-
|
|
502
|
-
if (this.status === Parser.status.PAUSED) {
|
|
561
|
+
if (this.status === 'PAUSED') {
|
|
503
562
|
LoggerProxy.logger.info('Locus-info:parser#nextEvent --> Locus parser paused.');
|
|
504
563
|
|
|
505
564
|
return;
|
|
506
565
|
}
|
|
507
566
|
|
|
567
|
+
if (this.status === 'BLOCKED') {
|
|
568
|
+
LoggerProxy.logger.info(
|
|
569
|
+
'Locus-info:parser#nextEvent --> Locus parser blocked by out-of-order delta.'
|
|
570
|
+
);
|
|
571
|
+
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
|
|
508
575
|
// continue processing until queue is empty
|
|
509
576
|
if (this.queue.size() > 0) {
|
|
510
577
|
this.processDeltaEvent();
|
|
511
578
|
} else {
|
|
512
|
-
|
|
513
|
-
this.status = Parser.status.IDLE;
|
|
579
|
+
this.status = 'IDLE';
|
|
514
580
|
}
|
|
515
581
|
}
|
|
516
582
|
|
|
@@ -532,15 +598,20 @@ export default class Parser {
|
|
|
532
598
|
onDeltaEvent(loci) {
|
|
533
599
|
// enqueue the new loci
|
|
534
600
|
this.queue.enqueue(loci);
|
|
535
|
-
// start processing events in the queue if idle
|
|
536
|
-
// and a function handler is defined
|
|
537
|
-
// @ts-ignore
|
|
538
|
-
if (this.status === Parser.status.IDLE && this.onDeltaAction) {
|
|
539
|
-
// Update status, ensure we only process one event at a time.
|
|
540
|
-
// @ts-ignore
|
|
541
|
-
this.status = Parser.status.WORKING;
|
|
542
601
|
|
|
543
|
-
|
|
602
|
+
if (this.onDeltaAction) {
|
|
603
|
+
if (this.status === 'BLOCKED') {
|
|
604
|
+
if (this.queue.size() > MAX_OOO_DELTA_COUNT) {
|
|
605
|
+
this.triggerSync('queue too big, blocked on out-of-order delta');
|
|
606
|
+
} else {
|
|
607
|
+
this.processDeltaEvent();
|
|
608
|
+
}
|
|
609
|
+
} else if (this.status === 'IDLE') {
|
|
610
|
+
// Update status, ensure we only process one event at a time.
|
|
611
|
+
this.status = 'WORKING';
|
|
612
|
+
|
|
613
|
+
this.processDeltaEvent();
|
|
614
|
+
}
|
|
544
615
|
}
|
|
545
616
|
}
|
|
546
617
|
|
|
@@ -559,11 +630,55 @@ export default class Parser {
|
|
|
559
630
|
* @returns {undefined}
|
|
560
631
|
*/
|
|
561
632
|
pause() {
|
|
562
|
-
|
|
563
|
-
this.status = Parser.status.PAUSED;
|
|
633
|
+
this.status = 'PAUSED';
|
|
564
634
|
LoggerProxy.logger.info('Locus-info:parser#pause --> Locus parser paused.');
|
|
565
635
|
}
|
|
566
636
|
|
|
637
|
+
/**
|
|
638
|
+
* Triggers a sync with Locus
|
|
639
|
+
*
|
|
640
|
+
* @param {string} reason used just for logging
|
|
641
|
+
* @returns {undefined}
|
|
642
|
+
*/
|
|
643
|
+
private triggerSync(reason: string) {
|
|
644
|
+
LoggerProxy.logger.info(`Locus-info:parser#triggerSync --> doing sync, reason: ${reason}`);
|
|
645
|
+
this.stopSyncTimer();
|
|
646
|
+
this.pause();
|
|
647
|
+
this.onDeltaAction(Parser.loci.DESYNC, this.workingCopy);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Starts a timer with a random delay. When that timer expires we will do a sync.
|
|
652
|
+
*
|
|
653
|
+
* The main purpose of this timer is to handle a case when we get some out-of-order deltas,
|
|
654
|
+
* so we start waiting to receive the missing delta. If that delta never arrives, this timer
|
|
655
|
+
* will trigger a sync with Locus.
|
|
656
|
+
*
|
|
657
|
+
* @returns {undefined}
|
|
658
|
+
*/
|
|
659
|
+
private startSyncTimer() {
|
|
660
|
+
if (this.syncTimer === null) {
|
|
661
|
+
const timeout = OOO_DELTA_WAIT_TIME + Math.random() * OOO_DELTA_WAIT_TIME_RANDOM_DELAY;
|
|
662
|
+
|
|
663
|
+
this.syncTimer = setTimeout(() => {
|
|
664
|
+
this.syncTimer = null;
|
|
665
|
+
this.triggerSync('timer expired, blocked on out-of-order delta');
|
|
666
|
+
}, timeout);
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Stops the timer for triggering a sync
|
|
672
|
+
*
|
|
673
|
+
* @returns {undefined}
|
|
674
|
+
*/
|
|
675
|
+
private stopSyncTimer() {
|
|
676
|
+
if (this.syncTimer !== null) {
|
|
677
|
+
clearTimeout(this.syncTimer);
|
|
678
|
+
this.syncTimer = null;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
567
682
|
/**
|
|
568
683
|
* Processes next locus delta in the queue,
|
|
569
684
|
* continues until the queue is empty
|
|
@@ -571,11 +686,13 @@ export default class Parser {
|
|
|
571
686
|
* @returns {undefined}
|
|
572
687
|
*/
|
|
573
688
|
processDeltaEvent() {
|
|
574
|
-
const {DESYNC, USE_INCOMING} = Parser.loci;
|
|
689
|
+
const {DESYNC, USE_INCOMING, WAIT} = Parser.loci;
|
|
575
690
|
const {extractComparisonState: extract} = Parser;
|
|
576
691
|
const newLoci = this.queue.dequeue();
|
|
577
692
|
|
|
578
693
|
if (!this.isValidLocus(newLoci)) {
|
|
694
|
+
this.nextEvent();
|
|
695
|
+
|
|
579
696
|
return;
|
|
580
697
|
}
|
|
581
698
|
|
|
@@ -586,6 +703,8 @@ export default class Parser {
|
|
|
586
703
|
// for full debugging.
|
|
587
704
|
LoggerProxy.logger.debug(`Locus-info:parser#processDeltaEvent --> Locus Debug: ${result}`);
|
|
588
705
|
|
|
706
|
+
let needToWait = false;
|
|
707
|
+
|
|
589
708
|
if (lociComparison === DESYNC) {
|
|
590
709
|
// wait for desync response
|
|
591
710
|
this.pause();
|
|
@@ -594,15 +713,39 @@ export default class Parser {
|
|
|
594
713
|
// Note: The working copy of parser gets updated in .onFullLocus()
|
|
595
714
|
// and here when USE_INCOMING locus.
|
|
596
715
|
this.workingCopy = newLoci;
|
|
716
|
+
} else if (lociComparison === WAIT) {
|
|
717
|
+
// we've taken newLoci from the front of the queue, so put it back there as we have to wait
|
|
718
|
+
// for the one that should be in front of it, before we can process it
|
|
719
|
+
this.queue.enqueue(newLoci);
|
|
720
|
+
needToWait = true;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (needToWait) {
|
|
724
|
+
this.status = 'BLOCKED';
|
|
725
|
+
this.startSyncTimer();
|
|
726
|
+
} else {
|
|
727
|
+
this.stopSyncTimer();
|
|
728
|
+
|
|
729
|
+
if (this.status === 'BLOCKED') {
|
|
730
|
+
// we are not blocked anymore
|
|
731
|
+
this.status = 'WORKING';
|
|
732
|
+
|
|
733
|
+
LoggerProxy.logger.info(
|
|
734
|
+
`Locus-info:parser#processDeltaEvent --> received delta that we were waiting for ${Parser.locus2string(
|
|
735
|
+
newLoci
|
|
736
|
+
)}, not blocked anymore`
|
|
737
|
+
);
|
|
738
|
+
}
|
|
597
739
|
}
|
|
598
740
|
|
|
599
741
|
if (this.onDeltaAction) {
|
|
600
742
|
LoggerProxy.logger.info(
|
|
601
|
-
`Locus-info:parser#processDeltaEvent --> Locus Delta
|
|
743
|
+
`Locus-info:parser#processDeltaEvent --> Locus Delta ${Parser.locus2string(
|
|
744
|
+
newLoci
|
|
745
|
+
)}, Action: ${lociComparison}`
|
|
602
746
|
);
|
|
603
747
|
|
|
604
|
-
|
|
605
|
-
this.onDeltaAction.call(this, lociComparison, newLoci);
|
|
748
|
+
this.onDeltaAction(lociComparison, newLoci);
|
|
606
749
|
}
|
|
607
750
|
|
|
608
751
|
this.nextEvent();
|
|
@@ -614,8 +757,7 @@ export default class Parser {
|
|
|
614
757
|
*/
|
|
615
758
|
resume() {
|
|
616
759
|
LoggerProxy.logger.info('Locus-info:parser#resume --> Locus parser resumed.');
|
|
617
|
-
|
|
618
|
-
this.status = Parser.status.WORKING;
|
|
760
|
+
this.status = 'WORKING';
|
|
619
761
|
this.nextEvent();
|
|
620
762
|
}
|
|
621
763
|
|
package/src/meeting/muteState.ts
CHANGED
|
@@ -278,7 +278,7 @@ export class MuteState {
|
|
|
278
278
|
this.state.server.localMute = this.type === AUDIO ? audioMuted : videoMuted;
|
|
279
279
|
|
|
280
280
|
if (locus) {
|
|
281
|
-
meeting.locusInfo.
|
|
281
|
+
meeting.locusInfo.handleLocusDelta(locus, meeting);
|
|
282
282
|
}
|
|
283
283
|
|
|
284
284
|
return locus;
|
package/src/meeting/request.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
HTTP_VERBS,
|
|
19
19
|
LEAVE,
|
|
20
20
|
LOCI,
|
|
21
|
-
LOCUS,
|
|
22
21
|
PARTICIPANT,
|
|
23
22
|
PROVISIONAL_TYPE_DIAL_IN,
|
|
24
23
|
PROVISIONAL_TYPE_DIAL_OUT,
|
|
@@ -383,62 +382,22 @@ export default class MeetingRequest extends StatelessWebexPlugin {
|
|
|
383
382
|
}
|
|
384
383
|
|
|
385
384
|
/**
|
|
386
|
-
*
|
|
385
|
+
* Sends a requests to get the latest locus DTO, it might be a full Locus or a delta, depending on the url provided
|
|
387
386
|
* @param {Object} options
|
|
388
|
-
* @param {boolean} options.desync flag to get partial or whole locus object
|
|
389
|
-
* @param {String} options.syncUrl sync url to get ht elatest locus delta
|
|
390
|
-
* @returns {Promise}
|
|
391
|
-
*/
|
|
392
|
-
syncMeeting(options: {desync: boolean; syncUrl: string}) {
|
|
393
|
-
/* eslint-disable no-else-return */
|
|
394
|
-
const {desync} = options;
|
|
395
|
-
let {syncUrl} = options;
|
|
396
|
-
|
|
397
|
-
/* istanbul ignore else */
|
|
398
|
-
if (desync) {
|
|
399
|
-
// check for existing URL parameters
|
|
400
|
-
syncUrl = syncUrl
|
|
401
|
-
.concat(syncUrl.split('?')[1] ? '&' : '?')
|
|
402
|
-
.concat(`${LOCUS.SYNCDEBUG}=${desync}`);
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// @ts-ignore
|
|
406
|
-
return this.request({
|
|
407
|
-
method: HTTP_VERBS.GET,
|
|
408
|
-
uri: syncUrl,
|
|
409
|
-
}) // TODO: Handle if delta sync failed . Get the full locus object
|
|
410
|
-
.catch((err) => {
|
|
411
|
-
LoggerProxy.logger.error(
|
|
412
|
-
`Meeting:request#syncMeeting --> Error syncing meeting, error ${err}`
|
|
413
|
-
);
|
|
414
|
-
|
|
415
|
-
return err;
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Request to get the complete locus object
|
|
421
|
-
* @param {Object} options
|
|
422
|
-
* @param {boolean} options.desync flag to get partial or whole locus object
|
|
423
387
|
* @param {String} options.locusUrl sync url to get ht elatest locus delta
|
|
424
388
|
* @returns {Promise}
|
|
425
389
|
*/
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
const {desync} = options;
|
|
429
|
-
|
|
430
|
-
if (locusUrl) {
|
|
431
|
-
if (desync) {
|
|
432
|
-
locusUrl += `?${LOCUS.SYNCDEBUG}=${desync}`;
|
|
433
|
-
}
|
|
390
|
+
getLocusDTO(options: {url: string}) {
|
|
391
|
+
const {url} = options;
|
|
434
392
|
|
|
393
|
+
if (url) {
|
|
435
394
|
// @ts-ignore
|
|
436
395
|
return this.request({
|
|
437
396
|
method: HTTP_VERBS.GET,
|
|
438
|
-
uri:
|
|
397
|
+
uri: url,
|
|
439
398
|
}).catch((err) => {
|
|
440
399
|
LoggerProxy.logger.error(
|
|
441
|
-
`Meeting:request#
|
|
400
|
+
`Meeting:request#getLocusDTO --> Error getting latest locus, error ${err}`
|
|
442
401
|
);
|
|
443
402
|
|
|
444
403
|
return err;
|
package/src/meeting/util.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {assert} from '@webex/test-helper-chai';
|
|
2
|
-
import
|
|
2
|
+
import SortedQueue from '@webex/plugin-meetings/src/common/queue';
|
|
3
3
|
|
|
4
4
|
describe('common/queue', () => {
|
|
5
5
|
let fifo = null;
|
|
@@ -11,7 +11,15 @@ describe('common/queue', () => {
|
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
beforeEach(() => {
|
|
14
|
-
fifo = new
|
|
14
|
+
fifo = new SortedQueue((left, right) => {
|
|
15
|
+
if (left.text > right.text) {
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
if (left.text < right.text) {
|
|
19
|
+
return -1;
|
|
20
|
+
}
|
|
21
|
+
return 0;
|
|
22
|
+
});
|
|
15
23
|
});
|
|
16
24
|
|
|
17
25
|
afterEach(() => {
|
|
@@ -66,4 +74,25 @@ describe('common/queue', () => {
|
|
|
66
74
|
it('Returns null if the queue is empty.', () => {
|
|
67
75
|
assert.equal(fifo.dequeue(), null);
|
|
68
76
|
});
|
|
77
|
+
|
|
78
|
+
it('Implement lifo', () => {
|
|
79
|
+
const lifo = new SortedQueue((left, right) => {
|
|
80
|
+
if (left.text < right.text) {
|
|
81
|
+
return 1;
|
|
82
|
+
}
|
|
83
|
+
if (left.text > right.text) {
|
|
84
|
+
return -1;
|
|
85
|
+
}
|
|
86
|
+
return 0;
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const item1 = {text: 'fake item1'};
|
|
90
|
+
const item2 = {text: 'fake item2'};
|
|
91
|
+
|
|
92
|
+
lifo.enqueue(item1);
|
|
93
|
+
lifo.enqueue(item2);
|
|
94
|
+
|
|
95
|
+
assert.equal(lifo.dequeue(), item2);
|
|
96
|
+
assert.equal(lifo.dequeue(), item1);
|
|
97
|
+
});
|
|
69
98
|
});
|