mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1072080 - Add the ability to define a marshaller for form data. r=jryans,jsantell
This commit is contained in:
parent
6d36f49b0b
commit
2d4dc42029
@ -79,11 +79,8 @@ exports.ShortLongString = Class({
|
||||
})
|
||||
|
||||
exports.LongStringFront = protocol.FrontClass(exports.LongStringActor, {
|
||||
initialize: function(client, form) {
|
||||
// Don't give the form by default, because we're being tricky and it might just
|
||||
// be a string.
|
||||
protocol.Front.prototype.initialize.call(this, client, null);
|
||||
this.form(form);
|
||||
initialize: function(client) {
|
||||
protocol.Front.prototype.initialize.call(this, client);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -94,7 +91,7 @@ exports.LongStringFront = protocol.FrontClass(exports.LongStringActor, {
|
||||
},
|
||||
|
||||
form: function(form) {
|
||||
this.actorID = form.actorID;
|
||||
this.actorID = form.actor;
|
||||
this.initial = form.initial;
|
||||
this.length = form.length;
|
||||
},
|
||||
|
@ -298,7 +298,11 @@ let AudioNodeActor = exports.AudioNodeActor = protocol.ActorClass({
|
||||
let AudioNodeFront = protocol.FrontClass(AudioNodeActor, {
|
||||
initialize: function (client, form) {
|
||||
protocol.Front.prototype.initialize.call(this, client, form);
|
||||
this.manage(this);
|
||||
// if we were manually passed a form, this was created manually and
|
||||
// needs to own itself for now.
|
||||
if (form) {
|
||||
this.manage(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -435,6 +439,8 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
|
||||
return;
|
||||
}
|
||||
this._initialized = false;
|
||||
systemOff("webaudio-node-demise", this._onDestroyNode);
|
||||
|
||||
off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
|
||||
off(this.tabActor, "window-ready", this._onGlobalCreated);
|
||||
this.tabActor = null;
|
||||
|
@ -145,6 +145,7 @@ types.addType = function(name, typeObject={}, options={}) {
|
||||
}
|
||||
|
||||
let type = object.merge({
|
||||
toString() { return "[protocol type:" + name + "]"},
|
||||
name: name,
|
||||
primitive: !(typeObject.read || typeObject.write),
|
||||
read: identityWrite,
|
||||
@ -258,13 +259,15 @@ types.addActorType = function(name) {
|
||||
// if it isn't found.
|
||||
let actorID = typeof(v) === "string" ? v : v.actor;
|
||||
let front = ctx.conn.getActor(actorID);
|
||||
if (front) {
|
||||
front.form(v, detail, ctx);
|
||||
} else {
|
||||
front = new type.frontClass(ctx.conn, v, detail, ctx)
|
||||
if (!front) {
|
||||
front = new type.frontClass(ctx.conn);
|
||||
front.actorID = actorID;
|
||||
ctx.marshallPool().manage(front);
|
||||
}
|
||||
|
||||
v = type.formType(detail).read(v, front, detail);
|
||||
front.form(v, detail, ctx);
|
||||
|
||||
return front;
|
||||
},
|
||||
write: (v, ctx, detail) => {
|
||||
@ -274,12 +277,28 @@ types.addActorType = function(name) {
|
||||
if (!v.actorID) {
|
||||
ctx.marshallPool().manage(v);
|
||||
}
|
||||
return v.form(detail);
|
||||
return type.formType(detail).write(v.form(detail), ctx, detail);
|
||||
}
|
||||
|
||||
// Writing a request from the client side, just send the actor id.
|
||||
return v.actorID;
|
||||
},
|
||||
formType: (detail) => {
|
||||
if (!("formType" in type.actorSpec)) {
|
||||
return types.Primitive;
|
||||
}
|
||||
|
||||
let formAttr = "formType";
|
||||
if (detail) {
|
||||
formAttr += "#" + detail;
|
||||
}
|
||||
|
||||
if (!(formAttr in type.actorSpec)) {
|
||||
throw new Error("No type defined for " + formAttr);
|
||||
}
|
||||
|
||||
return type.actorSpec[formAttr];
|
||||
}
|
||||
}, {
|
||||
// We usually freeze types, but actor types are updated when clients are
|
||||
// created, so don't freeze yet.
|
||||
@ -824,6 +843,8 @@ let Actor = Class({
|
||||
}
|
||||
},
|
||||
|
||||
toString: function() { return "[Actor " + this.typeName + "/" + this.actorID + "]" },
|
||||
|
||||
_sendEvent: function(name, ...args) {
|
||||
if (!this._actorSpec.events.has(name)) {
|
||||
// It's ok to emit events that don't go over the wire.
|
||||
@ -908,13 +929,24 @@ let actorProto = function(actorProto) {
|
||||
methods: [],
|
||||
};
|
||||
|
||||
// Find method specifications attached to prototype properties.
|
||||
// Find method and form specifications attached to prototype properties.
|
||||
for (let name of Object.getOwnPropertyNames(actorProto)) {
|
||||
let desc = Object.getOwnPropertyDescriptor(actorProto, name);
|
||||
if (!desc.value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (name.startsWith("formType")) {
|
||||
if (typeof(desc.value) === "string") {
|
||||
protoSpec[name] = types.getType(desc.value);
|
||||
} else if (desc.value.name && registeredTypes.has(desc.value.name)) {
|
||||
protoSpec[name] = desc.value;
|
||||
} else {
|
||||
// Shorthand for a newly-registered DictType.
|
||||
protoSpec[name] = types.addDictType(actorProto.typeName + "__" + name, desc.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (desc.value._methodSpec) {
|
||||
let frozenSpec = desc.value._methodSpec;
|
||||
let spec = {};
|
||||
@ -1044,8 +1076,14 @@ let Front = Class({
|
||||
initialize: function(conn=null, form=null, detail=null, context=null) {
|
||||
Pool.prototype.initialize.call(this, conn);
|
||||
this._requests = [];
|
||||
|
||||
// protocol.js no longer uses this data in the constructor, only external
|
||||
// uses do. External usage of manually-constructed fronts will be
|
||||
// drastically reduced if we convert the root and tab actors to
|
||||
// protocol.js, in which case this can probably go away.
|
||||
if (form) {
|
||||
this.actorID = form.actor;
|
||||
form = types.getType(this.typeName).formType(detail).read(form, this, detail);
|
||||
this.form(form, detail, context);
|
||||
}
|
||||
},
|
||||
@ -1120,6 +1158,7 @@ let Front = Class({
|
||||
args = event.request.read(packet, this);
|
||||
} catch(ex) {
|
||||
console.error("Error reading event: " + packet.type);
|
||||
console.exception(ex);
|
||||
throw ex;
|
||||
}
|
||||
if (event.pre) {
|
||||
|
@ -234,7 +234,9 @@ let RootFront = protocol.FrontClass(RootActor, {
|
||||
|
||||
getTemporaryChild: protocol.custom(function(id) {
|
||||
if (!this._temporaryHolder) {
|
||||
this._temporaryHolder = this.manage(new protocol.Front(this.conn, {actor: this.actorID + "_temp"}));
|
||||
this._temporaryHolder = protocol.Front(this.conn);
|
||||
this._temporaryHolder.actorID = this.actorID + "_temp";
|
||||
this._temporaryHolder = this.manage(this._temporaryHolder);
|
||||
}
|
||||
return this._getTemporaryChild(id);
|
||||
},{
|
||||
|
160
toolkit/devtools/server/tests/unit/test_protocol_formtype.js
Normal file
160
toolkit/devtools/server/tests/unit/test_protocol_formtype.js
Normal file
@ -0,0 +1,160 @@
|
||||
let protocol = devtools.require("devtools/server/protocol");
|
||||
let {method, Arg, Option, RetVal} = protocol;
|
||||
|
||||
protocol.types.addActorType("child");
|
||||
protocol.types.addActorType("root");
|
||||
|
||||
// The child actor doesn't provide a form description
|
||||
let ChildActor = protocol.ActorClass({
|
||||
typeName: "child",
|
||||
initialize(conn) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
},
|
||||
|
||||
form(detail) {
|
||||
return {
|
||||
actor: this.actorID,
|
||||
extra: "extra"
|
||||
}
|
||||
},
|
||||
|
||||
getChild: method(function() {
|
||||
return this;
|
||||
}, {
|
||||
response: RetVal("child")
|
||||
}),
|
||||
});
|
||||
|
||||
let ChildFront = protocol.FrontClass(ChildActor, {
|
||||
initialize(client) {
|
||||
protocol.Front.prototype.initialize.call(this, client);
|
||||
},
|
||||
|
||||
form(v, ctx, detail) {
|
||||
this.extra = v.extra;
|
||||
}
|
||||
});
|
||||
|
||||
// The root actor does provide a form description.
|
||||
let RootActor = protocol.ActorClass({
|
||||
typeName: "root",
|
||||
initialize(conn) {
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
this.manage(this);
|
||||
this.child = new ChildActor();
|
||||
},
|
||||
|
||||
// Basic form type, relies on implicit DictType creation
|
||||
formType: {
|
||||
childActor: "child"
|
||||
},
|
||||
|
||||
sayHello() {
|
||||
return {
|
||||
from: "root",
|
||||
applicationType: "xpcshell-tests",
|
||||
traits: []
|
||||
}
|
||||
},
|
||||
|
||||
// This detail uses explicit DictType creation
|
||||
"formType#detail1": protocol.types.addDictType("RootActorFormTypeDetail1", {
|
||||
detailItem: "child"
|
||||
}),
|
||||
|
||||
// This detail a string type.
|
||||
"formType#actorid": "string",
|
||||
|
||||
form(detail) {
|
||||
if (detail === "detail1") {
|
||||
return {
|
||||
actor: this.actorID,
|
||||
detailItem: this.child
|
||||
}
|
||||
} else if (detail === "actorid") {
|
||||
return this.actorID;
|
||||
}
|
||||
|
||||
return {
|
||||
actor: this.actorID,
|
||||
childActor: this.child
|
||||
}
|
||||
},
|
||||
|
||||
getDefault: method(function() {
|
||||
return this;
|
||||
}, {
|
||||
response: RetVal("root")
|
||||
}),
|
||||
|
||||
getDetail1: method(function() {
|
||||
return this;
|
||||
}, {
|
||||
response: RetVal("root#detail1")
|
||||
}),
|
||||
|
||||
getDetail2: method(function() {
|
||||
return this;
|
||||
}, {
|
||||
response: {
|
||||
item: RetVal("root#actorid")
|
||||
}
|
||||
}),
|
||||
|
||||
getUnknownDetail: method(function() {
|
||||
return this;
|
||||
}, {
|
||||
response: RetVal("root#unknownDetail")
|
||||
}),
|
||||
});
|
||||
|
||||
let RootFront = protocol.FrontClass(RootActor, {
|
||||
initialize(client) {
|
||||
this.actorID = "root";
|
||||
protocol.Front.prototype.initialize.call(this, client);
|
||||
|
||||
// Root owns itself.
|
||||
this.manage(this);
|
||||
},
|
||||
|
||||
form(v, ctx, detail) {
|
||||
this.lastForm = v;
|
||||
}
|
||||
});
|
||||
|
||||
const run_test = Test(function*() {
|
||||
DebuggerServer.createRootActor = (conn => {
|
||||
return RootActor(conn);
|
||||
});
|
||||
DebuggerServer.init(() => true);
|
||||
|
||||
const connection = DebuggerServer.connectPipe();
|
||||
const conn = new DebuggerClient(connection);
|
||||
const client = Async(conn);
|
||||
|
||||
yield client.connect();
|
||||
|
||||
let rootFront = RootFront(conn);
|
||||
|
||||
// Trigger some methods that return forms.
|
||||
let retval = yield rootFront.getDefault();
|
||||
do_check_true(retval instanceof RootFront);
|
||||
do_check_true(rootFront.lastForm.childActor instanceof ChildFront);
|
||||
|
||||
retval = yield rootFront.getDetail1();
|
||||
do_check_true(retval instanceof RootFront);
|
||||
do_check_true(rootFront.lastForm.detailItem instanceof ChildFront);
|
||||
|
||||
retval = yield rootFront.getDetail2();
|
||||
do_check_true(retval instanceof RootFront);
|
||||
do_check_true(typeof(rootFront.lastForm) === "string");
|
||||
|
||||
// getUnknownDetail should fail, since no typeName is specified.
|
||||
try {
|
||||
yield rootFront.getUnknownDetail();
|
||||
do_check_true(false);
|
||||
} catch(ex) {
|
||||
}
|
||||
|
||||
yield client.close();
|
||||
});
|
@ -65,6 +65,7 @@ support-files =
|
||||
[test_protocol_simple.js]
|
||||
[test_protocol_longstring.js]
|
||||
[test_protocol_children.js]
|
||||
[test_protocol_formtype.js]
|
||||
[test_breakpoint-01.js]
|
||||
[test_register_actor.js]
|
||||
skip-if = toolkit == "gonk"
|
||||
|
Loading…
Reference in New Issue
Block a user