tor-browser

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

lazy-pool.js (7639B)


      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 "use strict";
      6 
      7 const { Pool } = require("devtools/shared/protocol");
      8 
      9 /**
     10 * A Special Pool for RootActor and WindowGlobalTargetActor, which allows lazy loaded
     11 * actors to be added to the pool.
     12 *
     13 * Like the Pool, this is a protocol object that can manage the lifetime of other protocol
     14 * objects. Pools are used on both sides of the connection to help coordinate lifetimes.
     15 */
     16 class LazyPool extends Pool {
     17  /**
     18   * @param conn
     19   *   Is a DevToolsServerConnection.  Must have
     20   *   addActorPool, removeActorPool, and poolFor.
     21   */
     22  constructor(conn) {
     23    super(conn);
     24  }
     25 
     26  // The actor for a given actor id stored in this pool
     27  getActorByID(actorID) {
     28    if (this.__poolMap) {
     29      const entry = this._poolMap.get(actorID);
     30      if (entry instanceof LazyActor) {
     31        return entry.createActor();
     32      }
     33      return entry;
     34    }
     35    return null;
     36  }
     37 }
     38 
     39 exports.LazyPool = LazyPool;
     40 
     41 /**
     42 * Populate |parent._extraActors| as specified by |registeredActors|, reusing whatever
     43 * actors are already there. Add all actors in the final extra actors table to
     44 * |pool|. _extraActors is treated as a cache for lazy actors
     45 *
     46 * The target actor uses this to instantiate actors that other
     47 * parts of the browser have specified with ActorRegistry.addTargetScopedActor
     48 *
     49 * @param factories
     50 *     An object whose own property names are the names of properties to add to
     51 *     some reply packet (say, a target actor grip or the "listTabs" response
     52 *     form), and whose own property values are actor constructor functions, as
     53 *     documented for addTargetScopedActor
     54 *
     55 * @param parent
     56 *     The parent TargetActor with which the new actors
     57 *     will be associated. It should support whatever API the |factories|
     58 *     constructor functions might be interested in, as it is passed to them.
     59 *     For the sake of CommonCreateExtraActors itself, it should have at least
     60 *     the following properties:
     61 *
     62 *     - _extraActors
     63 *        An object whose own property names are factory table (and packet)
     64 *        property names, and whose values are no-argument actor constructors,
     65 *        of the sort that one can add to a Pool.
     66 *
     67 *     - conn
     68 *        The DevToolsServerConnection in which the new actors will participate.
     69 *
     70 *     - actorID
     71 *        The actor's name, for use as the new actors' parentID.
     72 * @param pool
     73 *     An object which implements the protocol.js Pool interface, and has the
     74 *     following properties
     75 *
     76 *     - manage
     77 *       a function which adds a given actor to an actor pool
     78 */
     79 function createExtraActors(registeredActors, pool, parent) {
     80  // Walk over global actors added by extensions.
     81  const nameMap = {};
     82  for (const name in registeredActors) {
     83    let actor = parent._extraActors[name];
     84    if (!actor) {
     85      // Register another factory, but this time specific to this connection.
     86      // It creates a fake actor that looks like an regular actor in the pool,
     87      // but without actually instantiating the actor.
     88      // It will only be instantiated on the first request made to the actor.
     89      actor = new LazyActor(registeredActors[name], parent, pool);
     90      parent._extraActors[name] = actor;
     91    }
     92 
     93    // If the actor already exists in the pool, it may have been instantiated,
     94    // so make sure not to overwrite it by a non-instantiated version.
     95    if (!pool.has(actor.actorID)) {
     96      pool.manage(actor);
     97    }
     98    nameMap[name] = actor.actorID;
     99  }
    100  return nameMap;
    101 }
    102 
    103 exports.createExtraActors = createExtraActors;
    104 
    105 /**
    106 * Creates an "actor-like" object which responds in the same way as an ordinary actor
    107 * but has fewer capabilities (ie, does not manage lifetimes or have it's own pool).
    108 */
    109 
    110 class LazyActor {
    111  /**
    112   * @param factory
    113   *     An object whose own property names are the names of properties to add to
    114   *     some reply packet (say, a target actor grip or the "listTabs" response
    115   *     form), and whose own property values are actor constructor functions, as
    116   *     documented for addTargetScopedActor
    117   *
    118   * @param parent
    119   *     The parent TargetActor with which the new actors
    120   *     will be associated. It should support whatever API the |factories|
    121   *     constructor functions might be interested in, as it is passed to them.
    122   *     For the sake of CommonCreateExtraActors itself, it should have at least
    123   *     the following properties:
    124   *
    125   *     - _extraActors
    126   *        An object whose own property names are factory table (and packet)
    127   *        property names, and whose values are no-argument actor constructors,
    128   *        of the sort that one can add to a Pool.
    129   *
    130   *     - conn
    131   *        The DevToolsServerConnection in which the new actors will participate.
    132   *
    133   *     - actorID
    134   *        The actor's name, for use as the new actors' parentID.
    135   * @param pool
    136   *     An object which implements the protocol.js Pool interface, and has the
    137   *     following properties
    138   *
    139   *     - manage
    140   *       a function which adds a given actor to an actor pool
    141   */
    142  constructor(factory, parent, pool) {
    143    this._options = factory.options;
    144    this._parentActor = parent;
    145    this._name = factory.name;
    146    this._pool = pool;
    147 
    148    // needed for taking a place in a pool
    149    this.typeName = factory.name;
    150  }
    151  loadModule(id) {
    152    const options = this._options;
    153    try {
    154      return require(id);
    155      // Fetch the actor constructor
    156    } catch (e) {
    157      throw new Error(
    158        `Unable to load actor module '${options.id}'\n${e.message}\n${e.stack}\n`
    159      );
    160    }
    161  }
    162 
    163  getConstructor() {
    164    const options = this._options;
    165    if (options.constructorFun) {
    166      // Actor definition registered by testing helpers
    167      return options.constructorFun;
    168    }
    169    // Lazy actor definition, where options contains all the information
    170    // required to load the actor lazily.
    171    // Exposes `name` attribute in order to allow removeXXXActor to match
    172    // the actor by its actor constructor name.
    173    this.name = options.constructorName;
    174    const module = this.loadModule(options.id);
    175    const constructor = module[options.constructorName];
    176    if (!constructor) {
    177      throw new Error(
    178        `Unable to find actor constructor named '${this.name}'. (Is it exported?)`
    179      );
    180    }
    181    return constructor;
    182  }
    183 
    184  /**
    185   * Return the parent pool for this lazy actor.
    186   */
    187  getParent() {
    188    return this.conn && this.conn.poolFor(this.actorID);
    189  }
    190 
    191  /**
    192   * This will only happen if the actor is destroyed before it is created
    193   * We do not want to use the Pool destruction method, because this actor
    194   * has no pool. However, it might have a parent that should unmange this
    195   * actor
    196   */
    197  destroy() {
    198    const parent = this.getParent();
    199    if (parent) {
    200      parent.unmanage(this);
    201    }
    202  }
    203 
    204  createActor() {
    205    // Fetch the actor constructor
    206    const Constructor = this.getConstructor();
    207    // Instantiate a new actor instance
    208    const conn = this._parentActor.conn;
    209    // this should be taken care of once all actors are moved to protocol.js
    210    const instance = new Constructor(conn, this._parentActor);
    211    instance.conn = conn;
    212 
    213    // We want the newly-constructed actor to completely replace the factory
    214    // actor. Reusing the existing actor ID will make sure Pool.manage
    215    // replaces the old actor with the new actor.
    216    instance.actorID = this.actorID;
    217 
    218    this._pool.manage(instance);
    219 
    220    return instance;
    221  }
    222 }