Skip to content

Instantly share code, notes, and snippets.

@ktsn
Last active March 2, 2018 15:48
Show Gist options
  • Save ktsn/ea666a34a330c03cbd10b4b2787b851c to your computer and use it in GitHub Desktop.
Save ktsn/ea666a34a330c03cbd10b4b2787b851c to your computer and use it in GitHub Desktop.
interface Emit<Payloads> {
<Name extends keyof Payloads>(name: Name, payload: Payloads[Name]): void
}
interface Observe<Payloads> {
<Name extends keyof Payloads>(
name: Name,
cb: (payload: Payloads[Name]) => void
): void
}
type Fn1 = (value: any) => void
function emit(listeners: Map<string, Fn1[]>, name: string, payload: any): void {
const list = listeners.get(name)
if (list) {
list.forEach(listener => listener(payload))
}
}
function observe(
listeners: Map<string, Fn1[]>,
name: string,
cb: (payload: any) => void
): void {
const list = listeners.get(name) || []
list.push(cb)
listeners.set(name, list)
}
export class EventObserver<Events> {
listeners: Map<string, Fn1[]> | undefined = new Map()
constructor(fn: (dispatch: Emit<Events>) => void) {
fn((name, payload) => {
if (this.listeners) {
emit(this.listeners, name, payload)
}
})
}
on<Name extends keyof Events>(
name: Name,
cb: (payload: Events[Name]) => void
): void {
if (this.listeners) {
observe(this.listeners, name, cb)
}
}
dispose(): void {
if (this.listeners) {
this.listeners.clear()
this.listeners = undefined
}
}
}
export class CommandEmitter<Commands> {
listeners: Map<string, Fn1[]> | undefined = new Map()
constructor(fn: (observe: Observe<Commands>) => void) {
fn((name, cb) => {
if (this.listeners) {
observe(this.listeners, name, cb)
}
})
}
emit<Name extends keyof Commands>(name: Name, payload: Commands[Name]): void {
if (this.listeners) {
emit(this.listeners, name, payload)
}
}
dispose(): void {
if (this.listeners) {
this.listeners.clear()
this.listeners = undefined
}
}
}
export class EventBus<Events, Commands> {
constructor(
private eventObservers: EventObserver<Events>[],
private commandEmitters: CommandEmitter<Commands>[]
) {}
on<Name extends keyof Events>(
name: Name,
cb: (payload: Events[Name]) => void
): void {
this.eventObservers.forEach(e => {
e.on(name, cb)
})
}
emit<Name extends keyof Commands>(name: Name, payload: Commands[Name]): void {
this.commandEmitters.forEach(c => {
c.emit(name, payload)
})
}
dispose(): void {
;(this.eventObservers as { dispose(): void }[])
.concat(this.commandEmitters)
.forEach(x => x.dispose())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment