diff --git a/packages/@webex/internal-plugin-mercury/src/mercury.js b/packages/@webex/internal-plugin-mercury/src/mercury.js index 5c94ebc4265..c1180931287 100644 --- a/packages/@webex/internal-plugin-mercury/src/mercury.js +++ b/packages/@webex/internal-plugin-mercury/src/mercury.js @@ -41,6 +41,10 @@ const Mercury = WebexPlugin.extend({ }, socket: 'object', localClusterServiceUrls: 'object', + mercuryTimeOffset: { + default: undefined, + type: 'number', + }, }, derived: { @@ -197,6 +201,7 @@ const Mercury = WebexPlugin.extend({ socket.on('close', (...args) => this._onclose(...args)); socket.on('message', (...args) => this._onmessage(...args)); + socket.on('pong', (...args) => this._setTimeOffset(...args)); socket.on('sequence-mismatch', (...args) => this._emit('sequence-mismatch', ...args)); socket.on('ping-pong-latency', (...args) => this._emit('ping-pong-latency', ...args)); @@ -486,6 +491,7 @@ const Mercury = WebexPlugin.extend({ }, _onmessage(event) { + this._setTimeOffset(event); const envelope = event.data; if (process.env.ENABLE_MERCURY_LOGGING) { @@ -529,6 +535,13 @@ const Mercury = WebexPlugin.extend({ }); }, + _setTimeOffset(event) { + const {wsWriteTimestamp} = event; + if (typeof wsWriteTimestamp === 'number' && wsWriteTimestamp > 0) { + this.mercuryTimeOffset = Date.now() - wsWriteTimestamp; + } + }, + _reconnect(webSocketUrl) { this.logger.info(`${this.namespace}: reconnecting`); diff --git a/packages/@webex/internal-plugin-mercury/src/socket/socket-base.js b/packages/@webex/internal-plugin-mercury/src/socket/socket-base.js index 02bbe25d5a1..e4129c1cce3 100644 --- a/packages/@webex/internal-plugin-mercury/src/socket/socket-base.js +++ b/packages/@webex/internal-plugin-mercury/src/socket/socket-base.js @@ -295,6 +295,7 @@ export default class Socket extends EventEmitter { try { const data = JSON.parse(event.data); const sequenceNumber = parseInt(data.sequenceNumber, 10); + const wsWriteTimestamp = parseInt(data.wsWriteTimestamp, 10); this.logger.debug(`socket,${this._domain}: sequence number: `, sequenceNumber); if (this.expectedSequenceNumber && sequenceNumber !== this.expectedSequenceNumber) { @@ -308,7 +309,7 @@ export default class Socket extends EventEmitter { // Yes, it's a little weird looking; we want to emit message events that // look like normal socket message events, but event.data cannot be // modified and we don't actually care about anything but the data property - const processedEvent = {data}; + const processedEvent = {data, wsWriteTimestamp}; this._acknowledge(processedEvent); if (data.type === 'pong') { diff --git a/packages/@webex/internal-plugin-mercury/test/unit/spec/mercury.js b/packages/@webex/internal-plugin-mercury/test/unit/spec/mercury.js index cd65a870e0c..9aca9da7ad3 100644 --- a/packages/@webex/internal-plugin-mercury/test/unit/spec/mercury.js +++ b/packages/@webex/internal-plugin-mercury/test/unit/spec/mercury.js @@ -773,6 +773,41 @@ describe('plugin-mercury', () => { }); }); + describe('#_setTimeOffset', () => { + it('sets mercuryTimeOffset based on the difference between wsWriteTimestamp and now', () => { + const event = { + data: { + wsWriteTimestamp: Date.now() - 60000, + } + }; + assert.isUndefined(mercury.mercuryTimeOffset); + mercury._setTimeOffset(event); + assert.isDefined(mercury.mercuryTimeOffset); + assert.isTrue(mercury.mercuryTimeOffset > 0); + }); + it('handles negative offsets', () => { + const event = { + data: { + wsWriteTimestamp: Date.now() + 60000, + } + }; + mercury._setTimeOffset(event); + assert.isTrue(mercury.mercuryTimeOffset < 0); + }); + it('handles invalid wsWriteTimestamp', () => { + const invalidTimestamps = [null, -1, 'invalid', undefined]; + invalidTimestamps.forEach(invalidTimestamp => { + const event = { + data: { + wsWriteTimestamp: invalidTimestamp, + } + }; + mercury._setTimeOffset(event); + assert.isUndefined(mercury.mercuryTimeOffset); + }); + }); + }); + describe('#_prepareUrl()', () => { beforeEach(() => { webex.internal.device.webSocketUrl = 'ws://example.com'; diff --git a/packages/@webex/internal-plugin-mercury/test/unit/spec/socket.js b/packages/@webex/internal-plugin-mercury/test/unit/spec/socket.js index 39b4f9f3da1..5c26384aa94 100644 --- a/packages/@webex/internal-plugin-mercury/test/unit/spec/socket.js +++ b/packages/@webex/internal-plugin-mercury/test/unit/spec/socket.js @@ -750,6 +750,7 @@ describe('plugin-mercury', () => { data: JSON.stringify({ sequenceNumber: 3, id: 'mockid', + wsWriteTimestamp: 1735689600000, }), }); @@ -757,6 +758,7 @@ describe('plugin-mercury', () => { data: { sequenceNumber: 3, id: 'mockid', + wsWriteTimestamp: 1735689600000, }, }); }); @@ -790,6 +792,7 @@ describe('plugin-mercury', () => { data: JSON.stringify({ sequenceNumber: 5, id: 'mockid', + wsWriteTimestamp: 1735689600000, }), }); assert.called(socket._acknowledge); @@ -797,6 +800,7 @@ describe('plugin-mercury', () => { data: { sequenceNumber: 5, id: 'mockid', + wsWriteTimestamp: 1735689600000, }, }); });