import {Instantiable, Singleton, StaticClass} from '../di' import {Bus, Dispatchable, EventSubscriber, EventSubscriberEntry, EventSubscription} from './types' import {Awaitable, Collection, uuid4} from '../util' /** * A non-queued bus implementation that executes subscribers immediately in the main thread. */ @Singleton() export class EventBus implements Bus { /** * Collection of subscribers, by their events. * @protected */ protected subscribers: Collection> = new Collection>() subscribe(event: StaticClass>, subscriber: EventSubscriber): Awaitable { const entry: EventSubscriberEntry = { id: uuid4(), event, subscriber, } this.subscribers.push(entry) return this.buildSubscription(entry.id) } unsubscribe(subscriber: EventSubscriber): Awaitable { this.subscribers = this.subscribers.where('subscriber', '!=', subscriber) } async dispatch(event: Dispatchable): Promise { const eventClass: StaticClass = event.constructor as StaticClass await this.subscribers.where('event', '=', eventClass) .promiseMap(entry => entry.subscriber(event)) } /** * Build an EventSubscription object for the subscriber of the given ID. * @param id * @protected */ protected buildSubscription(id: string): EventSubscription { let subscribed = true return { unsubscribe: (): Awaitable => { if ( subscribed ) { this.subscribers = this.subscribers.where('id', '!=', id) subscribed = false } }, } } }