toolkit/components/osfile/modules/_PromiseWorker.jsm

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /**
michael@0 2 * Thin wrapper around a ChromeWorker that wraps postMessage/onmessage/onerror
michael@0 3 * as promises.
michael@0 4 *
michael@0 5 * Not for public use yet.
michael@0 6 */
michael@0 7
michael@0 8 "use strict";
michael@0 9
michael@0 10 this.EXPORTED_SYMBOLS = ["PromiseWorker"];
michael@0 11
michael@0 12 // The library of promises.
michael@0 13 Components.utils.import("resource://gre/modules/Promise.jsm", this);
michael@0 14
michael@0 15 /**
michael@0 16 * An implementation of queues (FIFO).
michael@0 17 *
michael@0 18 * The current implementation uses one array, runs in O(n ^ 2), and is optimized
michael@0 19 * for the case in which queues are generally short.
michael@0 20 */
michael@0 21 let Queue = function Queue() {
michael@0 22 this._array = [];
michael@0 23 };
michael@0 24 Queue.prototype = {
michael@0 25 pop: function pop() {
michael@0 26 return this._array.shift();
michael@0 27 },
michael@0 28 push: function push(x) {
michael@0 29 return this._array.push(x);
michael@0 30 },
michael@0 31 isEmpty: function isEmpty() {
michael@0 32 return this._array.length == 0;
michael@0 33 }
michael@0 34 };
michael@0 35
michael@0 36 /**
michael@0 37 * An object responsible for dispatching messages to
michael@0 38 * a chrome worker and routing the responses.
michael@0 39 *
michael@0 40 * @param {string} url The url containing the source code for this worker,
michael@0 41 * as in constructor ChromeWorker.
michael@0 42 * @param {Function} log A logging function.
michael@0 43 *
michael@0 44 * @constructor
michael@0 45 */
michael@0 46 function PromiseWorker(url, log) {
michael@0 47 if (typeof url != "string") {
michael@0 48 throw new TypeError("Expecting a string");
michael@0 49 }
michael@0 50 if (typeof log !== "function") {
michael@0 51 throw new TypeError("log is expected to be a function");
michael@0 52 }
michael@0 53 this._log = log;
michael@0 54 this._url = url;
michael@0 55
michael@0 56 /**
michael@0 57 * The queue of deferred, waiting for the completion of their
michael@0 58 * respective job by the worker.
michael@0 59 *
michael@0 60 * Each item in the list may contain an additional field |closure|,
michael@0 61 * used to store strong references to value that must not be
michael@0 62 * garbage-collected before the reply has been received (e.g.
michael@0 63 * arrays).
michael@0 64 *
michael@0 65 * @type {Queue<{deferred:deferred, closure:*=}>}
michael@0 66 */
michael@0 67 this._queue = new Queue();
michael@0 68
michael@0 69 /**
michael@0 70 * The number of the current message.
michael@0 71 *
michael@0 72 * Used for debugging purposes.
michael@0 73 */
michael@0 74 this._id = 0;
michael@0 75
michael@0 76 /**
michael@0 77 * The instant at which the worker was launched.
michael@0 78 */
michael@0 79 this.launchTimeStamp = null;
michael@0 80
michael@0 81 /**
michael@0 82 * Timestamps provided by the worker for statistics purposes.
michael@0 83 */
michael@0 84 this.workerTimeStamps = null;
michael@0 85 }
michael@0 86 PromiseWorker.prototype = {
michael@0 87 /**
michael@0 88 * Instantiate the worker lazily.
michael@0 89 */
michael@0 90 get _worker() {
michael@0 91 delete this._worker;
michael@0 92 let worker = new ChromeWorker(this._url);
michael@0 93 let self = this;
michael@0 94 Object.defineProperty(this, "_worker", {value:
michael@0 95 worker
michael@0 96 });
michael@0 97
michael@0 98 // We assume that we call to _worker for the purpose of calling
michael@0 99 // postMessage().
michael@0 100 this.launchTimeStamp = Date.now();
michael@0 101
michael@0 102 /**
michael@0 103 * Receive errors that are not instances of OS.File.Error, propagate
michael@0 104 * them to the listeners.
michael@0 105 *
michael@0 106 * The worker knows how to serialize errors that are instances
michael@0 107 * of |OS.File.Error|. These are treated by |worker.onmessage|.
michael@0 108 * However, for other errors, we rely on DOM's mechanism for
michael@0 109 * serializing errors, which transmits these errors through
michael@0 110 * |worker.onerror|.
michael@0 111 *
michael@0 112 * @param {Error} error Some JS error.
michael@0 113 */
michael@0 114 worker.onerror = function onerror(error) {
michael@0 115 self._log("Received uncaught error from worker", error.message, error.filename, error.lineno);
michael@0 116 error.preventDefault();
michael@0 117 let {deferred} = self._queue.pop();
michael@0 118 deferred.reject(error);
michael@0 119 };
michael@0 120
michael@0 121 /**
michael@0 122 * Receive messages from the worker, propagate them to the listeners.
michael@0 123 *
michael@0 124 * Messages must have one of the following shapes:
michael@0 125 * - {ok: some_value} in case of success
michael@0 126 * - {fail: some_error} in case of error, where
michael@0 127 * some_error is an instance of |PromiseWorker.WorkerError|
michael@0 128 *
michael@0 129 * Messages may also contain a field |id| to help
michael@0 130 * with debugging.
michael@0 131 *
michael@0 132 * Messages may also optionally contain a field |durationMs|, holding
michael@0 133 * the duration of the function call in milliseconds.
michael@0 134 *
michael@0 135 * @param {*} msg The message received from the worker.
michael@0 136 */
michael@0 137 worker.onmessage = function onmessage(msg) {
michael@0 138 self._log("Received message from worker", msg.data);
michael@0 139 let handler = self._queue.pop();
michael@0 140 let deferred = handler.deferred;
michael@0 141 let data = msg.data;
michael@0 142 if (data.id != handler.id) {
michael@0 143 throw new Error("Internal error: expecting msg " + handler.id + ", " +
michael@0 144 " got " + data.id + ": " + JSON.stringify(msg.data));
michael@0 145 }
michael@0 146 if ("timeStamps" in data) {
michael@0 147 self.workerTimeStamps = data.timeStamps;
michael@0 148 }
michael@0 149 if ("ok" in data) {
michael@0 150 // Pass the data to the listeners.
michael@0 151 deferred.resolve(data);
michael@0 152 } else if ("StopIteration" in data) {
michael@0 153 // We have received a StopIteration error
michael@0 154 deferred.reject(StopIteration);
michael@0 155 } if ("fail" in data) {
michael@0 156 // We have received an error that was serialized by the
michael@0 157 // worker.
michael@0 158 deferred.reject(new PromiseWorker.WorkerError(data.fail));
michael@0 159 }
michael@0 160 };
michael@0 161 return worker;
michael@0 162 },
michael@0 163
michael@0 164 /**
michael@0 165 * Post a message to a worker.
michael@0 166 *
michael@0 167 * @param {string} fun The name of the function to call.
michael@0 168 * @param {Array} array The contents of the message.
michael@0 169 * @param {*=} closure An object holding references that should not be
michael@0 170 * garbage-collected before the message treatment is complete.
michael@0 171 *
michael@0 172 * @return {promise}
michael@0 173 */
michael@0 174 post: function post(fun, array, closure) {
michael@0 175 let deferred = Promise.defer();
michael@0 176 let id = ++this._id;
michael@0 177 let message = {fun: fun, args: array, id: id};
michael@0 178 this._log("Posting message", message);
michael@0 179 try {
michael@0 180 this._worker.postMessage(message);
michael@0 181 } catch (ex if typeof ex == "number") {
michael@0 182 this._log("Could not post message", message, "due to xpcom error", ex);
michael@0 183 // handle raw xpcom errors (see eg bug 961317)
michael@0 184 return Promise.reject(new Components.Exception("Error in postMessage", ex));
michael@0 185 } catch (ex) {
michael@0 186 this._log("Could not post message", message, "due to error", ex);
michael@0 187 return Promise.reject(ex);
michael@0 188 }
michael@0 189
michael@0 190 this._queue.push({deferred:deferred, closure: closure, id: id});
michael@0 191 this._log("Message posted");
michael@0 192 return deferred.promise;
michael@0 193 }
michael@0 194 };
michael@0 195
michael@0 196 /**
michael@0 197 * An error that has been serialized by the worker.
michael@0 198 *
michael@0 199 * @constructor
michael@0 200 */
michael@0 201 PromiseWorker.WorkerError = function WorkerError(data) {
michael@0 202 this.data = data;
michael@0 203 };
michael@0 204
michael@0 205 this.PromiseWorker = PromiseWorker;

mercurial