summaryrefslogtreecommitdiffstats
path: root/devtools/shared/protocol/Front/FrontClassWithSpec.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/protocol/Front/FrontClassWithSpec.js')
-rw-r--r--devtools/shared/protocol/Front/FrontClassWithSpec.js118
1 files changed, 118 insertions, 0 deletions
diff --git a/devtools/shared/protocol/Front/FrontClassWithSpec.js b/devtools/shared/protocol/Front/FrontClassWithSpec.js
new file mode 100644
index 0000000000..55091be3e4
--- /dev/null
+++ b/devtools/shared/protocol/Front/FrontClassWithSpec.js
@@ -0,0 +1,118 @@
+/* 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";
+
+var { Front } = require("resource://devtools/shared/protocol/Front.js");
+
+/**
+ * Generates request methods as described by the given actor specification on
+ * the given front prototype. Returns the front prototype.
+ */
+var generateRequestMethods = function (actorSpec, frontProto) {
+ if (frontProto._actorSpec) {
+ throw new Error("frontProto called twice on the same front prototype!");
+ }
+
+ frontProto.typeName = actorSpec.typeName;
+
+ // Generate request methods.
+ const methods = actorSpec.methods;
+ methods.forEach(spec => {
+ const name = spec.name;
+
+ frontProto[name] = function (...args) {
+ // If the front is destroyed, the request will not be able to complete.
+ if (this.isDestroyed()) {
+ throw new Error(
+ `Can not send request '${name}' because front '${this.typeName}' is already destroyed.`
+ );
+ }
+
+ const startTime = Cu.now();
+ let packet;
+ try {
+ packet = spec.request.write(args, this);
+ } catch (ex) {
+ console.error("Error writing request: " + name);
+ throw ex;
+ }
+ if (spec.oneway) {
+ // Fire-and-forget oneway packets.
+ this.send(packet);
+ return undefined;
+ }
+
+ return this.request(packet).then(response => {
+ let ret;
+ if (!this.conn) {
+ throw new Error("Missing conn on " + this);
+ }
+ if (this.isDestroyed()) {
+ throw new Error(
+ `Can not interpret '${name}' response because front '${this.typeName}' is already destroyed.`
+ );
+ }
+ try {
+ ret = spec.response.read(response, this);
+ } catch (ex) {
+ console.error("Error reading response to: " + name + "\n" + ex);
+ throw ex;
+ }
+ ChromeUtils.addProfilerMarker(
+ "RDP Front",
+ startTime,
+ `${this.typeName}:${name}()`
+ );
+ return ret;
+ });
+ };
+
+ // Release methods should call the destroy function on return.
+ if (spec.release) {
+ const fn = frontProto[name];
+ frontProto[name] = function (...args) {
+ return fn.apply(this, args).then(result => {
+ this.destroy();
+ return result;
+ });
+ };
+ }
+ });
+
+ // Process event specifications
+ frontProto._clientSpec = {};
+
+ const actorEvents = actorSpec.events;
+ if (actorEvents) {
+ frontProto._clientSpec.events = new Map();
+
+ for (const [name, request] of actorEvents) {
+ frontProto._clientSpec.events.set(request.type, {
+ name,
+ request,
+ });
+ }
+ }
+
+ frontProto._actorSpec = actorSpec;
+
+ return frontProto;
+};
+
+/**
+ * Create a front class for the given actor specification and front prototype.
+ *
+ * @param object actorSpec
+ * The actor specification you're creating a front for.
+ * @param object proto
+ * The object prototype. Must have a 'typeName' property,
+ * should have method definitions, can have event definitions.
+ */
+var FrontClassWithSpec = function (actorSpec) {
+ class OneFront extends Front {}
+ generateRequestMethods(actorSpec, OneFront.prototype);
+ return OneFront;
+};
+exports.FrontClassWithSpec = FrontClassWithSpec;