/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import {Injectable} from '@angular/core'; import {Observable} from 'rxjs/Observable'; import {Subject} from 'rxjs/Subject'; import {merge as obs_merge} from 'rxjs/observable/merge'; import {map as op_map} from 'rxjs/operator/map'; import {switchMap as op_switchMap} from 'rxjs/operator/switchMap'; import {take as op_take} from 'rxjs/operator/take'; import {toPromise as op_toPromise} from 'rxjs/operator/toPromise'; import {NgswCommChannel} from './low_level'; /** * Subscribe and listen to push notifications from the Service Worker. * * @experimental */ @Injectable() export class SwPush { readonly messages: Observable; readonly subscription: Observable; private pushManager: Observable; private subscriptionChanges: Subject = new Subject(); constructor(private sw: NgswCommChannel) { this.messages = op_map.call(this.sw.eventsOfType('PUSH'), (message: {data: object}) => message.data); this.pushManager = >(op_map.call( this.sw.registration, (registration: ServiceWorkerRegistration) => { return registration.pushManager; })); const workerDrivenSubscriptions = >(op_switchMap.call( this.pushManager, (pm: PushManager) => pm.getSubscription().then(sub => { return sub; }))); this.subscription = obs_merge(workerDrivenSubscriptions, this.subscriptionChanges); } requestSubscription(options: {serverPublicKey: string}): Promise { const pushOptions: PushSubscriptionOptionsInit = {userVisibleOnly: true}; let key = atob(options.serverPublicKey.replace(/_/g, '/').replace(/-/g, '+')); let applicationServerKey = new Uint8Array(new ArrayBuffer(key.length)); for (let i = 0; i < key.length; i++) { applicationServerKey[i] = key.charCodeAt(i); } pushOptions.applicationServerKey = applicationServerKey; const subscribe = >( op_switchMap.call(this.pushManager, (pm: PushManager) => pm.subscribe(pushOptions))); const subscribeOnce = op_take.call(subscribe, 1); return (op_toPromise.call(subscribeOnce) as Promise).then(sub => { this.subscriptionChanges.next(sub); return sub; }); } unsubscribe(): Promise { const unsubscribe = op_switchMap.call(this.subscription, (sub: PushSubscription | null) => { if (sub !== null) { return sub.unsubscribe().then(success => { if (success) { this.subscriptionChanges.next(null); return undefined; } else { throw new Error('Unsubscribe failed!'); } }); } else { throw new Error('Not subscribed to push notifications.'); } }); const unsubscribeOnce = op_take.call(unsubscribe, 1); return op_toPromise.call(unsubscribeOnce) as Promise; } }