diff --git a/src/portal/src/app/services/event-service/event.service.spec.ts b/src/portal/src/app/services/event-service/event.service.spec.ts index 89fdf400e..3bc7aa209 100644 --- a/src/portal/src/app/services/event-service/event.service.spec.ts +++ b/src/portal/src/app/services/event-service/event.service.spec.ts @@ -1,5 +1,6 @@ import { TestBed } from '@angular/core/testing'; import { EventService } from "./event.service"; +import { Subscription } from "rxjs"; describe('EventServiceService', () => { @@ -13,4 +14,18 @@ describe('EventServiceService', () => { it('should be created', () => { expect(service).toBeTruthy(); }); + + + it('able to subscribe', () => { + let result: string; + const sub1 = service.subscribe('testEvent', data => { + result = data; + }); + expect(sub1 ).toBeTruthy(); + expect((sub1 instanceof Subscription)).toEqual(true); + service.publish('testEvent', 'resultString'); + sub1.unsubscribe(); + expect(result).toEqual('resultString'); + + }); }); diff --git a/src/portal/src/app/services/event-service/event.service.ts b/src/portal/src/app/services/event-service/event.service.ts index 7af39e6d1..9063a1451 100644 --- a/src/portal/src/app/services/event-service/event.service.ts +++ b/src/portal/src/app/services/event-service/event.service.ts @@ -1,54 +1,73 @@ import { Injectable } from '@angular/core'; -import { from, Subject } from "rxjs"; +import { Subscription } from "rxjs"; @Injectable({ providedIn: "root" }) export class EventService { - private listeners = {}; - private eventsSubject = new Subject(); - private events = from(this.eventsSubject); - - constructor() { - this.events.subscribe( - ({name, args}) => { - if (this.listeners[name]) { - for (let listener of this.listeners[name]) { - listener(...args); - } - } - }); - } - subscribe(name: string, listener): any { - if (!this.listeners[name]) { - this.listeners[name] = []; + private _channels: any = []; + /** + * Subscribe to an event topic. Events that get posted to that topic will trigger the provided handler. + * + * @param {string} topic the topic to subscribe to + * @param {function} handler the event handler + * @return A Subscription to unsubscribe + */ + subscribe(topic: string, handler: Function): Subscription { + if (!this._channels[topic]) { + this._channels[topic] = []; } - this.listeners[name].push(listener); - return { - unsubscribe: () => { - this.doUnsubscribe(name, listener); - } - }; - } - doUnsubscribe(name, listener) { - this.listeners[name] = this.listeners[name].filter((v) => { - return v !== listener; + this._channels[topic].push(handler); + return new Subscription(() => { + this.unsubscribe(topic, handler); }); } - unsubscribe(name, listener?) { - if (this.listeners[name]) { - if (!listener) { - this.listeners[name] = []; - } else { - this.doUnsubscribe(name, listener); - } + + /** + * Unsubscribe from the given topic. Your handler will no longer receive events published to this topic. + * + * @param {string} topic the topic to unsubscribe from + * @param {function} handler the event handler + * + */ + private unsubscribe(topic: string, handler: Function = null) { + let t = this._channels[topic]; + if (!t) { + // Wasn't found, wasn't removed + return; } + if (!handler) { + // Remove all handlers for this topic + delete this._channels[topic]; + return; + } + // We need to find and remove a specific handler + let i = t.indexOf(handler); + if (i < 0) { + // Wasn't found, wasn't removed + return; + } + t.splice(i, 1); + // If the channel is empty now, remove it from the channel map + if (!t.length) { + delete this._channels[topic]; + } + return; } - publish(name, ...args) { - this.eventsSubject.next({ - name, - args + + /** + * Publish an event to the given topic. + * @param topic + * @param data + */ + publish(topic: string, data?: any) { + const t = this._channels[topic]; + if (!t) { + return; + } + t.forEach((handler: any) => { + handler(data); }); } }