| Index: lib/io.js |
| =================================================================== |
| --- a/lib/io.js |
| +++ b/lib/io.js |
| @@ -50,125 +50,183 @@ function callWebExt(method, ...args) |
| { |
| let id = ++messageID; |
| messageCallbacks.set(id, {resolve, reject}); |
| port.postMessage({id, method, args}); |
| }); |
| }); |
| } |
| -function attachCallback(promise, callback, fallback) |
| +function callLegacy(method, ...args) |
| { |
| - promise.then(result => |
| + return new Promise((resolve, reject) => |
| { |
| - callback(null, result); |
| - }).catch(error => |
| - { |
| - if (fallback && error == "NoSuchFile") |
| - fallback(); |
| - else |
| - callback(error); |
| + LegacyIO[method](...args, (error, result) => |
| + { |
| + if (error) |
| + reject(error); |
| + else |
| + resolve(result); |
| + }); |
| }); |
| } |
| +function legacyFile(fileName) |
| +{ |
| + let file = LegacyIO.resolveFilePath("adblockplus"); |
| + file.append(fileName); |
| + return file; |
| +} |
| + |
| exports.IO = |
| { |
| - resolveFilePath: LegacyIO.resolveFilePath, |
| + /** |
| + * @callback TextSink |
| + * @param {string} line |
| + */ |
| /** |
| - * 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. |
| + * Reads text lines from a file. |
| + * @param {string} fileName |
| + * Name of the file to be read |
| + * @param {TextSink} listener |
| + * Function that will be called for each line in the file |
| + * @return {Promise} |
| + * Promise to be resolved or rejected once the operation is completed |
| */ |
| - readFromFile(/**nsIFile*/ file, /**Object*/ listener, /**Function*/ callback) |
| + readFromFile(fileName, listener) |
| { |
| - attachCallback( |
| - callWebExt("readFromFile", file.leafName).then(contents => |
| + return callWebExt("readFromFile", fileName).then(contents => |
| + { |
| + return new Promise((resolve, reject) => |
| { |
| - return new Promise((resolve, reject) => |
| + let lineIndex = 0; |
| + |
| + function processBatch() |
| { |
| - let lineIndex = 0; |
| - |
| - function processBatch() |
| + while (lineIndex < contents.length) |
| { |
| - while (lineIndex < contents.length) |
| + listener(contents[lineIndex++]); |
| + if (lineIndex % 1000 == 0) |
| { |
| - listener.process(contents[lineIndex++]); |
| - if (lineIndex % 1000 == 0) |
| - { |
| - Utils.runAsync(processBatch); |
| - return; |
| - } |
| + Utils.runAsync(processBatch); |
| + return; |
| } |
| + } |
| + resolve(); |
| + } |
| - listener.process(null); |
| - resolve(); |
| + processBatch(); |
| + }); |
| + }).catch(error => |
| + { |
| + if (error == "NoSuchFile") |
| + { |
| + let wrapper = { |
| + process(line) |
| + { |
| + if (line !== null) |
| + listener(line); |
| } |
| - |
| - processBatch(); |
| - }); |
| - }), |
| - callback, |
| - () => LegacyIO.readFromFile(file, listener, callback) |
| - ); |
| + }; |
| + return callLegacy("readFromFile", legacyFile(fileName), wrapper); |
| + } |
| + throw error; |
| + }); |
| }, |
| /** |
| - * Writes string data to a file in UTF-8 format asynchronously. The callback |
| - * will be called when the write operation is done. |
| + * Writes text lines to a file. |
| + * @param {string} fileName |
| + * Name of the file to be written |
| + * @param {Iterable.<string>} data |
| + * An array-like or iterable object containing the lines (without line |
| + * endings) |
| + * @return {Promise} |
| + * Promise to be resolved or rejected once the operation is completed |
| */ |
| - writeToFile(/**nsIFile*/ file, /**Iterator*/ data, /**Function*/ callback) |
| + writeToFile(fileName, data) |
| { |
| - 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(/**nsIFile*/ fromFile, /**nsIFile*/ toFile, /**Function*/ callback) |
| - { |
| - attachCallback( |
| - callWebExt("copyFile", fromFile.leafName, toFile.leafName), |
| - callback, |
| - () => LegacyIO.copyFile(fromFile, toFile, callback) |
| - ); |
| + return callWebExt("writeToFile", fileName, Array.from(data)); |
| }, |
| /** |
| - * Renames a file within the same directory, will call callback when done. |
| + * Copies a file. |
| + * @param {string} fromFile |
| + * Name of the file to be copied |
| + * @param {string} toFile |
| + * Name of the file to be written, will be overwritten if exists |
| + * @return {Promise} |
| + * Promise to be resolved or rejected once the operation is completed |
| */ |
| - renameFile(/**nsIFile*/ fromFile, /**String*/ newName, /**Function*/ callback) |
| + copyFile(fromFile, toFile) |
| { |
| - attachCallback( |
| - callWebExt("renameFile", fromFile.leafName, newName), |
| - callback, |
| - () => LegacyIO.renameFile(fromFile, newName, callback) |
| - ); |
| + return callWebExt("copyFile", fromFile, toFile).catch(error => |
| + { |
| + if (error == "NoSuchFile") |
|
kzar
2017/04/20 10:25:07
It seems like this pattern is repeated quite a bit
Wladimir Palant
2017/04/20 12:02:06
I thought about it but couldn't see a way requirin
kzar
2017/04/20 12:11:59
Hmm I guess not. I didn't realise the arguments pa
|
| + return callLegacy("copyFile", legacyFile(fromFile), legacyFile(toFile)); |
| + throw error; |
| + }); |
| }, |
| /** |
| - * Removes a file, will call callback when done. |
| + * Renames a file. |
| + * @param {string} fromFile |
| + * Name of the file to be renamed |
| + * @param {string} newName |
| + * New file name, will be overwritten if exists |
| + * @return {Promise} |
| + * Promise to be resolved or rejected once the operation is completed |
| */ |
| - removeFile(/**nsIFile*/ file, /**Function*/ callback) |
| + renameFile(fromFile, newName) |
| { |
| - attachCallback( |
| - callWebExt("removeFile", file.leafName), |
| - callback, |
| - () => LegacyIO.removeFile(file, callback) |
| - ); |
| + return callWebExt("renameFile", fromFile, newName).catch(error => |
| + { |
| + if (error == "NoSuchFile") |
| + return callLegacy("renameFile", legacyFile(fromFile), newName); |
| + throw error; |
| + }); |
| }, |
| /** |
| - * Gets file information such as whether the file exists. |
| + * Removes a file. |
| + * @param {string} fileName |
| + * Name of the file to be removed |
| + * @return {Promise} |
| + * Promise to be resolved or rejected once the operation is completed |
| */ |
| - statFile(/**nsIFile*/ file, /**Function*/ callback) |
| + removeFile(fileName) |
| { |
| - attachCallback( |
| - callWebExt("statFile", file.leafName), |
| - callback, |
| - () => LegacyIO.statFile(file, callback) |
| - ); |
| + return callWebExt("removeFile", fileName).catch(error => |
| + { |
| + if (error == "NoSuchFile") |
| + return callLegacy("removeFile", legacyFile(fileName)); |
| + throw error; |
| + }); |
| + }, |
| + |
| + /** |
| + * @typedef StatData |
| + * @type {object} |
| + * @property {boolean} exists |
| + * true if the file exists |
| + * @property {number} lastModified |
| + * file modification time in milliseconds |
| + */ |
| + |
| + /** |
| + * Retrieves file metadata. |
| + * @param {string} fileName |
| + * Name of the file to be looked up |
| + * @return {Promise.<StatData>} |
| + * Promise to be resolved with file metadata once the operation is |
| + * completed |
| + */ |
| + statFile(fileName) |
| + { |
| + return callWebExt("statFile", fileName).catch(error => |
| + { |
| + if (error == "NoSuchFile") |
| + return callLegacy("statFile", legacyFile(fileName)); |
| + throw error; |
| + }); |
| } |
| }; |