Bug 1813648 - [devtools] Remove ActorClassWithSpec and all its dependencies. r=devtools-reviewers,jdescottes
Some actors weren't using any specification. They now have to pass a bare minimal spec object. Unifying them to the regular Actor interface helps merging constructor with initialize and instantiate all the actors without any code branch. Differential Revision: https://phabricator.services.mozilla.com/D169359
This commit is contained in:
@@ -7,10 +7,9 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
|
||||
class TestActor1 extends Actor {
|
||||
constructor(conn, tab) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "testOne", methods: [] });
|
||||
this.tab = tab;
|
||||
|
||||
this.typeName = "testOne";
|
||||
this.requestTypes = {
|
||||
ping: TestActor1.prototype.onPing,
|
||||
};
|
||||
|
||||
@@ -35,18 +35,18 @@ It has two parts: a spec and an implementation. The spec would go somewhere like
|
||||
The actor implementation would go somewhere like
|
||||
`devtools/server/actors/hello-world.js` and would look like:
|
||||
|
||||
const protocol = require("devtools/shared/protocol");
|
||||
const { Actor } = require("devtools/shared/protocol");
|
||||
const {helloWorldSpec} = require("devtools/shared/specs/hello-world");
|
||||
|
||||
const HelloActor = protocol.ActorClassWithSpec(helloWorldSpec, {
|
||||
initialize: function (conn) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn); // This is the worst part of heritage.
|
||||
},
|
||||
class HelloActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn, helloWorldSpec);
|
||||
}
|
||||
|
||||
sayHello: function () {
|
||||
sayHello() {
|
||||
return "hello";
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// You also need to export the actor class in your module for discovery.
|
||||
exports.HelloActor = HelloActor;
|
||||
@@ -310,15 +310,17 @@ Probably the most common objects that need custom martialing are actors themselv
|
||||
});
|
||||
|
||||
// implementation:
|
||||
const ChildActor = protocol.ActorClassWithSpec(childActorSpec, {
|
||||
initialize: function (conn, id) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
class ChildActor extends Actor {
|
||||
constructor(conn, id) {
|
||||
super(conn, childActorSpec);
|
||||
|
||||
this.greeting = "hello from " + id;
|
||||
},
|
||||
getGreeting: function () {
|
||||
}
|
||||
|
||||
getGreeting() {
|
||||
return this.greeting;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
exports.ChildActor = ChildActor;
|
||||
|
||||
@@ -464,8 +466,8 @@ Here's how the implementation would look:
|
||||
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
// In your protocol.ActorClassWithSpec definition:
|
||||
giveGoodNews: function (news) {
|
||||
// In your Actor class:
|
||||
giveGoodNews(news) {
|
||||
EventEmitter.emit(this, "good-news", news);
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,8 @@ add_task(async function() {
|
||||
const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
class ConnectToFrameTestActor extends Actor {
|
||||
constructor(conn, tab) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "connectToFrameTest", methods: [] });
|
||||
dump("instantiate test actor\n");
|
||||
this.typeName = "connectToFrameTest";
|
||||
this.requestTypes = {
|
||||
hello: this.hello,
|
||||
};
|
||||
|
||||
@@ -11,9 +11,8 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
*/
|
||||
class ErrorActor extends Actor {
|
||||
constructor(conn, tab) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "error", methods: [] });
|
||||
this.tab = tab;
|
||||
this.typeName = "error";
|
||||
this.requestTypes = {
|
||||
error: this.onError,
|
||||
};
|
||||
|
||||
@@ -7,9 +7,8 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
|
||||
class PostInitGlobalActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "postInitGlobal", methods: [] });
|
||||
|
||||
this.typeName = "postInitGlobal";
|
||||
this.requestTypes = {
|
||||
ping: this.onPing,
|
||||
};
|
||||
|
||||
@@ -7,9 +7,8 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
|
||||
class PostInitTargetScopedActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "postInitTargetScoped", methods: [] });
|
||||
|
||||
this.typeName = "postInitTargetScoped";
|
||||
this.requestTypes = {
|
||||
ping: this.onPing,
|
||||
};
|
||||
|
||||
@@ -7,9 +7,8 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
|
||||
class PreInitGlobalActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "preInitGlobal", methods: [] });
|
||||
|
||||
this.typeName = "preInitGlobal";
|
||||
this.requestTypes = {
|
||||
ping: this.onPing,
|
||||
};
|
||||
|
||||
@@ -7,9 +7,8 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
|
||||
class PreInitTargetScopedActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "preInitTargetScoped", methods: [] });
|
||||
|
||||
this.typeName = "preInitTargetScoped";
|
||||
this.requestTypes = {
|
||||
ping: this.onPing,
|
||||
};
|
||||
|
||||
@@ -11,9 +11,8 @@ const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
|
||||
class TestActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "test", methods: [] });
|
||||
|
||||
this.typeName = "test";
|
||||
this.requestTypes = {
|
||||
hello: this.hello,
|
||||
error: this.error,
|
||||
|
||||
@@ -181,9 +181,8 @@ function TestForwardPrefix12OnlyRoot() {
|
||||
const { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
class EchoActor extends Actor {
|
||||
constructor(conn) {
|
||||
super(conn);
|
||||
super(conn, { typeName: "EchoActor", methods: [] });
|
||||
|
||||
this.typeName = "EchoActor";
|
||||
this.requestTypes = {
|
||||
echo: EchoActor.prototype.onEcho,
|
||||
};
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
var {
|
||||
Actor,
|
||||
ActorClassWithSpec,
|
||||
} = require("resource://devtools/shared/protocol/Actor.js");
|
||||
var { Actor } = require("resource://devtools/shared/protocol/Actor.js");
|
||||
var { Pool } = require("resource://devtools/shared/protocol/Pool.js");
|
||||
var {
|
||||
types,
|
||||
@@ -28,7 +25,6 @@ const {
|
||||
exports.Front = Front;
|
||||
exports.Pool = Pool;
|
||||
exports.Actor = Actor;
|
||||
exports.ActorClassWithSpec = ActorClassWithSpec;
|
||||
exports.types = types;
|
||||
exports.generateActorSpec = generateActorSpec;
|
||||
exports.FrontClassWithSpec = FrontClassWithSpec;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const { extend } = require("resource://devtools/shared/extend.js");
|
||||
var { Pool } = require("resource://devtools/shared/protocol/Pool.js");
|
||||
|
||||
/**
|
||||
@@ -28,40 +27,18 @@ exports.actorSpecs = actorSpecs;
|
||||
|
||||
class Actor extends Pool {
|
||||
constructor(conn, spec) {
|
||||
super();
|
||||
super(conn);
|
||||
|
||||
// Actors migrated to ES Classes, passed the specification via the constructor
|
||||
if (spec) {
|
||||
this.typeName = spec.typeName;
|
||||
this.requestTypes = generateRequestTypes(spec);
|
||||
this._actorSpec = spec;
|
||||
}
|
||||
this.initialize(conn);
|
||||
}
|
||||
|
||||
// Existing Actors extending this class expect initialize to contain constructor logic.
|
||||
// Bug 1813648: This method can be folded into constructor once all Actor are migrated to ES Classes.
|
||||
initialize(conn) {
|
||||
// Repeat Pool.constructor here as we can't call it from initialize
|
||||
// This is to be removed once actors switch to es classes and are able to call
|
||||
// Actor's contructor.
|
||||
if (conn) {
|
||||
this.conn = conn;
|
||||
}
|
||||
this.typeName = spec.typeName;
|
||||
|
||||
// Will contain the actor's ID
|
||||
this.actorID = null;
|
||||
|
||||
// When the subclass is still using ActorClassWithSpec (i.e. not ES Classses)
|
||||
// The spec is only registered in actorSpecs.
|
||||
// This codepath can be removed once all actors are using ES Classes.
|
||||
if (!this._actorSpec) {
|
||||
this._actorSpec = actorSpecs.get(Object.getPrototypeOf(this));
|
||||
}
|
||||
this.requestTypes = generateRequestTypes(spec);
|
||||
|
||||
// Forward events to the connection.
|
||||
if (this._actorSpec && this._actorSpec.events) {
|
||||
for (const [name, request] of this._actorSpec.events.entries()) {
|
||||
if (spec.events) {
|
||||
for (const [name, request] of spec.events.entries()) {
|
||||
this.on(name, (...args) => {
|
||||
this._sendEvent(name, request, ...args);
|
||||
});
|
||||
@@ -278,44 +255,3 @@ var generateRequestTypes = function(actorSpec) {
|
||||
return requestTypes;
|
||||
};
|
||||
exports.generateRequestTypes = generateRequestTypes;
|
||||
|
||||
var generateRequestHandlers = function(actorSpec, actorProto) {
|
||||
actorProto.typeName = actorSpec.typeName;
|
||||
|
||||
// Generate request handlers for each method definition
|
||||
actorProto.requestTypes = generateRequestTypes(actorSpec);
|
||||
|
||||
return actorProto;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an actor class for the given actor specification and prototype.
|
||||
*
|
||||
* @param object actorSpec
|
||||
* The actor specification. Must have a 'typeName' property.
|
||||
* @param object actorProto
|
||||
* The actor prototype. Should have method definitions, can have event
|
||||
* definitions.
|
||||
*/
|
||||
// bug 1813648: We can remove this codepath, generateRequestHandlers and actorSpecs WeakMap once all Actors use ES Classes
|
||||
var ActorClassWithSpec = function(actorSpec, actorProto) {
|
||||
if (!actorSpec.typeName) {
|
||||
throw Error("Actor specification must have a typeName member.");
|
||||
}
|
||||
|
||||
// Existing Actors are relying on the initialize instead of constructor methods.
|
||||
const cls = function() {
|
||||
const instance = Object.create(cls.prototype);
|
||||
instance.initialize.apply(instance, arguments);
|
||||
return instance;
|
||||
};
|
||||
cls.prototype = extend(
|
||||
Actor.prototype,
|
||||
generateRequestHandlers(actorSpec, actorProto)
|
||||
);
|
||||
|
||||
actorSpecs.set(cls.prototype, actorSpec);
|
||||
|
||||
return cls;
|
||||
};
|
||||
exports.ActorClassWithSpec = ActorClassWithSpec;
|
||||
|
||||
@@ -17,7 +17,7 @@ add_task(async function() {
|
||||
front.destroy();
|
||||
ok(front.isDestroyed(), "Front is destroyed");
|
||||
|
||||
const actor = new Actor();
|
||||
const actor = new Actor(null, { typeName: "actor", methods: [] });
|
||||
ok(
|
||||
!actor.isDestroyed(),
|
||||
"Blank actor with no actor ID is not considered as destroyed"
|
||||
|
||||
Reference in New Issue
Block a user