Skip to content

Commit 0fac707

Browse files
committed
Migrate messaging to component framework (#2323)
* Migrate messaging to component framework * remove unused import * bundle firebase services in a single object * [AUTOMATED]: Prettier Code Styling * [AUTOMATED]: License Headers * address comment
1 parent f67cbcb commit 0fac707

20 files changed

+369
-238
lines changed

packages/messaging/index.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,41 +16,60 @@
1616
*/
1717

1818
import firebase from '@firebase/app';
19+
import '@firebase/installations';
1920
import {
2021
_FirebaseNamespace,
21-
FirebaseServiceFactory
22+
FirebaseService
2223
} from '@firebase/app-types/private';
2324
import { FirebaseMessaging } from '@firebase/messaging-types';
24-
2525
import { SwController } from './src/controllers/sw-controller';
2626
import { WindowController } from './src/controllers/window-controller';
2727
import { ErrorCode, errorFactory } from './src/models/errors';
28+
import {
29+
Component,
30+
ComponentType,
31+
ComponentContainer
32+
} from '@firebase/component';
33+
import { FirebaseInternalServices } from './src/interfaces/internal-services';
2834

2935
export function registerMessaging(instance: _FirebaseNamespace): void {
3036
const messagingName = 'messaging';
3137

32-
const factoryMethod: FirebaseServiceFactory = app => {
38+
const factoryMethod = (container: ComponentContainer): FirebaseService => {
39+
/* Dependencies */
40+
const app = container.getProvider('app').getImmediate();
41+
const installations = container.getProvider('installations').getImmediate();
42+
const analyticsProvider = container.getProvider('analytics-internal');
43+
44+
const firebaseServices: FirebaseInternalServices = {
45+
app,
46+
installations,
47+
analyticsProvider
48+
};
49+
3350
if (!isSupported()) {
3451
throw errorFactory.create(ErrorCode.UNSUPPORTED_BROWSER);
3552
}
3653

3754
if (self && 'ServiceWorkerGlobalScope' in self) {
3855
// Running in ServiceWorker context
39-
return new SwController(app);
56+
return new SwController(firebaseServices);
4057
} else {
4158
// Assume we are in the window context.
42-
return new WindowController(app);
59+
return new WindowController(firebaseServices);
4360
}
4461
};
4562

4663
const namespaceExports = {
4764
isSupported
4865
};
4966

50-
instance.INTERNAL.registerService(
51-
messagingName,
52-
factoryMethod,
53-
namespaceExports
67+
instance.INTERNAL.registerComponent(
68+
new Component(
69+
messagingName,
70+
factoryMethod,
71+
ComponentType.PUBLIC
72+
).setServiceProps(namespaceExports)
5473
);
5574
}
5675

packages/messaging/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"@firebase/installations": "0.3.2",
3030
"@firebase/messaging-types": "0.3.4",
3131
"@firebase/util": "0.2.31",
32+
"@firebase/component": "0.1.0",
3233
"tslib": "1.10.0"
3334
},
3435
"devDependencies": {

packages/messaging/src/controllers/base-controller.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import { ErrorCode, errorFactory } from '../models/errors';
3333
import { SubscriptionManager } from '../models/subscription-manager';
3434
import { TokenDetailsModel } from '../models/token-details-model';
3535
import { VapidDetailsModel } from '../models/vapid-details-model';
36+
import { FirebaseInternalServices } from '../interfaces/internal-services';
3637

3738
export type BgMessageHandler = (
3839
payload: MessagePayload
@@ -43,11 +44,14 @@ export const TOKEN_EXPIRATION_MILLIS = 7 * 24 * 60 * 60 * 1000; // 7 days
4344

4445
export abstract class BaseController implements FirebaseMessaging {
4546
INTERNAL: FirebaseServiceInternals;
47+
readonly app: FirebaseApp;
4648
private readonly tokenDetailsModel: TokenDetailsModel;
4749
private readonly vapidDetailsModel = new VapidDetailsModel();
4850
private readonly subscriptionManager = new SubscriptionManager();
4951

50-
constructor(readonly app: FirebaseApp) {
52+
constructor(protected readonly services: FirebaseInternalServices) {
53+
const { app } = services;
54+
this.app = app;
5155
if (
5256
!app.options.messagingSenderId ||
5357
typeof app.options.messagingSenderId !== 'string'
@@ -59,7 +63,7 @@ export abstract class BaseController implements FirebaseMessaging {
5963
delete: () => this.delete()
6064
};
6165

62-
this.tokenDetailsModel = new TokenDetailsModel(app);
66+
this.tokenDetailsModel = new TokenDetailsModel(services);
6367
}
6468

6569
async getToken(): Promise<string | null> {
@@ -147,15 +151,15 @@ export abstract class BaseController implements FirebaseMessaging {
147151
try {
148152
const updatedToken = await this.subscriptionManager.updateToken(
149153
tokenDetails,
150-
this.app,
154+
this.services,
151155
pushSubscription,
152156
publicVapidKey
153157
);
154158

155159
const allDetails: TokenDetails = {
156160
swScope: swReg.scope,
157161
vapidKey: publicVapidKey,
158-
fcmSenderId: this.app.options.messagingSenderId!,
162+
fcmSenderId: this.services.app.options.messagingSenderId!,
159163
fcmToken: updatedToken,
160164
createTime: Date.now(),
161165
endpoint: pushSubscription.endpoint,
@@ -181,7 +185,7 @@ export abstract class BaseController implements FirebaseMessaging {
181185
publicVapidKey: Uint8Array
182186
): Promise<string> {
183187
const newToken = await this.subscriptionManager.getToken(
184-
this.app,
188+
this.services,
185189
pushSubscription,
186190
publicVapidKey
187191
);
@@ -228,7 +232,7 @@ export abstract class BaseController implements FirebaseMessaging {
228232
*/
229233
private async deleteTokenFromDB(token: string): Promise<void> {
230234
const tokenDetails = await this.tokenDetailsModel.deleteToken(token);
231-
await this.subscriptionManager.deleteToken(this.app, tokenDetails);
235+
await this.subscriptionManager.deleteToken(this.services, tokenDetails);
232236
}
233237

234238
// Visible for testing

packages/messaging/src/controllers/sw-controller.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@
1616
*/
1717

1818
import './sw-types';
19-
20-
import { FirebaseApp } from '@firebase/app-types';
21-
2219
import {
2320
MessagePayload,
2421
NotificationDetails
@@ -30,6 +27,7 @@ import {
3027
} from '../models/fcm-details';
3128
import { InternalMessage, MessageType } from '../models/worker-page-message';
3229
import { BaseController, BgMessageHandler } from './base-controller';
30+
import { FirebaseInternalServices } from '../interfaces/internal-services';
3331

3432
// Let TS know that this is a service worker
3533
declare const self: ServiceWorkerGlobalScope;
@@ -39,8 +37,8 @@ const FCM_MSG = 'FCM_MSG';
3937
export class SwController extends BaseController {
4038
private bgMessageHandler: BgMessageHandler | null = null;
4139

42-
constructor(app: FirebaseApp) {
43-
super(app);
40+
constructor(services: FirebaseInternalServices) {
41+
super(services);
4442

4543
self.addEventListener('push', e => {
4644
this.onPush(e);

packages/messaging/src/controllers/window-controller.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { FirebaseApp } from '@firebase/app-types';
1918
import { _FirebaseApp } from '@firebase/app-types/private';
2019
import {
2120
CompleteFn,
@@ -39,6 +38,7 @@ import {
3938
} from '../models/fcm-details';
4039
import { InternalMessage, MessageType } from '../models/worker-page-message';
4140
import { BaseController } from './base-controller';
41+
import { FirebaseInternalServices } from '../interfaces/internal-services';
4242

4343
export class WindowController extends BaseController {
4444
private registrationToUse: ServiceWorkerRegistration | null = null;
@@ -63,8 +63,8 @@ export class WindowController extends BaseController {
6363
/**
6464
* A service that provides a MessagingService instance.
6565
*/
66-
constructor(app: FirebaseApp) {
67-
super(app);
66+
constructor(services: FirebaseInternalServices) {
67+
super(services);
6868

6969
this.setupSWMessageListener_();
7070
}
@@ -308,16 +308,23 @@ export class WindowController extends BaseController {
308308
// This message has a campaign id, meaning it was sent using the FN Console.
309309
// Analytics is enabled on this message, so we should log it.
310310
const eventType = getEventType(firebaseMessagingType);
311-
(this.app as _FirebaseApp).INTERNAL.analytics.logEvent(
312-
eventType,
313-
/* eslint-disable camelcase */
314-
{
315-
message_name: data[FN_CAMPAIGN_NAME],
316-
message_id: data[FN_CAMPAIGN_ID],
317-
message_time: data[FN_CAMPAIGN_TIME],
318-
message_device_time: Math.floor(Date.now() / 1000)
311+
this.services.analyticsProvider.get().then(
312+
analytics => {
313+
analytics.logEvent(
314+
eventType,
315+
/* eslint-disable camelcase */
316+
{
317+
message_name: data[FN_CAMPAIGN_NAME],
318+
message_id: data[FN_CAMPAIGN_ID],
319+
message_time: data[FN_CAMPAIGN_TIME],
320+
message_device_time: Math.floor(Date.now() / 1000)
321+
}
322+
/* eslint-enable camelcase */
323+
);
324+
},
325+
() => {
326+
/* it will never reject */
319327
}
320-
/* eslint-enable camelcase */
321328
);
322329
}
323330
},
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { FirebaseApp } from '@firebase/app-types';
19+
import { FirebaseInstallations } from '@firebase/installations-types';
20+
import { FirebaseAnalyticsInternal } from '@firebase/analytics-interop-types';
21+
import { Provider } from '@firebase/component';
22+
23+
export interface FirebaseInternalServices {
24+
app: FirebaseApp;
25+
installations: FirebaseInstallations;
26+
analyticsProvider: Provider<FirebaseAnalyticsInternal>;
27+
}

packages/messaging/src/models/clean-v1-undefined.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,12 @@
2828
*/
2929

3030
import { SubscriptionManager } from './subscription-manager';
31-
import { FirebaseApp } from '@firebase/app-types';
31+
import { FirebaseInternalServices } from '../interfaces/internal-services';
3232

3333
const OLD_DB_NAME = 'undefined';
3434
const OLD_OBJECT_STORE_NAME = 'fcm_token_object_Store';
3535

36-
function handleDb(db: IDBDatabase, app: FirebaseApp): void {
36+
function handleDb(db: IDBDatabase, services: FirebaseInternalServices): void {
3737
if (!db.objectStoreNames.contains(OLD_OBJECT_STORE_NAME)) {
3838
// We found a database with the name 'undefined', but our expected object
3939
// store isn't defined.
@@ -59,7 +59,7 @@ function handleDb(db: IDBDatabase, app: FirebaseApp): void {
5959
const tokenDetails = cursor.value;
6060

6161
// eslint-disable-next-line @typescript-eslint/no-floating-promises
62-
subscriptionManager.deleteToken(app, tokenDetails);
62+
subscriptionManager.deleteToken(services, tokenDetails);
6363

6464
cursor.continue();
6565
} else {
@@ -69,13 +69,13 @@ function handleDb(db: IDBDatabase, app: FirebaseApp): void {
6969
};
7070
}
7171

72-
export function cleanV1(app: FirebaseApp): void {
72+
export function cleanV1(services: FirebaseInternalServices): void {
7373
const request: IDBOpenDBRequest = indexedDB.open(OLD_DB_NAME);
7474
request.onerror = _event => {
7575
// NOOP - Nothing we can do.
7676
};
7777
request.onsuccess = _event => {
7878
const db = request.result;
79-
handleDb(db, app);
79+
handleDb(db, services);
8080
};
8181
}

packages/messaging/src/models/subscription-manager.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import { isArrayBufferEqual } from '../helpers/is-array-buffer-equal';
2020
import { ErrorCode, errorFactory } from './errors';
2121
import { DEFAULT_PUBLIC_VAPID_KEY, ENDPOINT } from './fcm-details';
2222
import { FirebaseApp } from '@firebase/app-types';
23-
import '@firebase/installations';
2423
import { TokenDetails } from '../interfaces/token-details';
24+
import { FirebaseInternalServices } from '../interfaces/internal-services';
2525

2626
interface ApiResponse {
2727
token?: string;
@@ -39,11 +39,11 @@ interface TokenRequestBody {
3939

4040
export class SubscriptionManager {
4141
async getToken(
42-
app: FirebaseApp,
42+
services: FirebaseInternalServices,
4343
subscription: PushSubscription,
4444
vapidKey: Uint8Array
4545
): Promise<string> {
46-
const headers = await getHeaders(app);
46+
const headers = await getHeaders(services);
4747
const body = getBody(subscription, vapidKey);
4848

4949
const subscribeOptions = {
@@ -54,7 +54,7 @@ export class SubscriptionManager {
5454

5555
let responseData: ApiResponse;
5656
try {
57-
const response = await fetch(getEndpoint(app), subscribeOptions);
57+
const response = await fetch(getEndpoint(services.app), subscribeOptions);
5858
responseData = await response.json();
5959
} catch (err) {
6060
throw errorFactory.create(ErrorCode.TOKEN_SUBSCRIBE_FAILED, {
@@ -81,11 +81,11 @@ export class SubscriptionManager {
8181
*/
8282
async updateToken(
8383
tokenDetails: TokenDetails,
84-
app: FirebaseApp,
84+
services: FirebaseInternalServices,
8585
subscription: PushSubscription,
8686
vapidKey: Uint8Array
8787
): Promise<string> {
88-
const headers = await getHeaders(app);
88+
const headers = await getHeaders(services);
8989
const body = getBody(subscription, vapidKey);
9090

9191
const updateOptions = {
@@ -97,7 +97,7 @@ export class SubscriptionManager {
9797
let responseData: ApiResponse;
9898
try {
9999
const response = await fetch(
100-
`${getEndpoint(app)}/${tokenDetails.fcmToken}`,
100+
`${getEndpoint(services.app)}/${tokenDetails.fcmToken}`,
101101
updateOptions
102102
);
103103
responseData = await response.json();
@@ -122,11 +122,11 @@ export class SubscriptionManager {
122122
}
123123

124124
async deleteToken(
125-
app: FirebaseApp,
125+
services: FirebaseInternalServices,
126126
tokenDetails: TokenDetails
127127
): Promise<void> {
128128
// TODO: Add FIS header
129-
const headers = await getHeaders(app);
129+
const headers = await getHeaders(services);
130130

131131
const unsubscribeOptions = {
132132
method: 'DELETE',
@@ -135,7 +135,7 @@ export class SubscriptionManager {
135135

136136
try {
137137
const response = await fetch(
138-
`${getEndpoint(app)}/${tokenDetails.fcmToken}`,
138+
`${getEndpoint(services.app)}/${tokenDetails.fcmToken}`,
139139
unsubscribeOptions
140140
);
141141
const responseData: ApiResponse = await response.json();
@@ -157,8 +157,10 @@ function getEndpoint(app: FirebaseApp): string {
157157
return `${ENDPOINT}/projects/${app.options.projectId!}/registrations`;
158158
}
159159

160-
async function getHeaders(app: FirebaseApp): Promise<Headers> {
161-
const installations = app.installations();
160+
async function getHeaders({
161+
app,
162+
installations
163+
}: FirebaseInternalServices): Promise<Headers> {
162164
const authToken = await installations.getToken();
163165

164166
return new Headers({

0 commit comments

Comments
 (0)