From 1ec86c7fd2b308e55165d2376fb825a5a92c6950 Mon Sep 17 00:00:00 2001 From: Jonathan Kingston Date: Mon, 8 May 2017 14:32:35 +0100 Subject: [PATCH] Moving remove, add and update code into the web extension background for stability --- webextension/background.js | 114 ++++++++++++++++++++++++++------ webextension/js/confirm-page.js | 2 +- webextension/js/popup.js | 94 ++++++-------------------- 3 files changed, 113 insertions(+), 97 deletions(-) diff --git a/webextension/background.js b/webextension/background.js index 6a85cbc..93bdd78 100644 --- a/webextension/background.js +++ b/webextension/background.js @@ -74,17 +74,6 @@ const assignManager = { }, init() { - browser.runtime.onMessage.addListener((m) => { - switch (m.type) { - case "delete-container": - assignManager.deleteContainer(m.message.userContextId); - break; - case "never-ask": - this._neverAsk(m); - break; - } - }); - browser.contextMenus.onClicked.addListener((info, tab) => { const userContextId = this.getUserContextIdFromCookieStore(tab); // Mapping ${URL(info.pageUrl).hostname} to ${userContextId} @@ -108,8 +97,7 @@ const assignManager = { message: `Successfully ${actionName} site to always open in this container`, iconUrl: browser.extension.getURL("/img/onboarding-1.png") }); - browser.runtime.sendMessage({ - method: "sendTelemetryPayload", + backgroundLogic.sendTelemetryPayload({ event: `${actionName}-container-assignment`, userContextId: userContextId, }); @@ -229,14 +217,12 @@ const assignManager = { // If the user has explicitly checked "Never Ask Again" on the warning page we will send them straight there if (neverAsk) { browser.tabs.create({url, cookieStoreId: `firefox-container-${userContextId}`, index}); - browser.runtime.sendMessage({ - method: "sendTelemetryPayload", + backgroundLogic.sendTelemetryPayload({ event: "auto-reload-page-in-container", userContextId: userContextId, }); } else { - browser.runtime.sendMessage({ - method: "sendTelemetryPayload", + backgroundLogic.sendTelemetryPayload({ event: "prompt-to-reload-page-in-container", userContextId: userContextId, }); @@ -251,6 +237,77 @@ const assignManager = { } }; + +const backgroundLogic = { + deleteContainer(userContextId) { + this.sendTelemetryPayload({ + event: "delete-container", + userContextId + }); + + const removeTabsPromise = this._containerTabs(userContextId).then((tabs) => { + const tabIds = tabs.map((tab) => tab.id); + return browser.tabs.remove(tabIds); + }); + + return new Promise((resolve) => { + removeTabsPromise.then(() => { + const removed = browser.contextualIdentities.remove(this.cookieStoreId(userContextId)); + removed.then(() => { + assignManager.deleteContainer(userContextId); + browser.runtime.sendMessage({ + method: "forgetIdentityAndRefresh" + }).then(() => { + resolve({done: true, userContextId}); + }).catch((e) => {throw e;}); + }).catch((e) => {throw e;}); + }).catch((e) => {throw e;}); + }); + }, + + createOrUpdateContainer(options) { + let donePromise; + if (options.userContextId) { + donePromise = browser.contextualIdentities.update( + this.cookieStoreId(options.userContextId), + options.params + ); + this.sendTelemetryPayload({ + event: "edit-container", + userContextId: options.userContextId + }); + } else { + donePromise = browser.contextualIdentities.create(options.params); + this.sendTelemetryPayload({ + event: "add-container" + }); + } + return donePromise.then(() => { + browser.runtime.sendMessage({ + method: "refreshNeeded" + }); + }); + }, + + sendTelemetryPayload(message = {}) { + if (!message.event) { + throw new Error("Missing event name for telemetry"); + } + message.method = "sendTelemetryPayload"; + browser.runtime.sendMessage(message); + }, + + cookieStoreId(userContextId) { + return `firefox-container-${userContextId}`; + }, + + _containerTabs(userContextId) { + return browser.tabs.query({ + cookieStoreId: this.cookieStoreId(userContextId) + }).catch((e) => {throw e;}); + }, +}; + const messageHandler = { // After the timer completes we assume it's a tab the user meant to keep open // We use this to catch redirected tabs that have just opened @@ -258,6 +315,23 @@ const messageHandler = { LAST_CREATED_TAB_TIMER: 2000, init() { + browser.runtime.onMessage.addListener((m) => { + let response; + + switch (m.method) { + case "deleteContainer": + response = backgroundLogic.deleteContainer(m.message.userContextId); + break; + case "createOrUpdateContainer": + response = backgroundLogic.createOrUpdateContainer(m.message); + break; + case "neverAsk": + assignManager._neverAsk(m); + break; + } + return response; + }); + // Handles messages from index.js const port = browser.runtime.connect(); port.onMessage.addListener(m => { @@ -416,8 +490,7 @@ const tabPageCounter = { return; } if (why === "user-closed-tab" && this.counters[tabId].tab) { - browser.runtime.sendMessage({ - method: "sendTelemetryPayload", + backgroundLogic.sendTelemetryPayload({ event: "page-requests-completed-per-tab", userContextId: this.counters[tabId].tab.cookieStoreId, pageRequestCount: this.counters[tabId].tab.pageRequests @@ -426,8 +499,7 @@ const tabPageCounter = { // delete both the 'tab' and 'activity' counters delete this.counters[tabId]; } else if (why === "user-went-idle" && this.counters[tabId].activity) { - browser.runtime.sendMessage({ - method: "sendTelemetryPayload", + backgroundLogic.sendTelemetryPayload({ event: "page-requests-completed-per-activity", userContextId: this.counters[tabId].activity.cookieStoreId, pageRequestCount: this.counters[tabId].activity.pageRequests diff --git a/webextension/js/confirm-page.js b/webextension/js/confirm-page.js index 319afec..d54dd06 100644 --- a/webextension/js/confirm-page.js +++ b/webextension/js/confirm-page.js @@ -9,7 +9,7 @@ document.getElementById("redirect-form").addEventListener("submit", (e) => { // Sending neverAsk message to background to store for next time we see this process if (neverAsk) { browser.runtime.sendMessage({ - type: "never-ask", + method: "neverAsk", neverAsk: true, pageUrl: redirectUrl }).then(() => { diff --git a/webextension/js/popup.js b/webextension/js/popup.js index 4dbc0c0..68f5dc1 100644 --- a/webextension/js/popup.js +++ b/webextension/js/popup.js @@ -141,26 +141,6 @@ const Logic = { return this._currentIdentity; }, - cookieStoreId(userContextId) { - return `firefox-container-${userContextId}`; - }, - - _containerTabIterator(userContextId, cb) { - browser.tabs.query({ - cookieStoreId: Logic.cookieStoreId(userContextId) - }).then((tabs) => { - tabs.forEach((tab) => { - cb(tab); - }); - }).catch((e) => {throw e;}); - }, - - _containerTabs(userContextId) { - return browser.tabs.query({ - cookieStoreId: Logic.cookieStoreId(userContextId) - }); - }, - sendTelemetryPayload(message = {}) { if (!message.event) { throw new Error("Missing event name for telemetry"); @@ -170,33 +150,13 @@ const Logic = { }, removeIdentity(userContextId) { - const eventName = "delete-container"; if (!userContextId) { return Promise.reject("removeIdentity must be called with userContextId argument."); } - this.sendTelemetryPayload({ - event: eventName, - userContextId - }); - - const removeTabsPromise = Logic._containerTabs(userContextId).then((tabs) => { - const tabIds = tabs.map((tab) => tab.id); - return browser.tabs.remove(tabIds); - }); - - return removeTabsPromise.then(() => { - const removed = browser.contextualIdentities.remove(Logic.cookieStoreId(userContextId)); - // Send delete event to webextension/background.js - browser.runtime.sendMessage({ - type: eventName, - message: {userContextId} - }); - browser.runtime.sendMessage({ - method: "forgetIdentityAndRefresh" - }).then(() => { - return removed; - }).catch((e) => {throw e;}); + return browser.runtime.sendMessage({ + method: "deleteContainer", + message: {userContextId} }); }, @@ -589,14 +549,17 @@ Logic.registerPanel(P_CONTAINER_EDIT, { _submitForm() { const identity = Logic.currentIdentity(); const formValues = new FormData(this._editForm); - this._createOrUpdateIdentity( - { - name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(), - icon: formValues.get("container-icon") || DEFAULT_ICON, - color: formValues.get("container-color") || DEFAULT_COLOR, - }, - identity.userContextId || false - ).then(() => { + return browser.runtime.sendMessage({ + method: "createOrUpdateContainer", + message: { + userContextId: identity.userContextId || false, + params: { + name: document.getElementById("edit-container-panel-name-input").value || Logic.generateIdentityName(), + icon: formValues.get("container-icon") || DEFAULT_ICON, + color: formValues.get("container-color") || DEFAULT_COLOR, + } + } + }).then(() => { return Logic.refreshIdentities(); }).then(() => { Logic.showPreviousPanel(); @@ -605,30 +568,6 @@ Logic.registerPanel(P_CONTAINER_EDIT, { }); }, - _createOrUpdateIdentity(params, userContextId) { - let donePromise; - if (userContextId) { - donePromise = browser.contextualIdentities.update( - Logic.cookieStoreId(userContextId), - params - ); - Logic.sendTelemetryPayload({ - event: "edit-container", - userContextId - }); - } else { - donePromise = browser.contextualIdentities.create(params); - Logic.sendTelemetryPayload({ - event: "add-container" - }); - } - return donePromise.then(() => { - browser.runtime.sendMessage({ - method: "refreshNeeded" - }); - }); - }, - initializeRadioButtons() { const colorRadioTemplate = (containerColor) => { return escaped` @@ -686,6 +625,11 @@ Logic.registerPanel(P_CONTAINER_DELETE, { }); document.querySelector("#delete-container-ok-link").addEventListener("click", () => { + /* This promise wont resolve if the last tab was removed from the window. + as the message async callback stops listening, this isn't an issue for us however it might be in future + if you want to do anything post delete do it in the background script. + Browser console currently warns about not listening also. + */ Logic.removeIdentity(Logic.currentIdentity().userContextId).then(() => { return Logic.refreshIdentities(); }).then(() => {