зеркало из https://github.com/mozilla/gecko-dev.git
232 строки
7.7 KiB
JavaScript
232 строки
7.7 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
const { extend } = require("devtools/shared/extend");
|
|
const { Pool } = require("devtools/shared/protocol");
|
|
|
|
/**
|
|
* A Special Pool for RootActor and BrowsingContextTargetActor, which allows lazy loaded
|
|
* actors to be added to the pool.
|
|
*
|
|
* Like the Pool, this is a protocol object that can manage the lifetime of other protocol
|
|
* objects. Pools are used on both sides of the connection to help coordinate lifetimes.
|
|
*
|
|
* @param conn
|
|
* Is a DebuggerServerConnection. Must have
|
|
* addActorPool, removeActorPool, and poolFor.
|
|
* @constructor
|
|
*/
|
|
function LazyPool(conn) {
|
|
this.conn = conn;
|
|
}
|
|
|
|
LazyPool.prototype = extend(Pool.prototype, {
|
|
// The actor for a given actor id stored in this pool
|
|
actor: function(actorID) {
|
|
if (this.__poolMap) {
|
|
const entry = this._poolMap.get(actorID);
|
|
if (entry instanceof LazyActor) {
|
|
return entry.createActor();
|
|
}
|
|
return entry;
|
|
}
|
|
return null;
|
|
},
|
|
|
|
// Same as actor, should update debugger connection to use 'actor'
|
|
// and then remove this.
|
|
get: function(actorID) {
|
|
return this.actor(actorID);
|
|
},
|
|
});
|
|
|
|
exports.LazyPool = LazyPool;
|
|
|
|
/**
|
|
* Populate |parent._extraActors| as specified by |registeredActors|, reusing whatever
|
|
* actors are already there. Add all actors in the final extra actors table to
|
|
* |pool|. _extraActors is treated as a cache for lazy actors
|
|
*
|
|
* The target actor uses this to instantiate actors that other
|
|
* parts of the browser have specified with ActorRegistry.addTargetScopedActor
|
|
*
|
|
* @param factories
|
|
* An object whose own property names are the names of properties to add to
|
|
* some reply packet (say, a target actor grip or the "listTabs" response
|
|
* form), and whose own property values are actor constructor functions, as
|
|
* documented for addTargetScopedActor
|
|
*
|
|
* @param parent
|
|
* The parent TargetActor with which the new actors
|
|
* will be associated. It should support whatever API the |factories|
|
|
* constructor functions might be interested in, as it is passed to them.
|
|
* For the sake of CommonCreateExtraActors itself, it should have at least
|
|
* the following properties:
|
|
*
|
|
* - _extraActors
|
|
* An object whose own property names are factory table (and packet)
|
|
* property names, and whose values are no-argument actor constructors,
|
|
* of the sort that one can add to an ActorPool.
|
|
*
|
|
* - conn
|
|
* The DebuggerServerConnection in which the new actors will participate.
|
|
*
|
|
* - actorID
|
|
* The actor's name, for use as the new actors' parentID.
|
|
* @param pool
|
|
* An object which implements the protocol.js Pool interface, and has the
|
|
* following properties
|
|
*
|
|
* - manage
|
|
* a function which adds a given actor to an actor pool
|
|
*/
|
|
function createExtraActors(registeredActors, pool, parent) {
|
|
// Walk over global actors added by extensions.
|
|
const nameMap = {};
|
|
for (const name in registeredActors) {
|
|
let actor = parent._extraActors[name];
|
|
if (!actor) {
|
|
// Register another factory, but this time specific to this connection.
|
|
// It creates a fake actor that looks like an regular actor in the pool,
|
|
// but without actually instantiating the actor.
|
|
// It will only be instantiated on the first request made to the actor.
|
|
actor = new LazyActor(registeredActors[name], parent, pool);
|
|
parent._extraActors[name] = actor;
|
|
}
|
|
|
|
// If the actor already exists in the pool, it may have been instantiated,
|
|
// so make sure not to overwrite it by a non-instantiated version.
|
|
if (!pool.has(actor.actorID)) {
|
|
pool.manage(actor);
|
|
}
|
|
nameMap[name] = actor.actorID;
|
|
}
|
|
return nameMap;
|
|
}
|
|
|
|
exports.createExtraActors = createExtraActors;
|
|
|
|
/**
|
|
* Creates an "actor-like" object which responds in the same way as an ordinary actor
|
|
* but has fewer capabilities (ie, does not manage lifetimes or have it's own pool).
|
|
*
|
|
*
|
|
* @param factories
|
|
* An object whose own property names are the names of properties to add to
|
|
* some reply packet (say, a target actor grip or the "listTabs" response
|
|
* form), and whose own property values are actor constructor functions, as
|
|
* documented for addTargetScopedActor
|
|
*
|
|
* @param parent
|
|
* The parent TargetActor with which the new actors
|
|
* will be associated. It should support whatever API the |factories|
|
|
* constructor functions might be interested in, as it is passed to them.
|
|
* For the sake of CommonCreateExtraActors itself, it should have at least
|
|
* the following properties:
|
|
*
|
|
* - _extraActors
|
|
* An object whose own property names are factory table (and packet)
|
|
* property names, and whose values are no-argument actor constructors,
|
|
* of the sort that one can add to an ActorPool.
|
|
*
|
|
* - conn
|
|
* The DebuggerServerConnection in which the new actors will participate.
|
|
*
|
|
* - actorID
|
|
* The actor's name, for use as the new actors' parentID.
|
|
* @param pool
|
|
* An object which implements the protocol.js Pool interface, and has the
|
|
* following properties
|
|
*
|
|
* - manage
|
|
* a function which adds a given actor to an actor pool
|
|
*/
|
|
|
|
function LazyActor(factory, parent, pool) {
|
|
this._options = factory.options;
|
|
this._parentActor = parent;
|
|
this._name = factory.name;
|
|
this._pool = pool;
|
|
|
|
// needed for taking a place in a pool
|
|
this.typeName = factory.name;
|
|
}
|
|
|
|
LazyActor.prototype = {
|
|
loadModule(id) {
|
|
const options = this._options;
|
|
try {
|
|
return require(id);
|
|
// Fetch the actor constructor
|
|
} catch (e) {
|
|
throw new Error(
|
|
`Unable to load actor module '${options.id}'\n${e.message}\n${e.stack}\n`
|
|
);
|
|
}
|
|
},
|
|
|
|
getConstructor() {
|
|
const options = this._options;
|
|
if (options.constructorFun) {
|
|
// Actor definition registered by ActorRegistryActor or testing helpers
|
|
return options.constructorFun;
|
|
}
|
|
// Lazy actor definition, where options contains all the information
|
|
// required to load the actor lazily.
|
|
// Exposes `name` attribute in order to allow removeXXXActor to match
|
|
// the actor by its actor constructor name.
|
|
this.name = options.constructorName;
|
|
const module = this.loadModule(options.id);
|
|
const constructor = module[options.constructorName];
|
|
if (!constructor) {
|
|
throw new Error(
|
|
`Unable to find actor constructor named '${this.name}'. (Is it exported?)`
|
|
);
|
|
}
|
|
return constructor;
|
|
},
|
|
|
|
/**
|
|
* Return the parent pool for this lazy actor.
|
|
*/
|
|
parent: function() {
|
|
return this.conn && this.conn.poolFor(this.actorID);
|
|
},
|
|
|
|
/**
|
|
* This will only happen if the actor is destroyed before it is created
|
|
* We do not want to use the Pool destruction method, because this actor
|
|
* has no pool. However, it might have a parent that should unmange this
|
|
* actor
|
|
*/
|
|
destroy() {
|
|
const parent = this.parent();
|
|
if (parent) {
|
|
parent.unmanage(this);
|
|
}
|
|
},
|
|
|
|
createActor() {
|
|
// Fetch the actor constructor
|
|
const Constructor = this.getConstructor();
|
|
// Instantiate a new actor instance
|
|
const conn = this._parentActor.conn;
|
|
// this should be taken care of once all actors are moved to protocol.js
|
|
const instance = new Constructor(conn, this._parentActor);
|
|
instance.conn = conn;
|
|
|
|
// We want the newly-constructed actor to completely replace the factory
|
|
// actor. Reusing the existing actor ID will make sure Pool.manage
|
|
// replaces the old actor with the new actor.
|
|
instance.actorID = this.actorID;
|
|
|
|
this._pool.manage(instance);
|
|
|
|
return instance;
|
|
},
|
|
};
|
|
|