Skip to content

Commit

Permalink
prototyping
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewazores committed Jun 19, 2018
1 parent 8f49345 commit ac111f1
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/app/app.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import { AboutService } from './shared/about.service';
import { ProviderService } from './shared/account/provider.service';
import { AnalyticService } from './shared/analytics.service';
import { BrandingService } from './shared/branding.service';
import { EventBusRegistry } from './shared/event-bus-registry';
import { LoginService } from './shared/login.service';
import { NotificationsService } from './shared/notifications.service';

Expand Down Expand Up @@ -124,6 +125,9 @@ describe('AppComponent', () => {
return logger;
}
},
{
provide: EventBusRegistry, useValue: null
},
MockContextResolver
],
schemas: [ NO_ERRORS_SCHEMA ]
Expand Down
4 changes: 3 additions & 1 deletion src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { AboutService } from './shared/about.service';
import { ProviderService } from './shared/account/provider.service';
import { AnalyticService } from './shared/analytics.service';
import { BrandingService } from './shared/branding.service';
import { EventBusRegistry } from './shared/event-bus-registry';
import { LoginService } from './shared/login.service';
import { NotificationsService } from './shared/notifications.service';

Expand Down Expand Up @@ -61,7 +62,8 @@ export class AppComponent {
private providerService: ProviderService,
private errorService: ErrorService,
private logger: Logger,
private toggleAckService: FeatureAcknowledgementService
private toggleAckService: FeatureAcknowledgementService,
private eventBusRegistry: EventBusRegistry
) {

}
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ import { FeatureAcknowledgementService } from './feature-flag/service/feature-ac
import { GettingStartedService } from './getting-started/services/getting-started.service';
import { RavenExceptionHandler } from './shared/exception.handler';

import { EventBusModule } from './shared/event-bus.module';

// Application wide providers
const APP_PROVIDERS = [
Expand Down Expand Up @@ -144,6 +145,7 @@ export type StoreType = {
BsDropdownModule.forRoot(),
EffectsModule.forRoot([]),
EmptyStateModule,
EventBusModule,
FeatureFooterModule,
FormsModule,
HttpModule,
Expand Down
44 changes: 44 additions & 0 deletions src/app/shared/event-bus-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
Inject,
Injectable,
InjectionToken
} from '@angular/core';

import {
Observable,
Observer
} from 'rxjs';

import {
Event,
EventBus
} from './event-bus.service';

// EVENTS_LISTENER *must* also be used with "multi" attribute set to true
export const EVENTS_LISTENER: InjectionToken<string> = new InjectionToken<string>('EventsListener');

export abstract class EventsListener<Event> implements Observer<Event> {
eventTypes: string[];
abstract next(event: Event);
error(err: any): void { }
complete(): void { }
}

@Injectable()
export class EventBusRegistry {
constructor(
private readonly eventBus: EventBus,
// Force DI to initialize all listeners in hierarchy
@Inject(EVENTS_LISTENER) private readonly listeners: EventsListener<Event<any>>[]
) {
listeners.forEach((listener: EventsListener<Event<any>>): void => {
let obs: Observable<any>;
if (listener.eventTypes.length > 0) {
obs = eventBus.for(listener.eventTypes[0], ...listener.eventTypes.slice(1));
} else {
obs = eventBus.for(listener.eventTypes[0]);
}
obs.subscribe(listener);
});
}
}
45 changes: 45 additions & 0 deletions src/app/shared/event-bus.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { NgModule } from '@angular/core';

import { Observable } from 'rxjs';

import {
EventBusRegistry,
EVENTS_LISTENER,
EventsListener
} from './event-bus-registry';
import {
Event,
EventBus,
EVENTS_PROVIDER,
EventsProvider,
EventType
} from './event-bus.service';

@NgModule({
imports: [],
providers: [
EventBus,
EventBusRegistry,
// stub default EVENTS_PROVIDER and EVENTS_LISTENER so DI doesn't choke if
// no other modules provide custom providers and listeners
{
provide: EVENTS_PROVIDER,
useValue: ({
eventType: EventType.GENERIC,
events: Observable.never()
} as EventsProvider<void>),
multi: true
},
{
provide: EVENTS_LISTENER,
useValue: ({
eventTypes: [],
next: () => null,
error: () => null,
complete: () => null
} as EventsListener<void>),
multi: true
}
]
})
export class EventBusModule { }
69 changes: 69 additions & 0 deletions src/app/shared/event-bus.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import {
Inject,
Injectable,
InjectionToken
} from '@angular/core';

import {
Observable,
Subject
} from 'rxjs';

import { includes } from 'lodash';

// Per-module EventsProvider implementations *MUST* set the "multi" attribute to true
export const EVENTS_PROVIDER: InjectionToken<string> = new InjectionToken<string>('EventsProvider');

export interface EventsProvider<T> {
eventType: string;
events: Observable<T>;
}

// Common event types for all publishers and subscribers.
// Publishers and subscribers are also free to use plain strings
// as event types to tag their own events so that this enum does
// not need to be updated to reflect every single use case.
export enum EventType {
GENERIC = 'Generic'
}

export interface Event<T> {
type: string;
message: T;
}

@Injectable()
export class EventBus {

private readonly stream: Subject<Event<any>> = new Subject<Event<any>>();

constructor(
@Inject(EVENTS_PROVIDER) private readonly eventsProviders: EventsProvider<any>[]
) {
eventsProviders.forEach((eventsProvider: EventsProvider<any>): void => this.register(eventsProvider));
}

private register(eventsProvider: EventsProvider<any>): void {
if (eventsProvider.eventType == null) {
console.error('Received EventsProvider without EventType!');
return;
}
if (!eventsProvider.events) {
console.error('Received EventsProvider without events!');
return;
}
eventsProvider.events
.map((e: any): Event<any> => ({ type: eventsProvider.eventType, message: e }))
.subscribe((event: any): void => this.stream.next(event));
}

all(): Observable<Event<any>> {
return this.stream.asObservable();
}

for(eventType: string, ...eventTypes: string[]): Observable<Event<any>> {
return this.all()
.filter((event: Event<any>): boolean => includes([eventType, ...eventTypes], event.type));
}

}

0 comments on commit ac111f1

Please sign in to comment.