@intuitionrobotics/push-pub-sub
Version:
184 lines • 9.73 kB
JavaScript
"use strict";
/*
* A typescript & react boilerplate with api call example
*
* Copyright (C) 2018 Intuition Robotics
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PushPubSubModule = exports.PushPubSubModule_Class = exports.pushSessionIdKey = exports.Command_SwToApp = void 0;
const ts_common_1 = require("@intuitionrobotics/ts-common");
const frontend_1 = require("@intuitionrobotics/thunderstorm/frontend");
const thunderstorm_1 = require("@intuitionrobotics/thunderstorm");
const frontend_2 = require("@intuitionrobotics/firebase/frontend");
const NotificationModule_1 = require("./NotificationModule");
exports.Command_SwToApp = "SwToApp";
exports.pushSessionIdKey = "x-push-session-id";
const pushSessionId = new frontend_1.StorageKey(exports.pushSessionIdKey, false);
class PushPubSubModule_Class extends ts_common_1.Module {
constructor() {
super("PushPubSubModule");
this.subscriptions = [];
this.timeout = 800;
this.registerServiceWorker = () => __awaiter(this, void 0, void 0, function* () {
console.log("Registering service worker...");
return yield navigator.serviceWorker.register(`/${this.config.swFileName || "ts_service_worker.js"}`);
});
this.initApp = () => {
var _a;
if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.publicKeyBase64))
throw new ts_common_1.ImplementationMissingException(`Please specify the right config for the 'PushPubSubModule'`);
this.runAsync("Initializing Firebase SDK and registering SW", () => __awaiter(this, void 0, void 0, function* () {
if ("serviceWorker" in navigator) {
const asyncs = [
this.registerServiceWorker(),
frontend_2.FirebaseModule.createSession()
];
const { 0: registration, 1: app } = yield Promise.all(asyncs);
yield registration.update();
this.messaging = app.getMessaging();
// this.messaging.usePublicVapidKey(this.config.publicKeyBase64);
// await this.messaging.useServiceWorker(registration);
yield this.getToken({ vapidKey: this.config.publicKeyBase64, serviceWorkerRegistration: registration });
if (navigator.serviceWorker.controller) {
console.log(`This page is currently controlled by: ${navigator.serviceWorker.controller}`);
}
navigator.serviceWorker.oncontrollerchange = function () {
console.log("This page is now controlled by:", navigator.serviceWorker.controller);
};
navigator.serviceWorker.onmessage = (event) => {
this.processMessageFromSw(event.data);
};
}
}));
};
// / need to call this from the login verified
this.getToken = (options) => __awaiter(this, void 0, void 0, function* () {
try {
this.logVerbose("Checking/Requesting permission...");
const permission = yield Notification.requestPermission();
this.logVerbose(`Notification permission: ${permission}`);
if (permission !== "granted")
return;
if (!this.messaging)
throw new ts_common_1.BadImplementationException("I literally just set this!");
this.firebaseToken = yield this.messaging.getToken(options);
if (!this.firebaseToken)
return;
this.messaging.onMessage((payload) => {
if (!payload.data)
return this.logInfo('No data passed to the message handler, I got this', payload);
this.processMessage(payload.data);
});
this.logVerbose("new token received: " + this.firebaseToken);
// this.logWarning("I don't believe there is a good reason to register whenever an app starts.. before we have any information about user or app status!!")
// this.logWarning("Convince me otherwise.. :)")
// Race Condition in CC proved that I didnt register for push due to the getToken being async which ended after modules init
// so I had subscriptions but didnt register them
if (this.subscriptions.length > 0)
this.register();
}
catch (err) {
this.logError("Unable to get token", err);
}
});
this.processMessageFromSw = (data) => {
this.logInfo("Got data from SW: ", data);
if (!data.command || !data.message || data.command !== exports.Command_SwToApp)
return;
this.processMessage(data.message);
};
this.processMessage = (data) => {
this.logInfo("process message", data);
const arr = JSON.parse(data.messages);
arr.forEach(s => {
s.persistent && NotificationModule_1.NotificationsModule.addNotification(s);
this.subscriptions
.filter(d => d.pushKey === s.pushKey && (0, ts_common_1.compare)(s.props, d.props))
.forEach(d => d.callBack(s.data));
});
};
this.subscribe = (subscription) => {
this.subscribeImpl(subscription);
return this.register();
};
this.subscribeImpl = (subscription) => {
const foundSubscription = this.subscriptions.find(d => d.pushKey === subscription.pushKey && (0, ts_common_1.compare)(subscription.props, d.props));
if (foundSubscription) {
this.logError("Subscription already exists", subscription);
return;
}
this.subscriptions.push(subscription);
};
this.subscribeMulti = (subscriptions) => {
subscriptions.forEach(subscription => this.subscribeImpl(subscription));
return this.register();
};
this.unsubscribe = (subscription) => {
const idx = this.subscriptions.findIndex(d => d.pushKey === subscription.pushKey && (0, ts_common_1.compare)(subscription.props, d.props));
const foundSubscription = idx !== -1 ? this.subscriptions[idx] : undefined;
if (foundSubscription)
this.subscriptions.splice(idx, 1);
return this.register();
};
this.register = () => {
const firebaseToken = this.firebaseToken;
if (!firebaseToken)
return this.logWarning("No Firebase token...");
this.debounce(() => {
const body = {
firebaseToken,
pushSessionId: this.getPushSessionId(),
subscriptions: this.subscriptions.map(({ pushKey, props }) => ({ pushKey, props }))
};
this.logDebug("Registering subscriptions");
for (const sub of this.subscriptions) {
this.logDebug(`${sub.pushKey} => ${sub.props ? (0, ts_common_1.__stringify)(sub.props) : "no props"}`);
}
frontend_1.XhrHttpModule
.createRequest(thunderstorm_1.HttpMethod.POST, "register-pub-sub-tab")
.setRelativeUrl("/v1/push/register")
.setJsonBody(body)
.setOnError("Failed to register for push")
.execute((response) => {
NotificationModule_1.NotificationsModule.setNotificationList(response);
this.logVerbose("Finished register PubSub");
});
}, "debounce-register", this.timeout);
};
window.name = window.name || (0, ts_common_1.generateHex)(32);
this.pushSessionId = pushSessionId.set(window.name);
}
init() {
var _a;
if (((_a = this.config) === null || _a === void 0 ? void 0 : _a.registerOnInit) === false)
return;
this.initApp();
}
getPushSessionId() {
return this.pushSessionId;
}
}
exports.PushPubSubModule_Class = PushPubSubModule_Class;
exports.PushPubSubModule = new PushPubSubModule_Class();
//# sourceMappingURL=PushPubSubModule.js.map