summaryrefslogtreecommitdiffstats
path: root/devtools/server/actors/targets/target-actor-mixin.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/server/actors/targets/target-actor-mixin.js')
-rw-r--r--devtools/server/actors/targets/target-actor-mixin.js121
1 files changed, 121 insertions, 0 deletions
diff --git a/devtools/server/actors/targets/target-actor-mixin.js b/devtools/server/actors/targets/target-actor-mixin.js
new file mode 100644
index 0000000000..8b989f5920
--- /dev/null
+++ b/devtools/server/actors/targets/target-actor-mixin.js
@@ -0,0 +1,121 @@
+/* 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 { ActorClassWithSpec } = require("devtools/shared/protocol");
+
+const Resources = require("devtools/server/actors/resources/index");
+
+module.exports = function(targetType, targetActorSpec, implementation) {
+ const proto = {
+ /**
+ * Type of target, a string of Targets.TYPES.
+ * @return {string}
+ */
+ targetType,
+
+ /**
+ * Process a new data entry, which can be watched resources, breakpoints, ...
+ *
+ * @param string type
+ * The type of data to be added
+ * @param Array<Object> entries
+ * The values to be added to this type of data
+ */
+ async addWatcherDataEntry(type, entries) {
+ if (type == "resources") {
+ await this._watchTargetResources(entries);
+ } else if (type == "breakpoints") {
+ // Breakpoints require the target to be attached,
+ // mostly to have the thread actor instantiated
+ // (content process targets don't have attach method,
+ // instead they instantiate their ThreadActor immediately)
+ if (typeof this.attach == "function") {
+ this.attach();
+ }
+
+ await Promise.all(
+ entries.map(({ location, options }) =>
+ this.threadActor.setBreakpoint(location, options)
+ )
+ );
+ }
+ },
+
+ removeWatcherDataEntry(type, entries) {
+ if (type == "resources") {
+ return this._unwatchTargetResources(entries);
+ } else if (type == "breakpoints") {
+ for (const { location } of entries) {
+ this.threadActor.removeBreakpoint(location);
+ }
+ }
+
+ return Promise.resolve();
+ },
+
+ /**
+ * These two methods will create and destroy resource watchers
+ * for each resource type. This will end up calling `notifyResourceAvailable`
+ * whenever new resources are observed.
+ *
+ * We have these shortcut methods in this module, because this is called from DevToolsFrameChild
+ * which is a JSM and doesn't have a reference to a DevTools Loader.
+ */
+ _watchTargetResources(resourceTypes) {
+ return Resources.watchResources(this, resourceTypes);
+ },
+
+ _unwatchTargetResources(resourceTypes) {
+ return Resources.unwatchResources(this, resourceTypes);
+ },
+
+ /**
+ * Called by Watchers, when new resources are available.
+ *
+ * @param Array<json> resources
+ * List of all available resources. A resource is a JSON object piped over to the client.
+ * It may contain actor IDs, actor forms, to be manually marshalled by the client.
+ */
+ notifyResourceAvailable(resources) {
+ this._emitResourcesForm("resource-available-form", resources);
+ },
+
+ notifyResourceDestroyed(resources) {
+ this._emitResourcesForm("resource-destroyed-form", resources);
+ },
+
+ notifyResourceUpdated(resources) {
+ this._emitResourcesForm("resource-updated-form", resources);
+ },
+
+ /**
+ * Wrapper around emit for resource forms to bail early after destroy.
+ */
+ _emitResourcesForm(name, resources) {
+ if (resources.length === 0 || this.isDestroyed()) {
+ // Don't try to emit if the resources array is empty or the actor was
+ // destroyed.
+ return;
+ }
+ this.emit(name, resources);
+ },
+ };
+ // Use getOwnPropertyDescriptors in order to prevent calling getter from implementation
+ Object.defineProperties(
+ proto,
+ Object.getOwnPropertyDescriptors(implementation)
+ );
+ proto.initialize = function() {
+ this.notifyResourceAvailable = this.notifyResourceAvailable.bind(this);
+ this.notifyResourceDestroyed = this.notifyResourceDestroyed.bind(this);
+ this.notifyResourceUpdated = this.notifyResourceUpdated.bind(this);
+
+ if (typeof implementation.initialize == "function") {
+ implementation.initialize.apply(this, arguments);
+ }
+ };
+ return ActorClassWithSpec(targetActorSpec, proto);
+};