mirror of https://github.com/gorhill/uBlock.git
Work toward modernizing code base: promisification
Swathes of code have been converted to use Promises/async/await. Related commits: -3224d9b5cc
-26235d80d0
-0051f3b5c7
-eec53c0154
-915687fddb
-55cc0c6997
-e27328f931
This commit is contained in:
parent
78f430678a
commit
022951547c
|
@ -32,22 +32,22 @@
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
const chrome = self.chrome;
|
const browser = self.browser;
|
||||||
const manifest = chrome.runtime.getManifest();
|
const manifest = browser.runtime.getManifest();
|
||||||
|
|
||||||
vAPI.cantWebsocket =
|
vAPI.cantWebsocket =
|
||||||
chrome.webRequest.ResourceType instanceof Object === false ||
|
browser.webRequest.ResourceType instanceof Object === false ||
|
||||||
chrome.webRequest.ResourceType.WEBSOCKET !== 'websocket';
|
browser.webRequest.ResourceType.WEBSOCKET !== 'websocket';
|
||||||
|
|
||||||
vAPI.lastError = function() {
|
vAPI.lastError = function() {
|
||||||
return chrome.runtime.lastError;
|
return browser.runtime.lastError;
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://github.com/gorhill/uBlock/issues/875
|
// https://github.com/gorhill/uBlock/issues/875
|
||||||
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
// https://code.google.com/p/chromium/issues/detail?id=410868#c8
|
||||||
// Must not leave `lastError` unchecked.
|
// Must not leave `lastError` unchecked.
|
||||||
vAPI.resetLastError = function() {
|
vAPI.resetLastError = function() {
|
||||||
void chrome.runtime.lastError;
|
void browser.runtime.lastError;
|
||||||
};
|
};
|
||||||
|
|
||||||
vAPI.supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet');
|
vAPI.supportsUserStylesheets = vAPI.webextFlavor.soup.has('user_stylesheet');
|
||||||
|
@ -109,7 +109,7 @@ vAPI.storage = webext.storage.local;
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
// https://github.com/gorhill/uMatrix/issues/234
|
// https://github.com/gorhill/uMatrix/issues/234
|
||||||
// https://developer.chrome.com/extensions/privacy#property-network
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/privacy/network
|
||||||
|
|
||||||
// 2015-08-12: Wrapped Chrome API in try-catch statements. I had a fluke
|
// 2015-08-12: Wrapped Chrome API in try-catch statements. I had a fluke
|
||||||
// event in which it appeared Chrome 46 decided to restart uBlock (for
|
// event in which it appeared Chrome 46 decided to restart uBlock (for
|
||||||
|
@ -123,8 +123,8 @@ vAPI.storage = webext.storage.local;
|
||||||
// values.
|
// values.
|
||||||
|
|
||||||
vAPI.browserSettings = (( ) => {
|
vAPI.browserSettings = (( ) => {
|
||||||
// Not all platforms support `chrome.privacy`.
|
// Not all platforms support `browser.privacy`.
|
||||||
if ( chrome.privacy instanceof Object === false ) { return; }
|
if ( browser.privacy instanceof Object === false ) { return; }
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// Whether the WebRTC-related privacy API is crashy is an open question
|
// Whether the WebRTC-related privacy API is crashy is an open question
|
||||||
|
@ -181,19 +181,19 @@ vAPI.browserSettings = (( ) => {
|
||||||
// crash.
|
// crash.
|
||||||
if ( this.webRTCSupported !== true ) { return; }
|
if ( this.webRTCSupported !== true ) { return; }
|
||||||
|
|
||||||
const cp = chrome.privacy;
|
const bp = browser.privacy;
|
||||||
const cpn = cp.network;
|
const bpn = bp.network;
|
||||||
|
|
||||||
// Older version of Chromium do not support this setting, and is
|
// Older version of Chromium do not support this setting, and is
|
||||||
// marked as "deprecated" since Chromium 48.
|
// marked as "deprecated" since Chromium 48.
|
||||||
if ( typeof cpn.webRTCMultipleRoutesEnabled === 'object' ) {
|
if ( typeof bpn.webRTCMultipleRoutesEnabled === 'object' ) {
|
||||||
try {
|
try {
|
||||||
if ( setting ) {
|
if ( setting ) {
|
||||||
cpn.webRTCMultipleRoutesEnabled.clear({
|
bpn.webRTCMultipleRoutesEnabled.clear({
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
} else {
|
} else {
|
||||||
cpn.webRTCMultipleRoutesEnabled.set({
|
bpn.webRTCMultipleRoutesEnabled.set({
|
||||||
value: false,
|
value: false,
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
|
@ -204,10 +204,10 @@ vAPI.browserSettings = (( ) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This setting became available in Chromium 48.
|
// This setting became available in Chromium 48.
|
||||||
if ( typeof cpn.webRTCIPHandlingPolicy === 'object' ) {
|
if ( typeof bpn.webRTCIPHandlingPolicy === 'object' ) {
|
||||||
try {
|
try {
|
||||||
if ( setting ) {
|
if ( setting ) {
|
||||||
cpn.webRTCIPHandlingPolicy.clear({
|
bpn.webRTCIPHandlingPolicy.clear({
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
} else {
|
} else {
|
||||||
|
@ -216,7 +216,7 @@ vAPI.browserSettings = (( ) => {
|
||||||
// https://github.com/gorhill/uBlock/issues/3009
|
// https://github.com/gorhill/uBlock/issues/3009
|
||||||
// Firefox currently works differently, use
|
// Firefox currently works differently, use
|
||||||
// `default_public_interface_only` for now.
|
// `default_public_interface_only` for now.
|
||||||
cpn.webRTCIPHandlingPolicy.set({
|
bpn.webRTCIPHandlingPolicy.set({
|
||||||
value: vAPI.webextFlavor.soup.has('chromium')
|
value: vAPI.webextFlavor.soup.has('chromium')
|
||||||
? 'disable_non_proxied_udp'
|
? 'disable_non_proxied_udp'
|
||||||
: 'default_public_interface_only',
|
: 'default_public_interface_only',
|
||||||
|
@ -239,11 +239,11 @@ vAPI.browserSettings = (( ) => {
|
||||||
const enabled = !!details[setting];
|
const enabled = !!details[setting];
|
||||||
try {
|
try {
|
||||||
if ( enabled ) {
|
if ( enabled ) {
|
||||||
chrome.privacy.network.networkPredictionEnabled.clear({
|
browser.privacy.network.networkPredictionEnabled.clear({
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
} else {
|
} else {
|
||||||
chrome.privacy.network.networkPredictionEnabled.set({
|
browser.privacy.network.networkPredictionEnabled.set({
|
||||||
value: false,
|
value: false,
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
|
@ -259,11 +259,11 @@ vAPI.browserSettings = (( ) => {
|
||||||
case 'hyperlinkAuditing':
|
case 'hyperlinkAuditing':
|
||||||
try {
|
try {
|
||||||
if ( !!details[setting] ) {
|
if ( !!details[setting] ) {
|
||||||
chrome.privacy.websites.hyperlinkAuditingEnabled.clear({
|
browser.privacy.websites.hyperlinkAuditingEnabled.clear({
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
} else {
|
} else {
|
||||||
chrome.privacy.websites.hyperlinkAuditingEnabled.set({
|
browser.privacy.websites.hyperlinkAuditingEnabled.set({
|
||||||
value: false,
|
value: false,
|
||||||
scope: 'regular'
|
scope: 'regular'
|
||||||
}, vAPI.resetLastError);
|
}, vAPI.resetLastError);
|
||||||
|
@ -302,8 +302,8 @@ const toTabId = function(tabId) {
|
||||||
: 0;
|
: 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// https://developer.chrome.com/extensions/webNavigation
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/webNavigation
|
||||||
// https://developer.chrome.com/extensions/tabs
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs
|
||||||
|
|
||||||
vAPI.Tabs = class {
|
vAPI.Tabs = class {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -546,10 +546,9 @@ vAPI.Tabs = class {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.chrome.com/extensions/tabs#method-query
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/query#Parameters
|
||||||
// "Note that fragment identifiers are not matched."
|
// "Note that fragment identifiers are not matched."
|
||||||
// It's a lie, fragment identifiers ARE matched. So we need to remove
|
// Fragment identifiers ARE matched -- we need to remove the fragment.
|
||||||
// the fragment.
|
|
||||||
const pos = targetURL.indexOf('#');
|
const pos = targetURL.indexOf('#');
|
||||||
const targetURLWithoutHash = pos === -1
|
const targetURLWithoutHash = pos === -1
|
||||||
? targetURL
|
? targetURL
|
||||||
|
@ -706,7 +705,7 @@ if ( browser.windows instanceof Object ) {
|
||||||
// Ensure ImageData for toolbar icon is valid before use.
|
// Ensure ImageData for toolbar icon is valid before use.
|
||||||
|
|
||||||
vAPI.setIcon = (( ) => {
|
vAPI.setIcon = (( ) => {
|
||||||
const browserAction = chrome.browserAction;
|
const browserAction = browser.browserAction;
|
||||||
const titleTemplate =
|
const titleTemplate =
|
||||||
browser.runtime.getManifest().browser_action.default_title +
|
browser.runtime.getManifest().browser_action.default_title +
|
||||||
' ({badge})';
|
' ({badge})';
|
||||||
|
@ -841,7 +840,7 @@ vAPI.setIcon = (( ) => {
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
chrome.browserAction.onClicked.addListener(function(tab) {
|
browser.browserAction.onClicked.addListener(function(tab) {
|
||||||
vAPI.tabs.open({
|
vAPI.tabs.open({
|
||||||
select: true,
|
select: true,
|
||||||
url: 'popup.html?tabId=' + tab.id + '&responsive=1'
|
url: 'popup.html?tabId=' + tab.id + '&responsive=1'
|
||||||
|
@ -1245,11 +1244,11 @@ vAPI.Net = class {
|
||||||
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/contextMenus#Browser_compatibility
|
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/contextMenus#Browser_compatibility
|
||||||
// Firefox for Android does no support browser.contextMenus.
|
// Firefox for Android does no support browser.contextMenus.
|
||||||
|
|
||||||
vAPI.contextMenu = chrome.contextMenus && {
|
vAPI.contextMenu = browser.contextMenus && {
|
||||||
_callback: null,
|
_callback: null,
|
||||||
_entries: [],
|
_entries: [],
|
||||||
_createEntry: function(entry) {
|
_createEntry: function(entry) {
|
||||||
chrome.contextMenus.create(
|
browser.contextMenus.create(
|
||||||
JSON.parse(JSON.stringify(entry)),
|
JSON.parse(JSON.stringify(entry)),
|
||||||
vAPI.resetLastError
|
vAPI.resetLastError
|
||||||
);
|
);
|
||||||
|
@ -1263,12 +1262,12 @@ vAPI.contextMenu = chrome.contextMenus && {
|
||||||
const newEntry = entries[i];
|
const newEntry = entries[i];
|
||||||
if ( oldEntryId && newEntry ) {
|
if ( oldEntryId && newEntry ) {
|
||||||
if ( newEntry.id !== oldEntryId ) {
|
if ( newEntry.id !== oldEntryId ) {
|
||||||
chrome.contextMenus.remove(oldEntryId);
|
browser.contextMenus.remove(oldEntryId);
|
||||||
this._createEntry(newEntry);
|
this._createEntry(newEntry);
|
||||||
this._entries[i] = newEntry.id;
|
this._entries[i] = newEntry.id;
|
||||||
}
|
}
|
||||||
} else if ( oldEntryId && !newEntry ) {
|
} else if ( oldEntryId && !newEntry ) {
|
||||||
chrome.contextMenus.remove(oldEntryId);
|
browser.contextMenus.remove(oldEntryId);
|
||||||
} else if ( !oldEntryId && newEntry ) {
|
} else if ( !oldEntryId && newEntry ) {
|
||||||
this._createEntry(newEntry);
|
this._createEntry(newEntry);
|
||||||
this._entries[i] = newEntry.id;
|
this._entries[i] = newEntry.id;
|
||||||
|
@ -1280,10 +1279,10 @@ vAPI.contextMenu = chrome.contextMenus && {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ( n !== 0 && callback !== null ) {
|
if ( n !== 0 && callback !== null ) {
|
||||||
chrome.contextMenus.onClicked.addListener(callback);
|
browser.contextMenus.onClicked.addListener(callback);
|
||||||
this._callback = callback;
|
this._callback = callback;
|
||||||
} else if ( n === 0 && this._callback !== null ) {
|
} else if ( n === 0 && this._callback !== null ) {
|
||||||
chrome.contextMenus.onClicked.removeListener(this._callback);
|
browser.contextMenus.onClicked.removeListener(this._callback);
|
||||||
this._callback = null;
|
this._callback = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1292,7 +1291,7 @@ vAPI.contextMenu = chrome.contextMenus && {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.commands = chrome.commands;
|
vAPI.commands = browser.commands;
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
@ -1334,26 +1333,34 @@ vAPI.adminStorage = (( ) => {
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.cloud = (function() {
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/sync
|
||||||
// Not all platforms support `chrome.storage.sync`.
|
|
||||||
if ( chrome.storage.sync instanceof Object === false ) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let chunkCountPerFetch = 16; // Must be a power of 2
|
vAPI.cloud = (( ) => {
|
||||||
|
// Not all platforms support `webext.storage.sync`.
|
||||||
|
if ( webext.storage.sync instanceof Object === false ) { return; }
|
||||||
|
|
||||||
// Mind chrome.storage.sync.MAX_ITEMS (512 at time of writing)
|
// Currently, only Chromium supports the following constants -- these
|
||||||
let maxChunkCountPerItem = Math.floor(512 * 0.75) & ~(chunkCountPerFetch - 1);
|
// values will be assumed for platforms which do not define them.
|
||||||
|
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/sync
|
||||||
|
// > You can store up to 100KB of data using this API
|
||||||
|
const MAX_ITEMS =
|
||||||
|
webext.storage.sync.MAX_ITEMS || 512;
|
||||||
|
const QUOTA_BYTES =
|
||||||
|
webext.storage.sync.QUOTA_BYTES || 102400;
|
||||||
|
const QUOTA_BYTES_PER_ITEM =
|
||||||
|
webext.storage.sync.QUOTA_BYTES_PER_ITEM || 8192;
|
||||||
|
|
||||||
|
const chunkCountPerFetch = 16; // Must be a power of 2
|
||||||
|
const maxChunkCountPerItem = Math.floor(MAX_ITEMS * 0.75) & ~(chunkCountPerFetch - 1);
|
||||||
|
|
||||||
// Mind chrome.storage.sync.QUOTA_BYTES_PER_ITEM (8192 at time of writing)
|
|
||||||
// https://github.com/gorhill/uBlock/issues/3006
|
// https://github.com/gorhill/uBlock/issues/3006
|
||||||
// For Firefox, we will use a lower ratio to allow for more overhead for
|
// For Firefox, we will use a lower ratio to allow for more overhead for
|
||||||
// the infrastructure. Unfortunately this leads to less usable space for
|
// the infrastructure. Unfortunately this leads to less usable space for
|
||||||
// actual data, but all of this is provided for free by browser vendors,
|
// actual data, but all of this is provided for free by browser vendors,
|
||||||
// so we need to accept and deal with these limitations.
|
// so we need to accept and deal with these limitations.
|
||||||
let evalMaxChunkSize = function() {
|
const evalMaxChunkSize = function() {
|
||||||
return Math.floor(
|
return Math.floor(
|
||||||
(chrome.storage.sync.QUOTA_BYTES_PER_ITEM || 8192) *
|
QUOTA_BYTES_PER_ITEM *
|
||||||
(vAPI.webextFlavor.soup.has('firefox') ? 0.6 : 0.75)
|
(vAPI.webextFlavor.soup.has('firefox') ? 0.6 : 0.75)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1366,13 +1373,9 @@ vAPI.cloud = (function() {
|
||||||
maxChunkSize = evalMaxChunkSize();
|
maxChunkSize = evalMaxChunkSize();
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
|
||||||
// Mind chrome.storage.sync.QUOTA_BYTES (128 kB at time of writing)
|
const maxStorageSize = QUOTA_BYTES;
|
||||||
// Firefox:
|
|
||||||
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/storage/sync
|
|
||||||
// > You can store up to 100KB of data using this API/
|
|
||||||
let maxStorageSize = chrome.storage.sync.QUOTA_BYTES || 102400;
|
|
||||||
|
|
||||||
let options = {
|
const options = {
|
||||||
defaultDeviceName: window.navigator.platform,
|
defaultDeviceName: window.navigator.platform,
|
||||||
deviceName: vAPI.localStorage.getItem('deviceName') || ''
|
deviceName: vAPI.localStorage.getItem('deviceName') || ''
|
||||||
};
|
};
|
||||||
|
@ -1384,34 +1387,32 @@ vAPI.cloud = (function() {
|
||||||
// good thing given chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_MINUTE
|
// good thing given chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_MINUTE
|
||||||
// and chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_HOUR.
|
// and chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_HOUR.
|
||||||
|
|
||||||
let getCoarseChunkCount = function(dataKey, callback) {
|
const getCoarseChunkCount = async function(dataKey) {
|
||||||
let bin = {};
|
const keys = {};
|
||||||
for ( let i = 0; i < maxChunkCountPerItem; i += 16 ) {
|
for ( let i = 0; i < maxChunkCountPerItem; i += 16 ) {
|
||||||
bin[dataKey + i.toString()] = '';
|
keys[dataKey + i.toString()] = '';
|
||||||
}
|
}
|
||||||
|
let bin;
|
||||||
chrome.storage.sync.get(bin, function(bin) {
|
try {
|
||||||
if ( chrome.runtime.lastError ) {
|
bin = await webext.storage.sync.get(keys);
|
||||||
return callback(0, chrome.runtime.lastError.message);
|
} catch (reason) {
|
||||||
}
|
return reason;
|
||||||
|
}
|
||||||
let chunkCount = 0;
|
let chunkCount = 0;
|
||||||
for ( let i = 0; i < maxChunkCountPerItem; i += 16 ) {
|
for ( let i = 0; i < maxChunkCountPerItem; i += 16 ) {
|
||||||
if ( bin[dataKey + i.toString()] === '' ) { break; }
|
if ( bin[dataKey + i.toString()] === '' ) { break; }
|
||||||
chunkCount = i + 16;
|
chunkCount = i + 16;
|
||||||
}
|
}
|
||||||
|
return chunkCount;
|
||||||
callback(chunkCount);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let deleteChunks = function(dataKey, start) {
|
const deleteChunks = function(dataKey, start) {
|
||||||
let keys = [];
|
const keys = [];
|
||||||
|
|
||||||
// No point in deleting more than:
|
// No point in deleting more than:
|
||||||
// - The max number of chunks per item
|
// - The max number of chunks per item
|
||||||
// - The max number of chunks per storage limit
|
// - The max number of chunks per storage limit
|
||||||
let n = Math.min(
|
const n = Math.min(
|
||||||
maxChunkCountPerItem,
|
maxChunkCountPerItem,
|
||||||
Math.ceil(maxStorageSize / maxChunkSize)
|
Math.ceil(maxStorageSize / maxChunkSize)
|
||||||
);
|
);
|
||||||
|
@ -1419,14 +1420,11 @@ vAPI.cloud = (function() {
|
||||||
keys.push(dataKey + i.toString());
|
keys.push(dataKey + i.toString());
|
||||||
}
|
}
|
||||||
if ( keys.length !== 0 ) {
|
if ( keys.length !== 0 ) {
|
||||||
chrome.storage.sync.remove(keys);
|
webext.storage.sync.remove(keys);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let start = function(/* dataKeys */) {
|
const push = async function(dataKey, data) {
|
||||||
};
|
|
||||||
|
|
||||||
let push = function(dataKey, data, callback) {
|
|
||||||
|
|
||||||
let bin = {
|
let bin = {
|
||||||
'source': options.deviceName || options.defaultDeviceName,
|
'source': options.deviceName || options.defaultDeviceName,
|
||||||
|
@ -1435,7 +1433,7 @@ vAPI.cloud = (function() {
|
||||||
'size': 0
|
'size': 0
|
||||||
};
|
};
|
||||||
bin.size = JSON.stringify(bin).length;
|
bin.size = JSON.stringify(bin).length;
|
||||||
let item = JSON.stringify(bin);
|
const item = JSON.stringify(bin);
|
||||||
|
|
||||||
// Chunkify taking into account QUOTA_BYTES_PER_ITEM:
|
// Chunkify taking into account QUOTA_BYTES_PER_ITEM:
|
||||||
// https://developer.chrome.com/extensions/storage#property-sync
|
// https://developer.chrome.com/extensions/storage#property-sync
|
||||||
|
@ -1449,84 +1447,77 @@ vAPI.cloud = (function() {
|
||||||
}
|
}
|
||||||
bin[dataKey + chunkCount.toString()] = ''; // Sentinel
|
bin[dataKey + chunkCount.toString()] = ''; // Sentinel
|
||||||
|
|
||||||
chrome.storage.sync.set(bin, function() {
|
let result;
|
||||||
let errorStr;
|
let errorStr;
|
||||||
if ( chrome.runtime.lastError ) {
|
try {
|
||||||
errorStr = chrome.runtime.lastError.message;
|
result = await webext.storage.sync.set(bin);
|
||||||
// https://github.com/gorhill/uBlock/issues/3006#issuecomment-332597677
|
} catch (reason) {
|
||||||
// - Delete all that was pushed in case of failure.
|
errorStr = reason;
|
||||||
// - It's unknown whether such issue applies only to Firefox:
|
}
|
||||||
// until such cases are reported for other browsers, we will
|
|
||||||
// reset the (now corrupted) content of the cloud storage
|
|
||||||
// only on Firefox.
|
|
||||||
if ( vAPI.webextFlavor.soup.has('firefox') ) {
|
|
||||||
chunkCount = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
callback(errorStr);
|
|
||||||
|
|
||||||
// Remove potentially unused trailing chunks
|
// https://github.com/gorhill/uBlock/issues/3006#issuecomment-332597677
|
||||||
deleteChunks(dataKey, chunkCount);
|
// - Delete all that was pushed in case of failure.
|
||||||
});
|
// - It's unknown whether such issue applies only to Firefox:
|
||||||
|
// until such cases are reported for other browsers, we will
|
||||||
|
// reset the (now corrupted) content of the cloud storage
|
||||||
|
// only on Firefox.
|
||||||
|
if ( errorStr !== undefined && vAPI.webextFlavor.soup.has('firefox') ) {
|
||||||
|
chunkCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove potentially unused trailing chunks
|
||||||
|
deleteChunks(dataKey, chunkCount);
|
||||||
|
|
||||||
|
return errorStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
let pull = function(dataKey, callback) {
|
const pull = async function(dataKey) {
|
||||||
|
|
||||||
let assembleChunks = function(bin) {
|
const result = await getCoarseChunkCount(dataKey);
|
||||||
if ( chrome.runtime.lastError ) {
|
if ( typeof result !== 'number' ) {
|
||||||
callback(null, chrome.runtime.lastError.message);
|
return result;
|
||||||
return;
|
}
|
||||||
}
|
const chunkKeys = {};
|
||||||
|
for ( let i = 0; i < result; i++ ) {
|
||||||
|
chunkKeys[dataKey + i.toString()] = '';
|
||||||
|
}
|
||||||
|
|
||||||
// Assemble chunks into a single string.
|
let bin;
|
||||||
// https://www.reddit.com/r/uMatrix/comments/8lc9ia/my_rules_tab_hangs_with_cloud_storage_support/
|
try {
|
||||||
// Explicit sentinel is not necessarily present: this can
|
bin = await webext.storage.sync.get(chunkKeys);
|
||||||
// happen when the number of chunks is a multiple of
|
} catch (reason) {
|
||||||
// chunkCountPerFetch. Hence why we must also test against
|
return reason;
|
||||||
// undefined.
|
}
|
||||||
let json = [], jsonSlice;
|
|
||||||
let i = 0;
|
|
||||||
for (;;) {
|
|
||||||
jsonSlice = bin[dataKey + i.toString()];
|
|
||||||
if ( jsonSlice === '' || jsonSlice === undefined ) { break; }
|
|
||||||
json.push(jsonSlice);
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let entry = null;
|
// Assemble chunks into a single string.
|
||||||
try {
|
// https://www.reddit.com/r/uMatrix/comments/8lc9ia/my_rules_tab_hangs_with_cloud_storage_support/
|
||||||
entry = JSON.parse(json.join(''));
|
// Explicit sentinel is not necessarily present: this can
|
||||||
} catch(ex) {
|
// happen when the number of chunks is a multiple of
|
||||||
}
|
// chunkCountPerFetch. Hence why we must also test against
|
||||||
callback(entry);
|
// undefined.
|
||||||
};
|
let json = [], jsonSlice;
|
||||||
|
let i = 0;
|
||||||
let fetchChunks = function(coarseCount, errorStr) {
|
for (;;) {
|
||||||
if ( coarseCount === 0 || typeof errorStr === 'string' ) {
|
jsonSlice = bin[dataKey + i.toString()];
|
||||||
callback(null, errorStr);
|
if ( jsonSlice === '' || jsonSlice === undefined ) { break; }
|
||||||
return;
|
json.push(jsonSlice);
|
||||||
}
|
i += 1;
|
||||||
|
}
|
||||||
let bin = {};
|
let entry = null;
|
||||||
for ( let i = 0; i < coarseCount; i++ ) {
|
try {
|
||||||
bin[dataKey + i.toString()] = '';
|
entry = JSON.parse(json.join(''));
|
||||||
}
|
} catch(ex) {
|
||||||
|
}
|
||||||
chrome.storage.sync.get(bin, assembleChunks);
|
return entry;
|
||||||
};
|
|
||||||
|
|
||||||
getCoarseChunkCount(dataKey, fetchChunks);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let getOptions = function(callback) {
|
const getOptions = function(callback) {
|
||||||
if ( typeof callback !== 'function' ) { return; }
|
if ( typeof callback !== 'function' ) { return; }
|
||||||
callback(options);
|
callback(options);
|
||||||
};
|
};
|
||||||
|
|
||||||
let setOptions = function(details, callback) {
|
const setOptions = function(details, callback) {
|
||||||
if ( typeof details !== 'object' || details === null ) {
|
if ( typeof details !== 'object' || details === null ) { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( typeof details.deviceName === 'string' ) {
|
if ( typeof details.deviceName === 'string' ) {
|
||||||
vAPI.localStorage.setItem('deviceName', details.deviceName);
|
vAPI.localStorage.setItem('deviceName', details.deviceName);
|
||||||
|
@ -1536,13 +1527,7 @@ vAPI.cloud = (function() {
|
||||||
getOptions(callback);
|
getOptions(callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return { push, pull, getOptions, setOptions };
|
||||||
start: start,
|
|
||||||
push: push,
|
|
||||||
pull: pull,
|
|
||||||
getOptions: getOptions,
|
|
||||||
setOptions: setOptions
|
|
||||||
};
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
|
@ -83,28 +83,113 @@ vAPI.messaging = {
|
||||||
msgIdGenerator: 1,
|
msgIdGenerator: 1,
|
||||||
shuttingDown: false,
|
shuttingDown: false,
|
||||||
|
|
||||||
Connection: function(handler, details) {
|
Connection: class {
|
||||||
this.messaging = vAPI.messaging;
|
constructor(handler, details) {
|
||||||
this.handler = handler;
|
this.messaging = vAPI.messaging;
|
||||||
this.id = details.id;
|
this.handler = handler;
|
||||||
this.to = details.to;
|
this.id = details.id;
|
||||||
this.toToken = details.toToken;
|
this.to = details.to;
|
||||||
this.from = details.from;
|
this.toToken = details.toToken;
|
||||||
this.fromToken = details.fromToken;
|
this.from = details.from;
|
||||||
this.checkTimer = undefined;
|
this.fromToken = details.fromToken;
|
||||||
// On Firefox it appears ports are not automatically disconnected
|
this.checkTimer = undefined;
|
||||||
// when navigating to another page.
|
// On Firefox it appears ports are not automatically disconnected
|
||||||
const ctor = this.messaging.Connection;
|
// when navigating to another page.
|
||||||
if ( ctor.pagehide !== undefined ) { return; }
|
const ctor = this.messaging.Connection;
|
||||||
ctor.pagehide = ( ) => {
|
if ( ctor.pagehide !== undefined ) { return; }
|
||||||
for ( const connection of this.messaging.connections.values() ) {
|
ctor.pagehide = ( ) => {
|
||||||
connection.disconnect();
|
for ( const connection of this.messaging.connections.values() ) {
|
||||||
connection.handler(
|
connection.disconnect();
|
||||||
connection.toDetails('connectionBroken')
|
connection.handler(
|
||||||
);
|
connection.toDetails('connectionBroken')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener('pagehide', ctor.pagehide);
|
||||||
|
}
|
||||||
|
toDetails(what, payload) {
|
||||||
|
return {
|
||||||
|
what: what,
|
||||||
|
id: this.id,
|
||||||
|
from: this.from,
|
||||||
|
fromToken: this.fromToken,
|
||||||
|
to: this.to,
|
||||||
|
toToken: this.toToken,
|
||||||
|
payload: payload
|
||||||
|
};
|
||||||
|
}
|
||||||
|
disconnect() {
|
||||||
|
if ( this.checkTimer !== undefined ) {
|
||||||
|
clearTimeout(this.checkTimer);
|
||||||
|
this.checkTimer = undefined;
|
||||||
}
|
}
|
||||||
};
|
this.messaging.connections.delete(this.id);
|
||||||
window.addEventListener('pagehide', ctor.pagehide);
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
port.postMessage({
|
||||||
|
channelName: 'vapi',
|
||||||
|
msg: this.toDetails('connectionBroken')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checkAsync() {
|
||||||
|
if ( this.checkTimer !== undefined ) {
|
||||||
|
clearTimeout(this.checkTimer);
|
||||||
|
}
|
||||||
|
this.checkTimer = vAPI.setTimeout(
|
||||||
|
( ) => { this.check(); },
|
||||||
|
499
|
||||||
|
);
|
||||||
|
}
|
||||||
|
check() {
|
||||||
|
this.checkTimer = undefined;
|
||||||
|
if ( this.messaging.connections.has(this.id) === false ) { return; }
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
port.postMessage({
|
||||||
|
channelName: 'vapi',
|
||||||
|
msg: this.toDetails('connectionCheck')
|
||||||
|
});
|
||||||
|
this.checkAsync();
|
||||||
|
}
|
||||||
|
receive(details) {
|
||||||
|
switch ( details.what ) {
|
||||||
|
case 'connectionAccepted':
|
||||||
|
this.toToken = details.toToken;
|
||||||
|
this.handler(details);
|
||||||
|
this.checkAsync();
|
||||||
|
break;
|
||||||
|
case 'connectionBroken':
|
||||||
|
this.messaging.connections.delete(this.id);
|
||||||
|
this.handler(details);
|
||||||
|
break;
|
||||||
|
case 'connectionMessage':
|
||||||
|
this.handler(details);
|
||||||
|
this.checkAsync();
|
||||||
|
break;
|
||||||
|
case 'connectionCheck':
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
if ( this.messaging.connections.has(this.id) ) {
|
||||||
|
this.checkAsync();
|
||||||
|
} else {
|
||||||
|
details.what = 'connectionBroken';
|
||||||
|
port.postMessage({ channelName: 'vapi', msg: details });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'connectionRefused':
|
||||||
|
this.messaging.connections.delete(this.id);
|
||||||
|
this.handler(details);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send(payload) {
|
||||||
|
const port = this.messaging.getPort();
|
||||||
|
if ( port === null ) { return; }
|
||||||
|
port.postMessage({
|
||||||
|
channelName: 'vapi',
|
||||||
|
msg: this.toDetails('connectionMessage', payload)
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
shutdown: function() {
|
shutdown: function() {
|
||||||
|
@ -125,7 +210,7 @@ vAPI.messaging = {
|
||||||
disconnectListenerBound: null,
|
disconnectListenerBound: null,
|
||||||
|
|
||||||
messageListener: function(details) {
|
messageListener: function(details) {
|
||||||
if ( !details ) { return; }
|
if ( details instanceof Object === false ) { return; }
|
||||||
|
|
||||||
// Sent to all channels
|
// Sent to all channels
|
||||||
if ( details.broadcast ) {
|
if ( details.broadcast ) {
|
||||||
|
@ -357,94 +442,6 @@ vAPI.messaging = {
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
vAPI.messaging.Connection.prototype = {
|
|
||||||
toDetails: function(what, payload) {
|
|
||||||
return {
|
|
||||||
what: what,
|
|
||||||
id: this.id,
|
|
||||||
from: this.from,
|
|
||||||
fromToken: this.fromToken,
|
|
||||||
to: this.to,
|
|
||||||
toToken: this.toToken,
|
|
||||||
payload: payload
|
|
||||||
};
|
|
||||||
},
|
|
||||||
disconnect: function() {
|
|
||||||
if ( this.checkTimer !== undefined ) {
|
|
||||||
clearTimeout(this.checkTimer);
|
|
||||||
this.checkTimer = undefined;
|
|
||||||
}
|
|
||||||
this.messaging.connections.delete(this.id);
|
|
||||||
const port = this.messaging.getPort();
|
|
||||||
if ( port === null ) { return; }
|
|
||||||
port.postMessage({
|
|
||||||
channelName: 'vapi',
|
|
||||||
msg: this.toDetails('connectionBroken')
|
|
||||||
});
|
|
||||||
},
|
|
||||||
checkAsync: function() {
|
|
||||||
if ( this.checkTimer !== undefined ) {
|
|
||||||
clearTimeout(this.checkTimer);
|
|
||||||
}
|
|
||||||
this.checkTimer = vAPI.setTimeout(
|
|
||||||
( ) => { this.check(); },
|
|
||||||
499
|
|
||||||
);
|
|
||||||
},
|
|
||||||
check: function() {
|
|
||||||
this.checkTimer = undefined;
|
|
||||||
if ( this.messaging.connections.has(this.id) === false ) { return; }
|
|
||||||
const port = this.messaging.getPort();
|
|
||||||
if ( port === null ) { return; }
|
|
||||||
port.postMessage({
|
|
||||||
channelName: 'vapi',
|
|
||||||
msg: this.toDetails('connectionCheck')
|
|
||||||
});
|
|
||||||
this.checkAsync();
|
|
||||||
},
|
|
||||||
receive: function(details) {
|
|
||||||
switch ( details.what ) {
|
|
||||||
case 'connectionAccepted':
|
|
||||||
this.toToken = details.toToken;
|
|
||||||
this.handler(details);
|
|
||||||
this.checkAsync();
|
|
||||||
break;
|
|
||||||
case 'connectionBroken':
|
|
||||||
this.messaging.connections.delete(this.id);
|
|
||||||
this.handler(details);
|
|
||||||
break;
|
|
||||||
case 'connectionMessage':
|
|
||||||
this.handler(details);
|
|
||||||
this.checkAsync();
|
|
||||||
break;
|
|
||||||
case 'connectionCheck':
|
|
||||||
const port = this.messaging.getPort();
|
|
||||||
if ( port === null ) { return; }
|
|
||||||
if ( this.messaging.connections.has(this.id) ) {
|
|
||||||
this.checkAsync();
|
|
||||||
} else {
|
|
||||||
details.what = 'connectionBroken';
|
|
||||||
port.postMessage({ channelName: 'vapi', msg: details });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'connectionRefused':
|
|
||||||
this.messaging.connections.delete(this.id);
|
|
||||||
this.handler(details);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
send: function(payload) {
|
|
||||||
const port = this.messaging.getPort();
|
|
||||||
if ( port === null ) { return; }
|
|
||||||
port.postMessage({
|
|
||||||
channelName: 'vapi',
|
|
||||||
msg: this.toDetails('connectionMessage', payload)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
|
|
||||||
vAPI.shutdown.add(function() {
|
vAPI.shutdown.add(function() {
|
||||||
vAPI.messaging.shutdown();
|
vAPI.messaging.shutdown();
|
||||||
window.vAPI = undefined;
|
window.vAPI = undefined;
|
||||||
|
|
|
@ -25,14 +25,16 @@
|
||||||
// the promisification of uBO progress.
|
// the promisification of uBO progress.
|
||||||
|
|
||||||
const webext = { // jshint ignore:line
|
const webext = { // jshint ignore:line
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage
|
||||||
storage: {
|
storage: {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/local
|
||||||
local: {
|
local: {
|
||||||
clear: function() {
|
clear: function() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
chrome.storage.local.clear(( ) => {
|
chrome.storage.local.clear(( ) => {
|
||||||
const lastError = chrome.runtime.lastError;
|
const lastError = chrome.runtime.lastError;
|
||||||
if ( lastError instanceof Object ) {
|
if ( lastError instanceof Object ) {
|
||||||
return reject(lastError);
|
return reject(lastError.message);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -43,7 +45,7 @@ const webext = { // jshint ignore:line
|
||||||
chrome.storage.local.get(...arguments, result => {
|
chrome.storage.local.get(...arguments, result => {
|
||||||
const lastError = chrome.runtime.lastError;
|
const lastError = chrome.runtime.lastError;
|
||||||
if ( lastError instanceof Object ) {
|
if ( lastError instanceof Object ) {
|
||||||
return reject(lastError);
|
return reject(lastError.message);
|
||||||
}
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
|
@ -54,7 +56,7 @@ const webext = { // jshint ignore:line
|
||||||
chrome.storage.local.getBytesInUse(...arguments, result => {
|
chrome.storage.local.getBytesInUse(...arguments, result => {
|
||||||
const lastError = chrome.runtime.lastError;
|
const lastError = chrome.runtime.lastError;
|
||||||
if ( lastError instanceof Object ) {
|
if ( lastError instanceof Object ) {
|
||||||
return reject(lastError);
|
return reject(lastError.message);
|
||||||
}
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
|
@ -65,7 +67,7 @@ const webext = { // jshint ignore:line
|
||||||
chrome.storage.local.remove(...arguments, ( ) => {
|
chrome.storage.local.remove(...arguments, ( ) => {
|
||||||
const lastError = chrome.runtime.lastError;
|
const lastError = chrome.runtime.lastError;
|
||||||
if ( lastError instanceof Object ) {
|
if ( lastError instanceof Object ) {
|
||||||
return reject(lastError);
|
return reject(lastError.message);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -76,7 +78,7 @@ const webext = { // jshint ignore:line
|
||||||
chrome.storage.local.set(...arguments, ( ) => {
|
chrome.storage.local.set(...arguments, ( ) => {
|
||||||
const lastError = chrome.runtime.lastError;
|
const lastError = chrome.runtime.lastError;
|
||||||
if ( lastError instanceof Object ) {
|
if ( lastError instanceof Object ) {
|
||||||
return reject(lastError);
|
return reject(lastError.message);
|
||||||
}
|
}
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
@ -84,7 +86,7 @@ const webext = { // jshint ignore:line
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs
|
||||||
tabs: {
|
tabs: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
@ -127,7 +129,7 @@ const webext = { // jshint ignore:line
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/windows
|
||||||
windows: {
|
windows: {
|
||||||
get: function() {
|
get: function() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
@ -156,6 +158,73 @@ const webext = { // jshint ignore:line
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/sync
|
||||||
|
if ( chrome.storage.sync instanceof Object ) {
|
||||||
|
webext.storage.sync = {
|
||||||
|
QUOTA_BYTES: chrome.storage.sync.QUOTA_BYTES,
|
||||||
|
QUOTA_BYTES_PER_ITEM: chrome.storage.sync.QUOTA_BYTES_PER_ITEM,
|
||||||
|
MAX_ITEMS: chrome.storage.sync.MAX_ITEMS,
|
||||||
|
MAX_WRITE_OPERATIONS_PER_HOUR: chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_HOUR,
|
||||||
|
MAX_WRITE_OPERATIONS_PER_MINUTE: chrome.storage.sync.MAX_WRITE_OPERATIONS_PER_MINUTE,
|
||||||
|
|
||||||
|
clear: function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.sync.clear(( ) => {
|
||||||
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if ( lastError instanceof Object ) {
|
||||||
|
return reject(lastError.message);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
get: function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.sync.get(...arguments, result => {
|
||||||
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if ( lastError instanceof Object ) {
|
||||||
|
return reject(lastError.message);
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getBytesInUse: function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.sync.getBytesInUse(...arguments, result => {
|
||||||
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if ( lastError instanceof Object ) {
|
||||||
|
return reject(lastError.message);
|
||||||
|
}
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
remove: function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.sync.remove(...arguments, ( ) => {
|
||||||
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if ( lastError instanceof Object ) {
|
||||||
|
return reject(lastError.message);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
set: function() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
chrome.storage.sync.set(...arguments, ( ) => {
|
||||||
|
const lastError = chrome.runtime.lastError;
|
||||||
|
if ( lastError instanceof Object ) {
|
||||||
|
return reject(lastError.message);
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// https://bugs.chromium.org/p/chromium/issues/detail?id=608854
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=608854
|
||||||
if ( chrome.tabs.removeCSS instanceof Function ) {
|
if ( chrome.tabs.removeCSS instanceof Function ) {
|
||||||
webext.tabs.removeCSS = function() {
|
webext.tabs.removeCSS = function() {
|
||||||
|
@ -168,6 +237,7 @@ if ( chrome.tabs.removeCSS instanceof Function ) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/managed
|
||||||
if ( chrome.storage.managed instanceof Object ) {
|
if ( chrome.storage.managed instanceof Object ) {
|
||||||
webext.storage.managed = {
|
webext.storage.managed = {
|
||||||
get: function() {
|
get: function() {
|
||||||
|
@ -175,7 +245,7 @@ if ( chrome.storage.managed instanceof Object ) {
|
||||||
chrome.storage.local.get(...arguments, result => {
|
chrome.storage.local.get(...arguments, result => {
|
||||||
const lastError = chrome.runtime.lastError;
|
const lastError = chrome.runtime.lastError;
|
||||||
if ( lastError instanceof Object ) {
|
if ( lastError instanceof Object ) {
|
||||||
return reject(lastError);
|
return reject(lastError.message);
|
||||||
}
|
}
|
||||||
resolve(result);
|
resolve(result);
|
||||||
});
|
});
|
||||||
|
|
|
@ -77,7 +77,7 @@ const onMessage = function(request, sender, callback) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'reloadAllFilters':
|
case 'reloadAllFilters':
|
||||||
µb.loadFilterLists();
|
µb.loadFilterLists().then(( ) => { callback(); });
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'scriptlet':
|
case 'scriptlet':
|
||||||
|
@ -752,10 +752,14 @@ const onMessage = function(request, sender, callback) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case 'cloudPull':
|
case 'cloudPull':
|
||||||
return vAPI.cloud.pull(request.datakey, callback);
|
return vAPI.cloud.pull(request.datakey).then(result => {
|
||||||
|
callback(result);
|
||||||
|
});
|
||||||
|
|
||||||
case 'cloudPush':
|
case 'cloudPush':
|
||||||
return vAPI.cloud.push(request.datakey, request.data, callback);
|
return vAPI.cloud.push(request.datakey, request.data).then(result => {
|
||||||
|
callback(result);
|
||||||
|
});
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -318,16 +318,6 @@ initializeTabs();
|
||||||
: 0
|
: 0
|
||||||
);
|
);
|
||||||
|
|
||||||
// vAPI.cloud is optional.
|
|
||||||
if ( µb.cloudStorageSupported ) {
|
|
||||||
vAPI.cloud.start([
|
|
||||||
'tpFiltersPane',
|
|
||||||
'myFiltersPane',
|
|
||||||
'myRulesPane',
|
|
||||||
'whitelistPane'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
µb.contextMenu.update(null);
|
µb.contextMenu.update(null);
|
||||||
|
|
||||||
// https://github.com/uBlockOrigin/uBlock-issues/issues/717
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/717
|
||||||
|
|
Loading…
Reference in New Issue