119 lines
3 KiB
JavaScript
119 lines
3 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";
|
|
|
|
var {
|
|
findPlaceholders,
|
|
getPath,
|
|
} = require("resource://devtools/shared/protocol/utils.js");
|
|
var { types } = require("resource://devtools/shared/protocol/types.js");
|
|
|
|
/**
|
|
* Manages a response template.
|
|
*
|
|
* @param object template
|
|
* The response template.
|
|
* @construcor
|
|
*/
|
|
var Response = function (template = {}) {
|
|
this.template = template;
|
|
if (this.template instanceof RetVal && this.template.isArrayType()) {
|
|
throw Error("Arrays should be wrapped in objects");
|
|
}
|
|
|
|
const placeholders = findPlaceholders(template, RetVal);
|
|
if (placeholders.length > 1) {
|
|
throw Error("More than one RetVal specified in response");
|
|
}
|
|
const placeholder = placeholders.shift();
|
|
if (placeholder) {
|
|
this.retVal = placeholder.placeholder;
|
|
this.path = placeholder.path;
|
|
}
|
|
};
|
|
|
|
Response.prototype = {
|
|
/**
|
|
* Write a response for the given return value.
|
|
*
|
|
* @param val ret
|
|
* The return value.
|
|
* @param object ctx
|
|
* The object writing the response.
|
|
*/
|
|
write(ret, ctx) {
|
|
// Consider that `template` is either directly a `RetVal`,
|
|
// or a dictionary with may be one `RetVal`.
|
|
if (this.template instanceof RetVal) {
|
|
return this.template.write(ret, ctx);
|
|
}
|
|
const result = {};
|
|
for (const key in this.template) {
|
|
const value = this.template[key];
|
|
if (value instanceof RetVal) {
|
|
result[key] = value.write(ret, ctx);
|
|
} else {
|
|
throw new Error(
|
|
"Response can only be a `RetVal` instance or an object " +
|
|
"with one property being a `RetVal` instance."
|
|
);
|
|
}
|
|
}
|
|
return result;
|
|
},
|
|
|
|
/**
|
|
* Read a return value from the given response.
|
|
*
|
|
* @param object packet
|
|
* The response packet.
|
|
* @param object ctx
|
|
* The object reading the response.
|
|
*/
|
|
read(packet, ctx) {
|
|
if (!this.retVal) {
|
|
return undefined;
|
|
}
|
|
const v = getPath(packet, this.path);
|
|
return this.retVal.read(v, ctx);
|
|
},
|
|
};
|
|
|
|
exports.Response = Response;
|
|
|
|
/**
|
|
* Placeholder for return values in a response template.
|
|
*
|
|
* @param type type
|
|
* The return value should be marshalled as this type.
|
|
*/
|
|
var RetVal = function (type) {
|
|
this._type = type;
|
|
// Prevent force loading all RetVal types by accessing it only when needed
|
|
loader.lazyGetter(this, "type", function () {
|
|
return types.getType(type);
|
|
});
|
|
};
|
|
|
|
RetVal.prototype = {
|
|
write(v, ctx) {
|
|
return this.type.write(v, ctx);
|
|
},
|
|
|
|
read(v, ctx) {
|
|
return this.type.read(v, ctx);
|
|
},
|
|
|
|
isArrayType() {
|
|
// `_type` should always be a string, but a few incorrect RetVal calls
|
|
// pass `0`. See Bug 1677703.
|
|
return typeof this._type === "string" && this._type.startsWith("array:");
|
|
},
|
|
};
|
|
|
|
// Outside of protocol.js, RetVal is called as factory method, without the new keyword.
|
|
exports.RetVal = function (type) {
|
|
return new RetVal(type);
|
|
};
|