Move async popup functions to message pass through the background script using a message queue because 'extensions.webextensions.remote' pref breaks async messages. Fixes #670

This commit is contained in:
Jonathan Kingston 2017-07-14 14:46:41 +01:00
parent 1c8530ef02
commit 9907be9537
3 changed files with 74 additions and 5 deletions

View file

@ -274,9 +274,19 @@ const ContainerService = {
try { try {
const api = await webExtension.startup(); const api = await webExtension.startup();
api.browser.runtime.onMessage.addListener((message, sender, sendReply) => { api.browser.runtime.onMessage.addListener(async function (message, sender, sendReply) {
if ("method" in message && methods.indexOf(message.method) !== -1) { if ("method" in message && methods.indexOf(message.method) !== -1) {
sendReply(this[message.method](message)); const response = ContainerService[message.method](message);
if (response instanceof Promise) {
const responseValue = await response;
ContainerService.triggerBackgroundCallback({
response: responseValue,
method: message.method,
uuid: message.uuid
}, "async-background-response");
} else {
sendReply(response);
}
} }
}); });

View file

@ -499,6 +499,13 @@ const messageHandler = {
const port = browser.runtime.connect(); const port = browser.runtime.connect();
port.onMessage.addListener(m => { port.onMessage.addListener(m => {
switch (m.type) { switch (m.type) {
case "async-background-response":
browser.runtime.sendMessage({
method: "async-popup-response",
message: m.message.response,
uuid: m.message.uuid
});
break;
case "lightweight-theme-changed": case "lightweight-theme-changed":
themeManager.update(m.message); themeManager.update(m.message);
break; break;

View file

@ -83,6 +83,14 @@ const Logic = {
const identitiesPromise = this.refreshIdentities(); const identitiesPromise = this.refreshIdentities();
// Get the onboarding variation // Get the onboarding variation
const variationPromise = this.getShieldStudyVariation(); const variationPromise = this.getShieldStudyVariation();
browser.runtime.onMessage.addListener((m) => {
if (m.method === "async-popup-response" && m.uuid) {
const uuid = m.uuid;
if (uuid in this.asyncMessageQueue) {
this.asyncMessageQueue[uuid].response = m.message;
}
}
});
try { try {
await Promise.all([identitiesPromise, variationPromise]); await Promise.all([identitiesPromise, variationPromise]);
@ -183,12 +191,56 @@ const Logic = {
return false; return false;
}, },
asyncTimeout: 2000,
asyncRefresh: 20,
asyncMessageQueue: {},
asyncId() {
// UUID SO result, as you do
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
)
},
asyncCreateMessage() {
const guid = this.asyncId();
this.asyncMessageQueue[guid] = {
time: Date.now(),
response: null
};
return guid;
},
awaitMessage(methodName) {
return new Promise((resolve, reject) => {
const messageId = this.asyncCreateMessage();
browser.runtime.sendMessage({
method: methodName,
uuid: messageId
});
const checkState = () => {
const messageState = this.asyncMessageQueue[messageId];
if (messageState.response !== null) {
resolve(messageState.response);
delete this.asyncMessageQueue[messageId];
return;
}
if (Date.now() - this.asyncTimeout > messageState.time) {
reject(null);
delete this.asyncMessageQueue[messageId];
return;
} else {
setTimeout(checkState, this.asyncRefresh);
}
};
checkState();
});
},
refreshIdentities() { refreshIdentities() {
return Promise.all([ return Promise.all([
browser.contextualIdentities.query({}), browser.contextualIdentities.query({}),
browser.runtime.sendMessage({ this.awaitMessage("queryIdentitiesState")
method: "queryIdentitiesState"
})
]).then(([identities, state]) => { ]).then(([identities, state]) => {
this._identities = identities.map((identity) => { this._identities = identities.map((identity) => {
const stateObject = state[Logic.userContextId(identity.cookieStoreId)]; const stateObject = state[Logic.userContextId(identity.cookieStoreId)];