refactor(service-worker): simplify/improve NgswCommChannel typings (#23138)

PR Close #23138
This commit is contained in:
George Kalpakas 2018-04-02 22:12:02 +03:00 committed by Jason Aden
parent 9e5b0794c5
commit 59d80c471a
2 changed files with 31 additions and 35 deletions

View File

@ -33,6 +33,14 @@ export interface UpdateActivatedEvent {
current: {hash: string, appData?: Object}; current: {hash: string, appData?: Object};
} }
/**
* An event emitted when a `PushEvent` is received by the service worker.
*/
export interface PushEvent {
type: 'PUSH';
data: any;
}
export type IncomingEvent = UpdateAvailableEvent | UpdateActivatedEvent; export type IncomingEvent = UpdateAvailableEvent | UpdateActivatedEvent;
export interface TypedEvent { type: string; } export interface TypedEvent { type: string; }
@ -72,30 +80,23 @@ export class NgswCommChannel {
if (!serviceWorker) { if (!serviceWorker) {
this.worker = this.events = this.registration = errorObservable(ERR_SW_NOT_SUPPORTED); this.worker = this.events = this.registration = errorObservable(ERR_SW_NOT_SUPPORTED);
} else { } else {
const controllerChangeEvents = const controllerChangeEvents = fromEvent(serviceWorker, 'controllerchange');
<Observable<any>>(fromEvent(serviceWorker, 'controllerchange')); const controllerChanges = controllerChangeEvents.pipe(map(() => serviceWorker.controller));
const controllerChanges = <Observable<ServiceWorker|null>>( const currentController = defer(() => of (serviceWorker.controller));
controllerChangeEvents.pipe(map(() => serviceWorker.controller))); const controllerWithChanges = concat(currentController, controllerChanges);
const currentController = this.worker = controllerWithChanges.pipe(filter<ServiceWorker>(c => !!c));
<Observable<ServiceWorker|null>>(defer(() => of (serviceWorker.controller)));
const controllerWithChanges =
<Observable<ServiceWorker|null>>(concat(currentController, controllerChanges));
this.worker = <Observable<ServiceWorker>>(
controllerWithChanges.pipe(filter((c: ServiceWorker) => !!c)));
this.registration = <Observable<ServiceWorkerRegistration>>( this.registration = <Observable<ServiceWorkerRegistration>>(
this.worker.pipe(switchMap(() => serviceWorker.getRegistration()))); this.worker.pipe(switchMap(() => serviceWorker.getRegistration())));
const rawEvents = fromEvent(serviceWorker, 'message'); const rawEvents = fromEvent<MessageEvent>(serviceWorker, 'message');
const rawEventPayload = rawEvents.pipe(map(event => event.data));
const rawEventPayload = rawEvents.pipe(map((event: MessageEvent) => event.data)); const eventsUnconnected = rawEventPayload.pipe(filter(event => event && event.type));
const eventsUnconnected =
(rawEventPayload.pipe(filter((event: Object) => !!event && !!(event as any)['type'])));
const events = eventsUnconnected.pipe(publish()) as ConnectableObservable<IncomingEvent>; const events = eventsUnconnected.pipe(publish()) as ConnectableObservable<IncomingEvent>;
this.events = events;
events.connect(); events.connect();
this.events = events;
} }
} }
@ -130,19 +131,16 @@ export class NgswCommChannel {
/** /**
* @internal * @internal
*/ */
// TODO(i): the typings and casts in this method are wonky, we should revisit it and make the eventsOfType<T extends TypedEvent>(type: T['type']): Observable<T> {
// types flow correctly const filterFn = (event: TypedEvent): event is T => event.type === type;
eventsOfType<T extends TypedEvent>(type: string): Observable<T> { return this.events.pipe(filter(filterFn));
return <Observable<T>>this.events.pipe(filter((event) => { return event.type === type; }));
} }
/** /**
* @internal * @internal
*/ */
// TODO(i): the typings and casts in this method are wonky, we should revisit it and make the nextEventOfType<T extends TypedEvent>(type: T['type']): Observable<T> {
// types flow correctly return this.eventsOfType(type).pipe(take(1));
nextEventOfType<T extends TypedEvent>(type: string): Observable<T> {
return <Observable<T>>(this.eventsOfType(type).pipe(take(1)));
} }
/** /**
@ -150,14 +148,12 @@ export class NgswCommChannel {
*/ */
waitForStatus(nonce: number): Promise<void> { waitForStatus(nonce: number): Promise<void> {
return this.eventsOfType<StatusEvent>('STATUS') return this.eventsOfType<StatusEvent>('STATUS')
.pipe( .pipe(filter(event => event.nonce === nonce), take(1), map(event => {
filter((event: StatusEvent) => event.nonce === nonce), take(1), if (event.status) {
map((event: StatusEvent) => { return undefined;
if (event.status) { }
return undefined; throw new Error(event.error !);
} }))
throw new Error(event.error !);
}))
.toPromise(); .toPromise();
} }

View File

@ -10,7 +10,7 @@ import {Injectable} from '@angular/core';
import {NEVER, Observable, Subject, merge} from 'rxjs'; import {NEVER, Observable, Subject, merge} from 'rxjs';
import {map, switchMap, take} from 'rxjs/operators'; import {map, switchMap, take} from 'rxjs/operators';
import {ERR_SW_NOT_SUPPORTED, NgswCommChannel} from './low_level'; import {ERR_SW_NOT_SUPPORTED, NgswCommChannel, PushEvent} from './low_level';
/** /**
@ -34,7 +34,7 @@ export class SwPush {
this.subscription = NEVER; this.subscription = NEVER;
return; return;
} }
this.messages = this.sw.eventsOfType('PUSH').pipe(map((message: any) => message.data)); this.messages = this.sw.eventsOfType<PushEvent>('PUSH').pipe(map(message => message.data));
this.pushManager = this.sw.registration.pipe( this.pushManager = this.sw.registration.pipe(
map((registration: ServiceWorkerRegistration) => { return registration.pushManager; })); map((registration: ServiceWorkerRegistration) => { return registration.pushManager; }));