From 14fcef62dc063f9da8fb6a0a2302f21e53ffab92 Mon Sep 17 00:00:00 2001 From: David East Date: Thu, 28 Jun 2018 13:53:51 -0600 Subject: [PATCH 1/3] feat(messaging): AngularFireMessaing --- src/messaging/index.spec.ts | 1 + src/messaging/index.ts | 1 + src/messaging/messaging.module.ts | 24 ++++++++++ src/messaging/messaging.ts | 44 +++++++++++++++++++ .../observable/request-permission.ts | 6 +++ src/messaging/package.json | 31 +++++++++++++ src/messaging/public_api.ts | 3 ++ src/messaging/test-config.ts | 8 ++++ src/messaging/tsconfig-build.json | 33 ++++++++++++++ src/messaging/tsconfig-esm.json | 19 ++++++++ src/messaging/tsconfig-test.json | 13 ++++++ src/root.spec.js | 1 + src/tsconfig.json | 1 + tools/build.js | 22 +++++++--- 14 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 src/messaging/index.spec.ts create mode 100644 src/messaging/index.ts create mode 100644 src/messaging/messaging.module.ts create mode 100644 src/messaging/messaging.ts create mode 100644 src/messaging/observable/request-permission.ts create mode 100644 src/messaging/package.json create mode 100644 src/messaging/public_api.ts create mode 100644 src/messaging/test-config.ts create mode 100644 src/messaging/tsconfig-build.json create mode 100644 src/messaging/tsconfig-esm.json create mode 100644 src/messaging/tsconfig-test.json diff --git a/src/messaging/index.spec.ts b/src/messaging/index.spec.ts new file mode 100644 index 000000000..d37e336c9 --- /dev/null +++ b/src/messaging/index.spec.ts @@ -0,0 +1 @@ +export * from './messaging.spec'; diff --git a/src/messaging/index.ts b/src/messaging/index.ts new file mode 100644 index 000000000..4aaf8f92e --- /dev/null +++ b/src/messaging/index.ts @@ -0,0 +1 @@ +export * from './public_api'; diff --git a/src/messaging/messaging.module.ts b/src/messaging/messaging.module.ts new file mode 100644 index 000000000..75b24952a --- /dev/null +++ b/src/messaging/messaging.module.ts @@ -0,0 +1,24 @@ +import { NgModule } from '@angular/core'; +import { AngularFireModule, FirebaseApp } from 'angularfire2'; +import { AngularFireMessaging } from './messaging'; +import 'firebase/messaging'; + +export function _getAngularFireMessaging(app: FirebaseApp) { + return new AngularFireMessaging(app); +} + +export const AngularFireMessagingProvider = { + provide: AngularFireMessaging, + useFactory: _getAngularFireMessaging, + deps: [ FirebaseApp ] +}; + +export const STORAGE_PROVIDERS = [ + AngularFireMessagingProvider, +]; + +@NgModule({ + imports: [ AngularFireModule ], + providers: [ STORAGE_PROVIDERS ] +}) +export class AngularFireMessagingModule { } diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts new file mode 100644 index 000000000..250111765 --- /dev/null +++ b/src/messaging/messaging.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { FirebaseApp } from 'angularfire2'; +import { messaging } from 'firebase'; +import { requestPermission } from './observable/request-permission'; +import { from } from 'rxjs'; +import { mergeMap } from 'rxjs/operators'; + +@Injectable() +export class AngularFireMessaging { + messaging: messaging.Messaging; + requestPermission: Observable; + getToken: Observable; + tokenChanges: Observable; + messages: Observable<{}>; + requestToken: Observable; + + constructor(public app: FirebaseApp) { + this.messaging = app.messaging(); + + this.requestPermission = requestPermission(this.messaging); + + this.getToken = from(this.messaging.getToken()); + + this.tokenChanges = new Observable(subscriber => { + this.messaging.getToken().then(t => subscriber.next(t)); + this.messaging.onTokenRefresh(subscriber); + }); + + this.messages = new Observable(subscriber => { + this.messaging.onMessage(subscriber); + }); + + this.requestToken = this.requestPermission.pipe( + mergeMap(() => this.tokenChanges) + ); + + } + + deleteToken(token: string) { + return from(this.messaging.deleteToken(token)!); + } + +} \ No newline at end of file diff --git a/src/messaging/observable/request-permission.ts b/src/messaging/observable/request-permission.ts new file mode 100644 index 000000000..d869b2c1d --- /dev/null +++ b/src/messaging/observable/request-permission.ts @@ -0,0 +1,6 @@ +import { Observable, from } from 'rxjs'; +import { messaging } from 'firebase'; + +export function requestPermission(messaging: messaging.Messaging): Observable { + return from(messaging.requestPermission()!); +} diff --git a/src/messaging/package.json b/src/messaging/package.json new file mode 100644 index 000000000..360fc5520 --- /dev/null +++ b/src/messaging/package.json @@ -0,0 +1,31 @@ +{ + "name": "angularfire2/messaging", + "version": "ANGULARFIRE2_VERSION", + "description": "The messaging module", + "main": "../bundles/messaging.umd.js", + "module": "index.js", + "es2015": "./es2015/index.js", + "keywords": [ + "angular", + "firebase", + "rxjs" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/angular/angularfire2.git" + }, + "author": "angular,firebase", + "license": "MIT", + "peerDependencies": { + "angularfire2": "ANGULARFIRE2_VERSION", + "@angular/common": "ANGULAR_VERSION", + "@angular/core": "ANGULAR_VERSION", + "@angular/platform-browser": "ANGULAR_VERSION", + "@angular/platform-browser-dynamic": "ANGULAR_VERSION", + "@firebase/app": "FIREBASE_APP_VERSION", + "@firebase/messaging": "FIREBASE_MESSAGING_VERSION", + "rxjs": "RXJS_VERSION", + "zone.js": "ZONEJS_VERSION" + }, + "typings": "index.d.ts" +} diff --git a/src/messaging/public_api.ts b/src/messaging/public_api.ts new file mode 100644 index 000000000..0c09cbd56 --- /dev/null +++ b/src/messaging/public_api.ts @@ -0,0 +1,3 @@ +export * from './observable/request-permission'; +export * from './messaging'; +export * from './messaging.module'; diff --git a/src/messaging/test-config.ts b/src/messaging/test-config.ts new file mode 100644 index 000000000..58f9efc32 --- /dev/null +++ b/src/messaging/test-config.ts @@ -0,0 +1,8 @@ + +export const COMMON_CONFIG = { + apiKey: "AIzaSyBVSy3YpkVGiKXbbxeK0qBnu3-MNZ9UIjA", + authDomain: "angularfire2-test.firebaseapp.com", + databaseURL: "https://angularfire2-test.firebaseio.com", + storageBucket: "angularfire2-test.appspot.com", + messagingSenderId: "920323787688" +}; diff --git a/src/messaging/tsconfig-build.json b/src/messaging/tsconfig-build.json new file mode 100644 index 000000000..749fa92b6 --- /dev/null +++ b/src/messaging/tsconfig-build.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "module": "es2015", + "target": "es2015", + "noImplicitAny": false, + "outDir": "../../dist/packages-dist/messaging/es2015", + "rootDir": ".", + "sourceMap": true, + "inlineSources": true, + "declaration": false, + "removeComments": true, + "strictNullChecks": true, + "lib": ["es2015", "dom", "es2015.promise", "es2015.collection", "es2015.iterable"], + "skipLibCheck": true, + "moduleResolution": "node", + "paths": { + "angularfire2": ["../../dist/packages-dist"] + } + }, + "files": [ + "index.ts", + "../../node_modules/zone.js/dist/zone.js.d.ts" + ], + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "enableSummariesForJit": false + } +} + diff --git a/src/messaging/tsconfig-esm.json b/src/messaging/tsconfig-esm.json new file mode 100644 index 000000000..0b3d05820 --- /dev/null +++ b/src/messaging/tsconfig-esm.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig-build.json", + "compilerOptions": { + "target": "es5", + "outDir": "../../dist/packages-dist/messaging", + "declaration": true + }, + "files": [ + "public_api.ts", + "../../node_modules/zone.js/dist/zone.js.d.ts" + ], + "angularCompilerOptions": { + "skipTemplateCodegen": true, + "strictMetadataEmit": true, + "enableSummariesForJit": false, + "flatModuleOutFile": "index.js", + "flatModuleId": "angularfire2/messaging" + } +} diff --git a/src/messaging/tsconfig-test.json b/src/messaging/tsconfig-test.json new file mode 100644 index 000000000..fc0dc883b --- /dev/null +++ b/src/messaging/tsconfig-test.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig-esm.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "angularfire2": ["../../dist/packages-dist"] + } + }, + "files": [ + "index.spec.ts", + "../../node_modules/zone.js/dist/zone.js.d.ts" + ] +} diff --git a/src/root.spec.js b/src/root.spec.js index 476e302b2..36aa0c0b8 100644 --- a/src/root.spec.js +++ b/src/root.spec.js @@ -13,6 +13,7 @@ export * from './packages-dist/database/list/snapshot-changes.spec'; export * from './packages-dist/database/list/state-changes.spec'; export * from './packages-dist/database/list/audit-trail.spec'; export * from './packages-dist/storage/storage.spec'; +export * from './packages-dist/messaging/messaging.spec'; // // Since this a deprecated API, we run on it on manual tests only // // It needs a network connection to run which makes it flaky on Travis diff --git a/src/tsconfig.json b/src/tsconfig.json index 35fa29c65..241f63939 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -16,6 +16,7 @@ "angularfire2/firestore": ["./firestore"], "angularfire2/functions": ["./functions"], "angularfire2/storage": ["./storage"], + "angularfire2/messaging": ["./messaging"], "angularfire2/database-deprecated": ["./database-deprecated"] }, "rootDir": ".", diff --git a/tools/build.js b/tools/build.js index ce8069736..892cf4495 100644 --- a/tools/build.js +++ b/tools/build.js @@ -29,7 +29,8 @@ const GLOBALS = { 'angularfire2/database-deprecated': 'angularfire2.database_deprecated', 'angularfire2/firestore': 'angularfire2.firestore', 'angularfire2/functions': 'angularfire2.functions', - 'angularfire2/storage': 'angularfire2.storage' + 'angularfire2/storage': 'angularfire2.storage', + 'angularfire2/messaging': 'angularfire2.messaging', }; // Map of dependency versions across all packages @@ -53,7 +54,8 @@ const MODULE_NAMES = { "database-deprecated": 'angularfire2.database_deprecated', firestore: 'angularfire2.firestore', functions: 'angularfire2.functions', - storage: 'angularfire2.storage' + storage: 'angularfire2.storage', + messaging: 'angularfire2.messaging', }; const ENTRIES = { @@ -63,7 +65,8 @@ const ENTRIES = { "database-deprecated": `${process.cwd()}/dist/packages-dist/database-deprecated/index.js`, firestore: `${process.cwd()}/dist/packages-dist/firestore/index.js`, functions: `${process.cwd()}/dist/packages-dist/functions/index.js`, - storage: `${process.cwd()}/dist/packages-dist/storage/index.js` + storage: `${process.cwd()}/dist/packages-dist/storage/index.js`, + messaging: `${process.cwd()}/dist/packages-dist/messaging/index.js`, }; const SRC_PKG_PATHS = { @@ -74,7 +77,8 @@ const SRC_PKG_PATHS = { firestore: `${process.cwd()}/src/firestore/package.json`, "firebase-node": `${process.cwd()}/src/firebase-node/package.json`, functions: `${process.cwd()}/src/functions/package.json`, - storage: `${process.cwd()}/src/storage/package.json` + storage: `${process.cwd()}/src/storage/package.json`, + messaging: `${process.cwd()}/src/messaging/package.json`, }; const DEST_PKG_PATHS = { @@ -85,7 +89,8 @@ const DEST_PKG_PATHS = { firestore: `${process.cwd()}/dist/packages-dist/firestore/package.json`, "firebase-node": `${process.cwd()}/dist/packages-dist/firebase-node/package.json`, functions: `${process.cwd()}/dist/packages-dist/functions/package.json`, - storage: `${process.cwd()}/dist/packages-dist/storage/package.json` + storage: `${process.cwd()}/dist/packages-dist/storage/package.json`, + messaging: `${process.cwd()}/dist/packages-dist/messaging/package.json`, }; // Constants for running typescript commands @@ -246,6 +251,7 @@ function getVersions() { getDestPackageFile('firebase-node'), getDestPackageFile('functions'), getDestPackageFile('storage'), + getDestPackageFile('messaging'), getDestPackageFile('database-deprecated') ]; return paths @@ -285,6 +291,7 @@ function buildModules(globals) { const firestore$ = buildModule('firestore', globals); const functions$ = buildModule('functions', globals); const storage$ = buildModule('storage', globals); + const messaging$ = buildModule('messaging', globals); const dbdep$ = buildModule('database-deprecated', globals); return forkJoin(core$, from(copyRootTest())).pipe( switchMapTo(auth$), @@ -292,7 +299,8 @@ function buildModules(globals) { switchMapTo(firestore$), switchMapTo(functions$), switchMapTo(storage$), - switchMapTo(dbdep$) + switchMapTo(messaging$), + switchMapTo(dbdep$), ); } @@ -312,6 +320,7 @@ function buildLibrary(globals) { const fsStats = measure('firestore'); const functionsStats = measure('functions'); const storageStats = measure('storage'); + const messagingStats = measure('messaging'); const dbdepStats = measure('database-deprecated'); console.log(` core.umd.js - ${coreStats.size}, ${coreStats.gzip} @@ -320,6 +329,7 @@ function buildLibrary(globals) { firestore.umd.js - ${fsStats.size}, ${fsStats.gzip} functions.umd.js - ${functionsStats.size}, ${functionsStats.gzip} storage.umd.js - ${storageStats.size}, ${storageStats.gzip} + messaging.umd.js - ${messagingStats.size}, ${messagingStats.gzip} database-deprecated.umd.js - ${dbdepStats.size}, ${dbdepStats.gzip} `); verifyVersions(); From ec6937f75f3202727dedc69d1f827677e9d12d95 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Fri, 10 Aug 2018 00:35:45 -0700 Subject: [PATCH 2/3] Zone.js and DI on top of this work, also fixing a couple small things --- src/messaging/messaging.ts | 77 ++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/messaging/messaging.ts b/src/messaging/messaging.ts index 250111765..2d49710fe 100644 --- a/src/messaging/messaging.ts +++ b/src/messaging/messaging.ts @@ -1,10 +1,11 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { FirebaseApp } from 'angularfire2'; +import { Injectable, Inject, Optional, NgZone, PLATFORM_ID } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; import { messaging } from 'firebase'; import { requestPermission } from './observable/request-permission'; -import { from } from 'rxjs'; -import { mergeMap } from 'rxjs/operators'; +import { Observable, empty, from, of, throwError } from 'rxjs'; +import { mergeMap, catchError } from 'rxjs/operators'; +import { FirebaseOptions, FirebaseAppConfig } from 'angularfire2'; +import { FirebaseOptionsToken, FirebaseNameOrConfigToken, _firebaseAppFactory, FirebaseZoneScheduler } from 'angularfire2'; @Injectable() export class AngularFireMessaging { @@ -14,31 +15,61 @@ export class AngularFireMessaging { tokenChanges: Observable; messages: Observable<{}>; requestToken: Observable; + deleteToken: (string) => Observable; - constructor(public app: FirebaseApp) { - this.messaging = app.messaging(); + constructor( + @Inject(FirebaseOptionsToken) options:FirebaseOptions, + @Optional() @Inject(FirebaseNameOrConfigToken) nameOrConfig:string|FirebaseAppConfig|undefined, + @Inject(PLATFORM_ID) platformId: Object, + zone: NgZone + ) { + const scheduler = new FirebaseZoneScheduler(zone, platformId); + this.messaging = zone.runOutsideAngular(() => { + const app = _firebaseAppFactory(options, nameOrConfig); + return app.messaging(); + }); - this.requestPermission = requestPermission(this.messaging); + if (isPlatformBrowser(platformId)) { - this.getToken = from(this.messaging.getToken()); + this.requestPermission = scheduler.runOutsideAngular( + requestPermission(this.messaging) + ); - this.tokenChanges = new Observable(subscriber => { - this.messaging.getToken().then(t => subscriber.next(t)); - this.messaging.onTokenRefresh(subscriber); - }); + this.getToken = scheduler.runOutsideAngular( + from(this.messaging.getToken()) + ); - this.messages = new Observable(subscriber => { - this.messaging.onMessage(subscriber); - }); - - this.requestToken = this.requestPermission.pipe( - mergeMap(() => this.tokenChanges) - ); + this.tokenChanges = scheduler.runOutsideAngular( + new Observable(subscriber => { + this.messaging.getToken().then(t => subscriber.next(t)); + this.messaging.onTokenRefresh(subscriber.next); + }) + ); - } + this.messages = scheduler.runOutsideAngular( + new Observable(subscriber => { + this.messaging.onMessage(subscriber.next); + }) + ); - deleteToken(token: string) { - return from(this.messaging.deleteToken(token)!); + this.requestToken = this.requestPermission.pipe( + catchError(() => of(null)), + mergeMap(() => this.tokenChanges), + ); + + } else { + + this.requestPermission = throwError('Not available on server platform.'); + this.getToken = of(null); + this.tokenChanges = of(null); + this.messages = empty(); + this.requestToken = of(null); + + } + + this.deleteToken = (token: string) => scheduler.runOutsideAngular( + from(this.messaging.deleteToken(token)) + ); } } \ No newline at end of file From 32ed3418c27fb4308895e5fc157396aaa62cbb41 Mon Sep 17 00:00:00 2001 From: James Daniels Date: Fri, 10 Aug 2018 01:40:05 -0700 Subject: [PATCH 3/3] Cleanup the build --- src/messaging/messaging.module.ts | 17 +---------------- src/root.spec.js | 2 +- tools/build.js | 1 + 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/messaging/messaging.module.ts b/src/messaging/messaging.module.ts index 75b24952a..b9f5ea989 100644 --- a/src/messaging/messaging.module.ts +++ b/src/messaging/messaging.module.ts @@ -3,22 +3,7 @@ import { AngularFireModule, FirebaseApp } from 'angularfire2'; import { AngularFireMessaging } from './messaging'; import 'firebase/messaging'; -export function _getAngularFireMessaging(app: FirebaseApp) { - return new AngularFireMessaging(app); -} - -export const AngularFireMessagingProvider = { - provide: AngularFireMessaging, - useFactory: _getAngularFireMessaging, - deps: [ FirebaseApp ] -}; - -export const STORAGE_PROVIDERS = [ - AngularFireMessagingProvider, -]; - @NgModule({ - imports: [ AngularFireModule ], - providers: [ STORAGE_PROVIDERS ] + providers: [ AngularFireMessaging ] }) export class AngularFireMessagingModule { } diff --git a/src/root.spec.js b/src/root.spec.js index 36aa0c0b8..27cfec26b 100644 --- a/src/root.spec.js +++ b/src/root.spec.js @@ -13,7 +13,7 @@ export * from './packages-dist/database/list/snapshot-changes.spec'; export * from './packages-dist/database/list/state-changes.spec'; export * from './packages-dist/database/list/audit-trail.spec'; export * from './packages-dist/storage/storage.spec'; -export * from './packages-dist/messaging/messaging.spec'; +//export * from './packages-dist/messaging/messaging.spec'; // // Since this a deprecated API, we run on it on manual tests only // // It needs a network connection to run which makes it flaky on Travis diff --git a/tools/build.js b/tools/build.js index 892cf4495..466dc6548 100644 --- a/tools/build.js +++ b/tools/build.js @@ -20,6 +20,7 @@ const GLOBALS = { 'firebase/app': 'firebase', 'firebase/auth': 'firebase', 'firebase/database': 'firebase', + 'firebase/messaging': 'firebase', 'firebase/firestore': 'firebase', 'firebase/functions': 'firebase', 'firebase/storage': 'firebase',