@webex/internal-plugin-mercury 3.8.1-web-workers-keepalive.1 → 3.9.0-multiple-llm.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/dist/mercury.js +321 -132
- package/dist/mercury.js.map +1 -1
- package/dist/socket/socket-base.js +15 -0
- package/dist/socket/socket-base.js.map +1 -1
- package/package.json +18 -18
- package/src/mercury.js +279 -106
- package/src/socket/socket-base.js +13 -0
- package/test/unit/spec/mercury-events.js +20 -2
- package/test/unit/spec/mercury.js +53 -22
|
@@ -33,6 +33,8 @@ export default class Socket extends EventEmitter {
|
|
|
33
33
|
this._domain = 'unknown-domain';
|
|
34
34
|
this.onmessage = this.onmessage.bind(this);
|
|
35
35
|
this.onclose = this.onclose.bind(this);
|
|
36
|
+
// Increase max listeners to avoid memory leak warning in tests
|
|
37
|
+
this.setMaxListeners(5);
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/**
|
|
@@ -358,9 +360,20 @@ export default class Socket extends EventEmitter {
|
|
|
358
360
|
return Promise.reject(new Error('`event.data.id` is required'));
|
|
359
361
|
}
|
|
360
362
|
|
|
363
|
+
// Don't try to acknowledge if socket is not in open state
|
|
364
|
+
if (this.readyState !== 1) {
|
|
365
|
+
return Promise.resolve(); // Silently ignore acknowledgment for closed sockets
|
|
366
|
+
}
|
|
367
|
+
|
|
361
368
|
return this.send({
|
|
362
369
|
messageId: event.data.id,
|
|
363
370
|
type: 'ack',
|
|
371
|
+
}).catch((error) => {
|
|
372
|
+
// Gracefully handle send errors (like INVALID_STATE_ERROR) to prevent test issues
|
|
373
|
+
if (error.message === 'INVALID_STATE_ERROR') {
|
|
374
|
+
return Promise.resolve(); // Socket was closed, ignore the acknowledgment
|
|
375
|
+
}
|
|
376
|
+
throw error; // Re-throw other errors
|
|
364
377
|
});
|
|
365
378
|
}
|
|
366
379
|
|
|
@@ -38,14 +38,31 @@ describe('plugin-mercury', () => {
|
|
|
38
38
|
},
|
|
39
39
|
timestamp: Date.now(),
|
|
40
40
|
trackingId: `suffix_${uuid.v4()}_${Date.now()}`,
|
|
41
|
+
sessionId: 'mercury-default-session',
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
beforeEach(() => {
|
|
44
45
|
clock = FakeTimers.install({now: Date.now()});
|
|
45
46
|
});
|
|
46
47
|
|
|
47
|
-
afterEach(() => {
|
|
48
|
+
afterEach(async () => {
|
|
48
49
|
clock.uninstall();
|
|
50
|
+
// Clean up mercury socket and mockWebSocket
|
|
51
|
+
if (mercury && mercury.socket) {
|
|
52
|
+
try {
|
|
53
|
+
await mercury.socket.close();
|
|
54
|
+
} catch (e) {}
|
|
55
|
+
}
|
|
56
|
+
if (mockWebSocket && typeof mockWebSocket.close === 'function') {
|
|
57
|
+
mockWebSocket.close();
|
|
58
|
+
}
|
|
59
|
+
// Restore stubs
|
|
60
|
+
if (Socket.getWebSocketConstructor.restore) {
|
|
61
|
+
Socket.getWebSocketConstructor.restore();
|
|
62
|
+
}
|
|
63
|
+
if (socketOpenStub && socketOpenStub.restore) {
|
|
64
|
+
socketOpenStub.restore();
|
|
65
|
+
}
|
|
49
66
|
});
|
|
50
67
|
|
|
51
68
|
beforeEach(() => {
|
|
@@ -76,6 +93,7 @@ describe('plugin-mercury', () => {
|
|
|
76
93
|
});
|
|
77
94
|
|
|
78
95
|
mercury = webex.internal.mercury;
|
|
96
|
+
mercury.defaultSessionId = 'mercury-default-session';
|
|
79
97
|
});
|
|
80
98
|
|
|
81
99
|
afterEach(() => {
|
|
@@ -301,7 +319,7 @@ describe('plugin-mercury', () => {
|
|
|
301
319
|
})
|
|
302
320
|
.then(() => {
|
|
303
321
|
assert.called(offlineSpy);
|
|
304
|
-
assert.calledWith(offlineSpy, {code, reason});
|
|
322
|
+
assert.calledWith(offlineSpy, {code, reason, sessionId: 'mercury-default-session'});
|
|
305
323
|
switch (action) {
|
|
306
324
|
case 'close':
|
|
307
325
|
assert.called(permanentSpy);
|
|
@@ -97,9 +97,32 @@ describe('plugin-mercury', () => {
|
|
|
97
97
|
});
|
|
98
98
|
|
|
99
99
|
mercury = webex.internal.mercury;
|
|
100
|
+
mercury.defaultSessionId = 'mercury-default-session';
|
|
100
101
|
});
|
|
101
102
|
|
|
102
|
-
afterEach(() => {
|
|
103
|
+
afterEach(async () => {
|
|
104
|
+
// Clean up Mercury connections and internal state
|
|
105
|
+
if (mercury) {
|
|
106
|
+
try {
|
|
107
|
+
await mercury.disconnectAll();
|
|
108
|
+
} catch (e) {
|
|
109
|
+
// Ignore cleanup errors
|
|
110
|
+
}
|
|
111
|
+
// Clear any remaining connection promises
|
|
112
|
+
if (mercury._connectPromises) {
|
|
113
|
+
mercury._connectPromises.clear();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Ensure mock socket is properly closed
|
|
118
|
+
if (mockWebSocket && typeof mockWebSocket.close === 'function') {
|
|
119
|
+
try {
|
|
120
|
+
mockWebSocket.close();
|
|
121
|
+
} catch (e) {
|
|
122
|
+
// Ignore cleanup errors
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
103
126
|
if (socketOpenStub) {
|
|
104
127
|
socketOpenStub.restore();
|
|
105
128
|
}
|
|
@@ -107,6 +130,9 @@ describe('plugin-mercury', () => {
|
|
|
107
130
|
if (Socket.getWebSocketConstructor.restore) {
|
|
108
131
|
Socket.getWebSocketConstructor.restore();
|
|
109
132
|
}
|
|
133
|
+
|
|
134
|
+
// Small delay to ensure all async operations complete
|
|
135
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
110
136
|
});
|
|
111
137
|
|
|
112
138
|
describe('#listen()', () => {
|
|
@@ -436,9 +462,13 @@ describe('plugin-mercury', () => {
|
|
|
436
462
|
|
|
437
463
|
// skipping due to apparent bug with lolex in all browsers but Chrome.
|
|
438
464
|
skipInBrowser(it)('does not continue attempting to connect', () => {
|
|
439
|
-
mercury.connect();
|
|
465
|
+
const promise = mercury.connect();
|
|
466
|
+
|
|
467
|
+
// Wait for the connection to be established before proceeding
|
|
468
|
+
mockWebSocket.open();
|
|
440
469
|
|
|
441
|
-
return
|
|
470
|
+
return promise.then(() =>
|
|
471
|
+
promiseTick(2)
|
|
442
472
|
.then(() => {
|
|
443
473
|
clock.tick(6 * webex.internal.mercury.config.backoffTimeReset);
|
|
444
474
|
|
|
@@ -446,7 +476,8 @@ describe('plugin-mercury', () => {
|
|
|
446
476
|
})
|
|
447
477
|
.then(() => {
|
|
448
478
|
assert.calledOnce(Socket.prototype.open);
|
|
449
|
-
|
|
479
|
+
})
|
|
480
|
+
);
|
|
450
481
|
});
|
|
451
482
|
});
|
|
452
483
|
|
|
@@ -521,11 +552,11 @@ describe('plugin-mercury', () => {
|
|
|
521
552
|
});
|
|
522
553
|
|
|
523
554
|
describe('#logout()', () => {
|
|
524
|
-
it('calls
|
|
555
|
+
it('calls disconnectAll and logs', () => {
|
|
525
556
|
sinon.stub(mercury.logger, 'info');
|
|
526
|
-
sinon.stub(mercury, '
|
|
557
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
527
558
|
mercury.logout();
|
|
528
|
-
assert.called(mercury.
|
|
559
|
+
assert.called(mercury.disconnectAll);
|
|
529
560
|
assert.calledTwice(mercury.logger.info);
|
|
530
561
|
|
|
531
562
|
assert.calledWith(mercury.logger.info.getCall(0), 'Mercury: logout() called');
|
|
@@ -537,24 +568,24 @@ describe('plugin-mercury', () => {
|
|
|
537
568
|
});
|
|
538
569
|
|
|
539
570
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code 3050 for logout', () => {
|
|
540
|
-
sinon.stub(mercury, '
|
|
571
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
541
572
|
mercury.config.beforeLogoutOptionsCloseReason = 'done (permanent)';
|
|
542
573
|
mercury.logout();
|
|
543
|
-
assert.calledWith(mercury.
|
|
574
|
+
assert.calledWith(mercury.disconnectAll, {code: 3050, reason: 'done (permanent)'});
|
|
544
575
|
});
|
|
545
576
|
|
|
546
577
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send code 3050 for logout if the reason is different than standard', () => {
|
|
547
|
-
sinon.stub(mercury, '
|
|
578
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
548
579
|
mercury.config.beforeLogoutOptionsCloseReason = 'test';
|
|
549
580
|
mercury.logout();
|
|
550
|
-
assert.calledWith(mercury.
|
|
581
|
+
assert.calledWith(mercury.disconnectAll, {code: 3050, reason: 'test'});
|
|
551
582
|
});
|
|
552
583
|
|
|
553
584
|
it('uses the config.beforeLogoutOptionsCloseReason to disconnect and will send undefined for logout if the reason is same as standard', () => {
|
|
554
|
-
sinon.stub(mercury, '
|
|
585
|
+
sinon.stub(mercury, 'disconnectAll');
|
|
555
586
|
mercury.config.beforeLogoutOptionsCloseReason = 'done (forced)';
|
|
556
587
|
mercury.logout();
|
|
557
|
-
assert.calledWith(mercury.
|
|
588
|
+
assert.calledWith(mercury.disconnectAll, undefined);
|
|
558
589
|
});
|
|
559
590
|
});
|
|
560
591
|
|
|
@@ -660,12 +691,12 @@ describe('plugin-mercury', () => {
|
|
|
660
691
|
return promiseTick(webex.internal.mercury.config.backoffTimeReset).then(() => {
|
|
661
692
|
// By this time backoffCall and mercury socket should be defined by the
|
|
662
693
|
// 'connect' call
|
|
663
|
-
assert.isDefined(mercury.
|
|
694
|
+
assert.isDefined(mercury.backoffCalls.get('mercury-default-session'), 'Mercury backoffCall is not defined');
|
|
664
695
|
assert.isDefined(mercury.socket, 'Mercury socket is not defined');
|
|
665
696
|
// Calling disconnect will abort the backoffCall, close the socket, and
|
|
666
697
|
// reject the connect
|
|
667
698
|
mercury.disconnect();
|
|
668
|
-
assert.isUndefined(mercury.
|
|
699
|
+
assert.isUndefined(mercury.backoffCalls.get('mercury-default-session'), 'Mercury backoffCall is still defined');
|
|
669
700
|
// The socket will never be unset (which seems bad)
|
|
670
701
|
assert.isDefined(mercury.socket, 'Mercury socket is not defined');
|
|
671
702
|
|
|
@@ -683,15 +714,15 @@ describe('plugin-mercury', () => {
|
|
|
683
714
|
|
|
684
715
|
let reason;
|
|
685
716
|
|
|
686
|
-
mercury.
|
|
687
|
-
mercury._attemptConnection('ws://example.com', (_reason) => {
|
|
717
|
+
mercury.backoffCalls.clear();
|
|
718
|
+
mercury._attemptConnection('ws://example.com', 'mercury-default-session',(_reason) => {
|
|
688
719
|
reason = _reason;
|
|
689
720
|
});
|
|
690
721
|
|
|
691
722
|
return promiseTick(webex.internal.mercury.config.backoffTimeReset).then(() => {
|
|
692
723
|
assert.equal(
|
|
693
724
|
reason.message,
|
|
694
|
-
|
|
725
|
+
`Mercury: prevent socket open when backoffCall no longer defined for ${mercury.defaultSessionId}`
|
|
695
726
|
);
|
|
696
727
|
});
|
|
697
728
|
});
|
|
@@ -713,7 +744,7 @@ describe('plugin-mercury', () => {
|
|
|
713
744
|
return assert.isRejected(promise).then((error) => {
|
|
714
745
|
const lastError = mercury.getLastError();
|
|
715
746
|
|
|
716
|
-
assert.equal(error.message,
|
|
747
|
+
assert.equal(error.message, `Mercury Connection Aborted for ${mercury.defaultSessionId}`);
|
|
717
748
|
assert.isDefined(lastError);
|
|
718
749
|
assert.equal(lastError, realError);
|
|
719
750
|
});
|
|
@@ -807,7 +838,7 @@ describe('plugin-mercury', () => {
|
|
|
807
838
|
},
|
|
808
839
|
};
|
|
809
840
|
assert.isUndefined(mercury.mercuryTimeOffset);
|
|
810
|
-
mercury._setTimeOffset(event);
|
|
841
|
+
mercury._setTimeOffset('mercury-default-session', event);
|
|
811
842
|
assert.isDefined(mercury.mercuryTimeOffset);
|
|
812
843
|
assert.isTrue(mercury.mercuryTimeOffset > 0);
|
|
813
844
|
});
|
|
@@ -817,7 +848,7 @@ describe('plugin-mercury', () => {
|
|
|
817
848
|
wsWriteTimestamp: Date.now() + 60000,
|
|
818
849
|
},
|
|
819
850
|
};
|
|
820
|
-
mercury._setTimeOffset(event);
|
|
851
|
+
mercury._setTimeOffset('mercury-default-session', event);
|
|
821
852
|
assert.isTrue(mercury.mercuryTimeOffset < 0);
|
|
822
853
|
});
|
|
823
854
|
it('handles invalid wsWriteTimestamp', () => {
|
|
@@ -828,7 +859,7 @@ describe('plugin-mercury', () => {
|
|
|
828
859
|
wsWriteTimestamp: invalidTimestamp,
|
|
829
860
|
},
|
|
830
861
|
};
|
|
831
|
-
mercury._setTimeOffset(event);
|
|
862
|
+
mercury._setTimeOffset('mercury-default-session', event);
|
|
832
863
|
assert.isUndefined(mercury.mercuryTimeOffset);
|
|
833
864
|
});
|
|
834
865
|
});
|