diff --git a/libs/accelerator/src/lib/topic/topic-message.ts b/libs/accelerator/src/lib/topic/topic-message.ts index 33496277..1cb87734 100644 --- a/libs/accelerator/src/lib/topic/topic-message.ts +++ b/libs/accelerator/src/lib/topic/topic-message.ts @@ -1,12 +1,8 @@ -import { Message } from "./message"; -import { TopicMessageType } from "./topic-message-type"; +import { Message } from './message' +import { TopicMessageType } from './topic-message-type' export class TopicMessage extends Message { - constructor( - type: TopicMessageType, - public name: string, - public version: number - ) { - super(type); - } - } \ No newline at end of file + constructor(type: TopicMessageType, public name: string, public version: number) { + super(type) + } +} diff --git a/libs/accelerator/src/lib/topic/topic.spec.ts b/libs/accelerator/src/lib/topic/topic.spec.ts index 4c89a887..6133a8e3 100644 --- a/libs/accelerator/src/lib/topic/topic.spec.ts +++ b/libs/accelerator/src/lib/topic/topic.spec.ts @@ -8,6 +8,9 @@ import { map } from 'rxjs' import { Topic } from './topic' +import { TopicMessageType } from './topic-message-type' +import { TopicDataMessage } from './topic-data-message' +import { TopicMessage } from './topic-message' describe('Topic', () => { const origAddEventListener = window.addEventListener @@ -155,4 +158,130 @@ describe('Topic', () => { done() }) }) + + describe('on message', () => { + let currentMessage: TopicDataMessage + let incomingMessage: MessageEvent> + + beforeEach(() => { + currentMessage = { + type: TopicMessageType.TopicNext, + name: testTopic1.name, + version: testTopic1.version, + data: '', + timestamp: 0, + id: 0, + } + incomingMessage = { + data: { + type: TopicMessageType.TopicNext, + name: testTopic1.name, + version: testTopic1.version, + data: '', + timestamp: 0, + id: 0, + }, + } as any + + // initialize topic + testTopic1.publish('initMsg') + }) + + it('should have value if incoming id is greater than previous id', () => { + currentMessage.data = 'msg1' + currentMessage.id = 0 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = 1 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg', 'msg2']) + }) + + it('should have value if incoming timestamp is greater than previous timestamp with no ids provided', () => { + currentMessage.data = 'msg1' + currentMessage.id = undefined! + currentMessage.timestamp = 1 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = undefined! + incomingMessage.data.timestamp = 3 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg', 'msg2']) + }) + + it('should have value if incoming timestamp is greater than previous timestamp when current message has id', () => { + currentMessage.data = 'msg1' + currentMessage.id = 1 + currentMessage.timestamp = 1 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = undefined! + incomingMessage.data.timestamp = 3 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg', 'msg2']) + }) + + it('should have value if incoming timestamp is greater than previous timestamp when incoming message has id', () => { + currentMessage.data = 'msg1' + currentMessage.id = undefined! + currentMessage.timestamp = 1 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = 1 + incomingMessage.data.timestamp = 3 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg', 'msg2']) + }) + + it('should have no value if incoming timestamp is equal to the previous timestamp with no ids provided', () => { + currentMessage.data = 'msg1' + currentMessage.id = undefined! + currentMessage.timestamp = 3 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = undefined! + incomingMessage.data.timestamp = 3 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg']) + }) + + it('should have no value if incoming timestamp is equal to the previous timestamp when current message has id', () => { + jest.spyOn(console, 'warn') + currentMessage.data = 'msg1' + currentMessage.id = 1 + currentMessage.timestamp = 3 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = undefined! + incomingMessage.data.timestamp = 3 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg']) + expect(console.warn).toHaveBeenLastCalledWith( + 'Message was swallowed because of equal timestamps. Please upgrate to the latest version to ensure messages are correctly timed' + ) + }) + + it('should have no value if incoming timestamp is equal to previous timestamp when incoming message has id', () => { + jest.spyOn(console, 'warn') + currentMessage.data = 'msg1' + currentMessage.id = undefined! + currentMessage.timestamp = 3 + incomingMessage.data.data = 'msg2' + incomingMessage.data.id = 1 + incomingMessage.data.timestamp = 3 + + testTopic1.onMessage(currentMessage, incomingMessage) + + expect(values1).toEqual(['initMsg']) + expect(console.warn).toHaveBeenLastCalledWith( + 'Message was swallowed because of equal timestamps. Please upgrate to the latest version to ensure messages are correctly timed' + ) + }) + }) }) diff --git a/libs/accelerator/src/lib/topic/topic.ts b/libs/accelerator/src/lib/topic/topic.ts index 375b3d3b..a03c7461 100644 --- a/libs/accelerator/src/lib/topic/topic.ts +++ b/libs/accelerator/src/lib/topic/topic.ts @@ -19,7 +19,7 @@ export class Topic extends TopicPublisher implements Subscribable { protected isInit = false private resolveInitPromise!: (value: void | PromiseLike) => void - private eventListener = (m: MessageEvent) => this.onMessage(m) + private eventListener = (m: MessageEvent) => this.onMessage(this.data.value, m) constructor(name: string, version: number, sendGetMessage = true) { super(name, version) @@ -142,34 +142,34 @@ export class Topic extends TopicPublisher implements Subscribable { window.removeEventListener('message', this.eventListener, true) } - private onMessage(m: MessageEvent): any { - switch (m.data.type) { + public onMessage(currentMessage: TopicDataMessage | undefined, incomingMessage: MessageEvent): any { + switch (incomingMessage.data.type) { case TopicMessageType.TopicNext: - if (m.data.name !== this.name || m.data.version !== this.version) { + if (incomingMessage.data.name !== this.name || incomingMessage.data.version !== this.version) { break } if ( - !this.data.value || + !currentMessage || (this.isInit && - (m.data).id && - this.data.value.id && - (m.data).id > this.data.value.id) || - (this.isInit && (m.data).timestamp > this.data.value.timestamp) + (incomingMessage.data).id !== undefined && + currentMessage.id !== undefined && + (incomingMessage.data).id > currentMessage.id) || + (this.isInit && (incomingMessage.data).timestamp > currentMessage.timestamp) ) { this.isInit = true - this.data.next(>m.data) + this.data.next(>incomingMessage.data) this.resolveInitPromise() - const publishPromiseResolver = this.publishPromiseResolver[m.data.timestamp] + const publishPromiseResolver = this.publishPromiseResolver[incomingMessage.data.timestamp] if (publishPromiseResolver) { publishPromiseResolver() - delete this.publishPromiseResolver[m.data.timestamp] + delete this.publishPromiseResolver[incomingMessage.data.timestamp] } } else if ( - this.data.value && + currentMessage && this.isInit && - (m.data).timestamp === this.data.value.timestamp && - ((m.data).id || this.data.value.id) + (incomingMessage.data).timestamp === currentMessage.timestamp && + ((incomingMessage.data).id || currentMessage.id) ) { console.warn( 'Message was swallowed because of equal timestamps. Please upgrate to the latest version to ensure messages are correctly timed' @@ -177,10 +177,15 @@ export class Topic extends TopicPublisher implements Subscribable { } break case TopicMessageType.TopicGet: - if (m.data.name === this.name && m.data.version === this.version && this.isInit && this.data.value) { - window.postMessage(this.data.value, '*') - m.stopImmediatePropagation() - m.stopPropagation() + if ( + incomingMessage.data.name === this.name && + incomingMessage.data.version === this.version && + this.isInit && + currentMessage + ) { + window.postMessage(currentMessage, '*') + incomingMessage.stopImmediatePropagation() + incomingMessage.stopPropagation() } break }