You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
54 lines
1.9 KiB
54 lines
1.9 KiB
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<EventSubscriberEntry<any>> = new Collection<EventSubscriberEntry<any>>()
|
|
|
|
subscribe<T extends Dispatchable>(event: StaticClass<T, Instantiable<T>>, subscriber: EventSubscriber<T>): Awaitable<EventSubscription> {
|
|
const entry: EventSubscriberEntry<T> = {
|
|
id: uuid4(),
|
|
event,
|
|
subscriber,
|
|
}
|
|
|
|
this.subscribers.push(entry)
|
|
return this.buildSubscription(entry.id)
|
|
}
|
|
|
|
unsubscribe<T extends Dispatchable>(subscriber: EventSubscriber<T>): Awaitable<void> {
|
|
this.subscribers = this.subscribers.where('subscriber', '!=', subscriber)
|
|
}
|
|
|
|
async dispatch(event: Dispatchable): Promise<void> {
|
|
const eventClass: StaticClass<typeof event, typeof event> = event.constructor as StaticClass<Dispatchable, Dispatchable>
|
|
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<void> => {
|
|
if ( subscribed ) {
|
|
this.subscribers = this.subscribers.where('id', '!=', id)
|
|
subscribed = false
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|