[Pkg-mozext-commits] [adblock-plus] 75/98: Issue 5050 - Make legacy extension use WebExtensions I/O
David Prévot
taffit at moszumanska.debian.org
Tue Oct 24 01:30:22 UTC 2017
This is an automated email from the git hooks/post-receive script.
taffit pushed a commit to branch master
in repository adblock-plus.
commit 0b5000d06b63ef690f55c7b7834233065247b1c1
Author: Wladimir Palant <trev at adblockplus.org>
Date: Thu Mar 30 14:31:43 2017 +0200
Issue 5050 - Make legacy extension use WebExtensions I/O
---
chrome/content/ui/utils.js | 2 +-
lib/io.js | 363 ++++++++++++--------------------------------
lib/{io.js => legacyIO.js} | 6 +-
lib/prefs.json | 1 -
lib/utils.js | 10 +-
webextension/.eslintrc.json | 7 +
webextension/background.js | 41 +++++
webextension/io.js | 109 +++++++++++++
webextension/manifest.json | 9 ++
9 files changed, 268 insertions(+), 280 deletions(-)
diff --git a/chrome/content/ui/utils.js b/chrome/content/ui/utils.js
index 7e0c371..5f8d515 100644
--- a/chrome/content/ui/utils.js
+++ b/chrome/content/ui/utils.js
@@ -39,7 +39,7 @@ var {Filter, InvalidFilter, CommentFilter, ActiveFilter, RegExpFilter,
ElemHideException, ElemHideEmulationFilter} = require("filterClasses");
var {FilterNotifier} = require("filterNotifier");
var {FilterStorage} = require("filterStorage");
-var {IO} = require("io");
+var {IO} = require("legacyIO");
var {defaultMatcher, Matcher, CombinedMatcher} = require("matcher");
var {Prefs} = require("prefs");
var {RequestNotifier} = require("requestNotifier");
diff --git a/lib/io.js b/lib/io.js
index 4df5f2d..e566264 100644
--- a/lib/io.js
+++ b/lib/io.js
@@ -15,325 +15,160 @@
* along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * @fileOverview Module containing file I/O helpers.
- */
-
-let {Services} = Cu.import("resource://gre/modules/Services.jsm", null);
-let {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm", null);
-let {OS} = Cu.import("resource://gre/modules/osfile.jsm", null);
-let {Task} = Cu.import("resource://gre/modules/Task.jsm", null);
+"use strict";
-let {Prefs} = require("prefs");
+let {IO: LegacyIO} = require("legacyIO");
let {Utils} = require("utils");
-let firstRead = true;
-const BUFFER_SIZE = 0x80000; // 512kB
+let webextension = require("webextension");
+let messageID = 0;
+let messageCallbacks = new Map();
-let IO = exports.IO =
+webextension.then(port =>
{
- /**
- * Retrieves the platform-dependent line break string.
- */
- get lineBreak()
+ port.onMessage.addListener(message =>
{
- let lineBreak = (Services.appinfo.OS == "WINNT" ? "\r\n" : "\n");
- Object.defineProperty(this, "lineBreak", {value: lineBreak});
- return lineBreak;
- },
+ let {id} = message;
+ let callbacks = messageCallbacks.get(id);
+ if (callbacks)
+ {
+ messageCallbacks.delete(id);
- /**
- * Tries to interpret a file path as an absolute path or a path relative to
- * user's profile. Returns a file or null on failure.
- */
- resolveFilePath: function(/**String*/ path) /**nsIFile*/
- {
- if (!path)
- return null;
+ if (message.success)
+ callbacks.resolve(message.result);
+ else
+ callbacks.reject(message.result);
+ }
+ });
+});
- try {
- // Assume an absolute path first
- return new FileUtils.File(path);
- } catch (e) {}
+function callWebExt(method, ...args)
+{
+ return webextension.then(port =>
+ {
+ return new Promise((resolve, reject) =>
+ {
+ let id = ++messageID;
+ messageCallbacks.set(id, {resolve, reject});
+ port.postMessage({id, method, args});
+ });
+ });
+}
- try {
- // Try relative path now
- return FileUtils.getFile("ProfD", path.split("/"));
- } catch (e) {}
+function attachCallback(promise, callback, fallback)
+{
+ promise.then(result =>
+ {
+ callback(null, result);
+ }).catch(error =>
+ {
+ if (fallback && error == "NoSuchFile")
+ fallback();
+ else
+ callback(error);
+ });
+}
- return null;
- },
+exports.IO =
+{
+ resolveFilePath: LegacyIO.resolveFilePath,
/**
* Reads strings from a file asynchronously, calls listener.process() with
* each line read and with a null parameter once the read operation is done.
* The callback will be called when the operation is done.
*/
- readFromFile: function(/**nsIFile*/ file, /**Object*/ listener, /**Function*/ callback)
+ readFromFile(/**nsIFile*/ file, /**Object*/ listener, /**Function*/ callback)
{
- try
- {
- let processing = false;
- let buffer = "";
- let loaded = false;
- let error = null;
-
- let onProgress = function*(data)
+ attachCallback(
+ callWebExt("readFromFile", file.leafName).then(contents =>
{
- let index = (processing ? -1 : Math.max(data.lastIndexOf("\n"), data.lastIndexOf("\r")));
- if (index >= 0)
+ return new Promise((resolve, reject) =>
{
- // Protect against reentrance in case the listener processes events.
- processing = true;
- try
- {
- let oldBuffer = buffer;
- buffer = data.substr(index + 1);
- data = data.substr(0, index + 1);
- let lines = data.split(/[\r\n]+/);
- lines.pop();
- lines[0] = oldBuffer + lines[0];
- for (let i = 0; i < lines.length; i++)
- {
- let promise = listener.process(lines[i]);
- if (promise)
- yield promise;
- }
- }
- finally
- {
- processing = false;
- data = buffer;
- buffer = "";
- yield* onProgress(data);
+ let lineIndex = 0;
- if (loaded)
- {
- loaded = false;
- onSuccess();
- }
-
- if (error)
+ function processBatch()
+ {
+ while (lineIndex < contents.length)
{
- let param = error;
- error = null;
- onError(param);
+ listener.process(contents[lineIndex++]);
+ if (lineIndex % 1000 == 0)
+ {
+ Utils.runAsync(processBatch);
+ return;
+ }
}
- }
- }
- else
- buffer += data;
- };
- let onSuccess = function()
- {
- if (processing)
- {
- // Still processing data, delay processing this event.
- loaded = true;
- return;
- }
-
- // We are ignoring return value of listener.process() here because
- // turning this callback into a generator would be complicated, and
- // delaying isn't really necessary for the last two calls.
- if (buffer !== "")
- listener.process(buffer);
- listener.process(null);
-
- callback(null);
- };
-
- let onError = function(e)
- {
- if (processing)
- {
- // Still processing data, delay processing this event.
- error = e;
- return;
- }
-
- callback(e);
- };
-
- let decoder = new TextDecoder();
- Task.spawn(function*()
- {
- if (firstRead && Services.vc.compare(Utils.platformVersion, "23.0a1") <= 0)
- {
- // See https://issues.adblockplus.org/ticket/530 - the first file
- // opened cannot be closed due to Gecko bug 858723. Make sure that
- // our patterns.ini file doesn't stay locked by opening a dummy file
- // first.
- try
- {
- let dummyPath = IO.resolveFilePath(Prefs.data_directory + "/dummy").path;
- let dummy = yield OS.File.open(dummyPath, {write: true, truncate: true});
- yield dummy.close();
- }
- catch (e)
- {
- // Dummy might be locked already, we don't care
+ listener.process(null);
+ resolve();
}
- }
- firstRead = false;
- let f = yield OS.File.open(file.path, {read: true});
- while (true)
- {
- let array = yield f.read(BUFFER_SIZE);
- if (!array.length)
- break;
-
- let data = decoder.decode(array, {stream: true});
- yield* onProgress(data);
- }
- yield f.close();
- }.bind(this)).then(onSuccess, onError);
- }
- catch (e)
- {
- callback(e);
- }
+ processBatch();
+ });
+ }),
+ callback,
+ () => LegacyIO.readFromFile(file, listener, callback)
+ );
},
/**
* Writes string data to a file in UTF-8 format asynchronously. The callback
* will be called when the write operation is done.
*/
- writeToFile: function(/**nsIFile*/ file, /**Iterator*/ data, /**Function*/ callback)
+ writeToFile(/**nsIFile*/ file, /**Iterator*/ data, /**Function*/ callback)
{
- try
- {
- let encoder = new TextEncoder();
-
- Task.spawn(function*()
- {
- // This mimics OS.File.writeAtomic() but writes in chunks.
- let tmpPath = file.path + ".tmp";
- let f = yield OS.File.open(tmpPath, {write: true, truncate: true});
-
- let buf = [];
- let bufLen = 0;
- let lineBreak = this.lineBreak;
-
- function writeChunk()
- {
- let array = encoder.encode(buf.join(lineBreak) + lineBreak);
- buf = [];
- bufLen = 0;
- return f.write(array);
- }
-
- for (let line of data)
- {
- buf.push(line);
- bufLen += line.length;
- if (bufLen >= BUFFER_SIZE)
- yield writeChunk();
- }
-
- if (bufLen)
- yield writeChunk();
-
- // OS.File.flush() isn't exposed prior to Gecko 27, see bug 912457.
- if (typeof f.flush == "function")
- yield f.flush();
- yield f.close();
- yield OS.File.move(tmpPath, file.path, {noCopy: true});
- }.bind(this)).then(callback.bind(null, null), callback);
- }
- catch (e)
- {
- callback(e);
- }
+ attachCallback(
+ callWebExt("writeToFile", file.leafName, Array.from(data)),
+ callback
+ );
},
/**
* Copies a file asynchronously. The callback will be called when the copy
* operation is done.
*/
- copyFile: function(/**nsIFile*/ fromFile, /**nsIFile*/ toFile, /**Function*/ callback)
+ copyFile(/**nsIFile*/ fromFile, /**nsIFile*/ toFile, /**Function*/ callback)
{
- try
- {
- let promise = OS.File.copy(fromFile.path, toFile.path);
- promise.then(callback.bind(null, null), callback);
- }
- catch (e)
- {
- callback(e);
- }
+ attachCallback(
+ callWebExt("copyFile", fromFile.leafName, toFile.leafName),
+ callback,
+ () => LegacyIO.copyFile(fromFile, toFile, callback)
+ );
},
/**
* Renames a file within the same directory, will call callback when done.
*/
- renameFile: function(/**nsIFile*/ fromFile, /**String*/ newName, /**Function*/ callback)
+ renameFile(/**nsIFile*/ fromFile, /**String*/ newName, /**Function*/ callback)
{
- try
- {
- let toFile = fromFile.clone();
- toFile.leafName = newName;
- let promise = OS.File.move(fromFile.path, toFile.path);
- promise.then(callback.bind(null, null), callback);
- }
- catch(e)
- {
- callback(e);
- }
+ attachCallback(
+ callWebExt("renameFile", fromFile.leafName, newName),
+ callback,
+ () => LegacyIO.renameFile(fromFile, newName, callback)
+ );
},
/**
* Removes a file, will call callback when done.
*/
- removeFile: function(/**nsIFile*/ file, /**Function*/ callback)
+ removeFile(/**nsIFile*/ file, /**Function*/ callback)
{
- try
- {
- let promise = OS.File.remove(file.path);
- promise.then(callback.bind(null, null), callback);
- }
- catch(e)
- {
- callback(e);
- }
+ attachCallback(
+ callWebExt("removeFile", file.leafName),
+ callback,
+ () => LegacyIO.removeFile(file, callback)
+ );
},
/**
* Gets file information such as whether the file exists.
*/
- statFile: function(/**nsIFile*/ file, /**Function*/ callback)
+ statFile(/**nsIFile*/ file, /**Function*/ callback)
{
- try
- {
- let promise = OS.File.stat(file.path);
- promise.then(function onSuccess(info)
- {
- callback(null, {
- exists: true,
- isDirectory: info.isDir,
- isFile: !info.isDir,
- lastModified: info.lastModificationDate.getTime()
- });
- }, function onError(e)
- {
- if (e.becauseNoSuchFile)
- {
- callback(null, {
- exists: false,
- isDirectory: false,
- isFile: false,
- lastModified: 0
- });
- }
- else
- callback(e);
- });
- }
- catch(e)
- {
- callback(e);
- }
+ attachCallback(
+ callWebExt("statFile", file.leafName),
+ callback,
+ () => LegacyIO.statFile(file, callback)
+ );
}
-}
+};
diff --git a/lib/io.js b/lib/legacyIO.js
similarity index 98%
copy from lib/io.js
copy to lib/legacyIO.js
index 4df5f2d..5549d96 100644
--- a/lib/io.js
+++ b/lib/legacyIO.js
@@ -94,11 +94,7 @@ let IO = exports.IO =
lines.pop();
lines[0] = oldBuffer + lines[0];
for (let i = 0; i < lines.length; i++)
- {
- let promise = listener.process(lines[i]);
- if (promise)
- yield promise;
- }
+ listener.process(lines[i]);
}
finally
{
diff --git a/lib/prefs.json b/lib/prefs.json
index ca1a9fe..4cdd539 100644
--- a/lib/prefs.json
+++ b/lib/prefs.json
@@ -35,7 +35,6 @@
"notificationurl": "https://notification.adblockplus.org/notification.json",
"notificationdata": {},
"subscriptions_antiadblockurl": "https://easylist-downloads.adblockplus.org/antiadblockfilters.txt",
- "please_kill_startup_performance": false,
"suppress_first_run_page": false,
"notifications_showui": false,
"notifications_ignoredcategories": []
diff --git a/lib/utils.js b/lib/utils.js
index 7558615..6df64b4 100644
--- a/lib/utils.js
+++ b/lib/utils.js
@@ -326,18 +326,10 @@ let Utils = exports.Utils =
},
/**
- * Pauses code execution and allows events to be processed. Warning:
- * other extension code might execute, the extension might even shut down.
+ * DEPRECATED, do not use!
*/
yield: function()
{
- let {Prefs} = require("prefs");
- if (Prefs.please_kill_startup_performance)
- {
- this.yield = function() {};
- return;
- }
- return new Promise((resolve, reject) => Utils.runAsync(resolve));
},
/**
diff --git a/webextension/.eslintrc.json b/webextension/.eslintrc.json
new file mode 100644
index 0000000..ea12297
--- /dev/null
+++ b/webextension/.eslintrc.json
@@ -0,0 +1,7 @@
+{
+ "extends": "eslint-config-eyeo",
+ "root": true,
+ "env": {
+ "webextensions": true
+ }
+}
diff --git a/webextension/background.js b/webextension/background.js
new file mode 100644
index 0000000..88feb91
--- /dev/null
+++ b/webextension/background.js
@@ -0,0 +1,41 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2017 eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+"use strict";
+
+/* global IO */
+
+let port = browser.runtime.connect();
+
+port.onMessage.addListener(message =>
+{
+ IO[message.method](...message.args).then(result =>
+ {
+ port.postMessage({
+ id: message.id,
+ success: true,
+ result
+ });
+ }).catch(error =>
+ {
+ port.postMessage({
+ id: message.id,
+ success: false,
+ result: String(error)
+ });
+ });
+});
diff --git a/webextension/io.js b/webextension/io.js
new file mode 100644
index 0000000..adfee2f
--- /dev/null
+++ b/webextension/io.js
@@ -0,0 +1,109 @@
+/*
+ * This file is part of Adblock Plus <https://adblockplus.org/>,
+ * Copyright (C) 2006-2017 eyeo GmbH
+ *
+ * Adblock Plus is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * Adblock Plus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+"use strict";
+
+(function(exports)
+{
+ const keyPrefix = "file:";
+
+ function fileToKey(fileName)
+ {
+ return keyPrefix + fileName;
+ }
+
+ function loadFile(file)
+ {
+ let key = fileToKey(file);
+
+ return browser.storage.local.get(key).then(items =>
+ {
+ if (items.hasOwnProperty(key))
+ return items[key];
+
+ throw "NoSuchFile";
+ });
+ }
+
+ function saveFile(file, data)
+ {
+ return browser.storage.local.set({
+ [fileToKey(file)]: {
+ content: Array.from(data),
+ lastModified: Date.now()
+ }
+ });
+ }
+
+ function removeFile(file)
+ {
+ return browser.storage.local.remove(fileToKey(file));
+ }
+
+ exports.IO =
+ {
+ readFromFile(file)
+ {
+ return loadFile(file).then(entry =>
+ {
+ return entry.content;
+ });
+ },
+
+ writeToFile(file, data)
+ {
+ return saveFile(file, data);
+ },
+
+ copyFile(fromFile, toFile)
+ {
+ return loadFile(fromFile).then(entry =>
+ {
+ return saveFile(toFile, entry.content);
+ });
+ },
+
+ renameFile(fromFile, newName)
+ {
+ return loadFile(fromFile).then(entry =>
+ {
+ return browser.storage.local.set({
+ [fileToKey(newName)]: entry
+ });
+ }).then(() =>
+ {
+ return removeFile(fromFile);
+ });
+ },
+
+ removeFile(file)
+ {
+ return removeFile(file);
+ },
+
+ statFile(file)
+ {
+ return loadFile(file).then(entry =>
+ {
+ return {
+ exists: true,
+ lastModified: entry.lastModified
+ };
+ });
+ }
+ };
+})(this);
diff --git a/webextension/manifest.json b/webextension/manifest.json
new file mode 100644
index 0000000..46575e7
--- /dev/null
+++ b/webextension/manifest.json
@@ -0,0 +1,9 @@
+{
+ "manifest_version": 2,
+ "name": "Web Extensions I/O backend",
+ "version": "1.0",
+ "permissions": ["storage"],
+ "background": {
+ "scripts": ["background.js", "io.js"]
+ }
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/adblock-plus.git
More information about the Pkg-mozext-commits
mailing list