tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

helper.js (3862B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /* eslint-env amd */
      6 
      7 "use strict";
      8 
      9 /* global workerHelper */
     10 /* exported workerHelper */
     11 (function (root, factory) {
     12  if (typeof define === "function" && define.amd) {
     13    define(factory);
     14  } else if (typeof exports === "object") {
     15    module.exports = factory();
     16  } else {
     17    root.workerHelper = factory();
     18  }
     19 })(this, function () {
     20  /**
     21   * This file is to only be included by ChromeWorkers. This exposes
     22   * a `createTask` function to workers to register tasks for communication
     23   * back to `devtools/shared/worker`.
     24   *
     25   * Tasks can be send their responses via a return value, either a primitive
     26   * or a promise.
     27   *
     28   * createTask(self, "average", function (data) {
     29   *   return data.reduce((sum, val) => sum + val, 0) / data.length;
     30   * });
     31   *
     32   * createTask(self, "average", function (data) {
     33   *   return new Promise((resolve, reject) => {
     34   *     resolve(data.reduce((sum, val) => sum + val, 0) / data.length);
     35   *   });
     36   * });
     37   *
     38   *
     39   * Errors:
     40   *
     41   * Returning an Error value, or if the returned promise is rejected, this
     42   * propagates to the DevToolsWorker as a rejected promise. If an error is
     43   * thrown in a synchronous function, that error is also propagated.
     44   */
     45 
     46  /**
     47   * Takes a worker's `self` object, a task name, and a function to
     48   * be called when that task is called. The task is called with the
     49   * passed in data as the first argument
     50   *
     51   * @param {object} self
     52   * @param {string} name
     53   * @param {function} fn
     54   */
     55  function createTask(self, name, fn) {
     56    // Store a hash of task name to function on the Worker
     57    if (!self._tasks) {
     58      self._tasks = {};
     59    }
     60 
     61    // Create the onmessage handler if not yet created.
     62    if (!self.onmessage) {
     63      self.onmessage = createHandler(self);
     64    }
     65 
     66    // Store the task on the worker.
     67    self._tasks[name] = fn;
     68  }
     69 
     70  /**
     71   * Creates the `self.onmessage` handler for a Worker.
     72   *
     73   * @param {object} self
     74   * @return {function}
     75   */
     76  function createHandler(self) {
     77    return function (e) {
     78      const { id, task, data } = e.data;
     79      const taskFn = self._tasks[task];
     80 
     81      if (!taskFn) {
     82        self.postMessage({ id, error: `Task "${task}" not found in worker.` });
     83        return;
     84      }
     85 
     86      try {
     87        handleResponse(taskFn(data));
     88      } catch (ex) {
     89        handleError(ex);
     90      }
     91 
     92      function handleResponse(response) {
     93        // If a promise
     94        if (response && typeof response.then === "function") {
     95          response.then(
     96            val => self.postMessage({ id, response: val }),
     97            handleError
     98          );
     99        } else if (response instanceof Error) {
    100          // If an error object
    101          handleError(response);
    102        } else {
    103          // If anything else
    104          self.postMessage({ id, response });
    105        }
    106      }
    107 
    108      function handleError(error = "Error") {
    109        try {
    110          // First, try and structured clone the error across directly.
    111          self.postMessage({ id, error });
    112        } catch (x) {
    113          // We could not clone whatever error value was given. Do our best to
    114          // stringify it.
    115          let errorString = `Error while performing task "${task}": `;
    116 
    117          try {
    118            errorString += error.toString();
    119          } catch (ex) {
    120            errorString += "<could not stringify error>";
    121          }
    122 
    123          if ("stack" in error) {
    124            try {
    125              errorString += "\n" + error.stack;
    126            } catch (err) {
    127              // Do nothing
    128            }
    129          }
    130 
    131          self.postMessage({ id, error: errorString });
    132        }
    133      }
    134    };
    135  }
    136 
    137  return { createTask };
    138 });