forked from mirrors/gecko-dev
Bug 1000814 - Cleanup marionette transport.js from DevTools specifics. r=jryans
MozReview-Commit-ID: 5aKwtYeuVs1 --HG-- extra : rebase_source : 5ef5443ea59c13c4e5462308252ca53467acfb7d
This commit is contained in:
parent
ec56fa4e2d
commit
398f1b86db
1 changed files with 1 additions and 404 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
/* global Pipe, ScriptableInputStream, uneval */
|
/* global Pipe, ScriptableInputStream */
|
||||||
|
|
||||||
const CC = Components.Constructor;
|
const CC = Components.Constructor;
|
||||||
|
|
||||||
|
|
@ -15,16 +15,6 @@ const {StreamUtils} =
|
||||||
const {Packet, JSONPacket, BulkPacket} =
|
const {Packet, JSONPacket, BulkPacket} =
|
||||||
ChromeUtils.import("chrome://marionette/content/packets.js", {});
|
ChromeUtils.import("chrome://marionette/content/packets.js", {});
|
||||||
|
|
||||||
const defer = function() {
|
|
||||||
let deferred = {
|
|
||||||
promise: new Promise((resolve, reject) => {
|
|
||||||
deferred.resolve = resolve;
|
|
||||||
deferred.reject = reject;
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
return deferred;
|
|
||||||
};
|
|
||||||
|
|
||||||
const executeSoon = function(func) {
|
const executeSoon = function(func) {
|
||||||
Services.tm.dispatchToMainThread(func);
|
Services.tm.dispatchToMainThread(func);
|
||||||
};
|
};
|
||||||
|
|
@ -531,396 +521,3 @@ DebuggerTransport.prototype = {
|
||||||
this._incoming = null;
|
this._incoming = null;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* An adapter that handles data transfers between the debugger client
|
|
||||||
* and server when they both run in the same process. It presents the
|
|
||||||
* same API as DebuggerTransport, but instead of transmitting serialized
|
|
||||||
* messages across a connection it merely calls the packet dispatcher of
|
|
||||||
* the other side.
|
|
||||||
*
|
|
||||||
* @param {LocalDebuggerTransport} other
|
|
||||||
* The other endpoint for this debugger connection.
|
|
||||||
*
|
|
||||||
* @see {DebuggerTransport}
|
|
||||||
*/
|
|
||||||
function LocalDebuggerTransport(other) {
|
|
||||||
EventEmitter.decorate(this);
|
|
||||||
|
|
||||||
this.other = other;
|
|
||||||
this.hooks = null;
|
|
||||||
|
|
||||||
// A packet number, shared between this and this.other. This isn't
|
|
||||||
// used by the protocol at all, but it makes the packet traces a lot
|
|
||||||
// easier to follow.
|
|
||||||
this._serial = this.other ? this.other._serial : {count: 0};
|
|
||||||
this.close = this.close.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
LocalDebuggerTransport.prototype = {
|
|
||||||
/**
|
|
||||||
* Transmit a message by directly calling the onPacket handler of the other
|
|
||||||
* endpoint.
|
|
||||||
*/
|
|
||||||
send(packet) {
|
|
||||||
this.emit("send", packet);
|
|
||||||
|
|
||||||
let serial = this._serial.count++;
|
|
||||||
if (flags.wantLogging) {
|
|
||||||
// Check 'from' first, as 'echo' packets have both.
|
|
||||||
if (packet.from) {
|
|
||||||
dumpv("Packet " + serial + " sent from " + uneval(packet.from));
|
|
||||||
} else if (packet.to) {
|
|
||||||
dumpv("Packet " + serial + " sent to " + uneval(packet.to));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._deepFreeze(packet);
|
|
||||||
let other = this.other;
|
|
||||||
if (other) {
|
|
||||||
executeSoon(() => {
|
|
||||||
// Avoid the cost of JSON.stringify() when logging is disabled.
|
|
||||||
if (flags.wantLogging) {
|
|
||||||
dumpv(`Received packet ${serial}: ` +
|
|
||||||
JSON.stringify(packet, null, 2));
|
|
||||||
}
|
|
||||||
if (other.hooks) {
|
|
||||||
other.emit("packet", packet);
|
|
||||||
other.hooks.onPacket(packet);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a streaming bulk packet directly to the onBulkPacket handler
|
|
||||||
* of the other endpoint.
|
|
||||||
*
|
|
||||||
* This case is much simpler than the full DebuggerTransport, since
|
|
||||||
* there is no primary stream we have to worry about managing while
|
|
||||||
* we hand it off to others temporarily. Instead, we can just make a
|
|
||||||
* single use pipe and be done with it.
|
|
||||||
*/
|
|
||||||
startBulkSend({actor, type, length}) {
|
|
||||||
this.emit("startbulksend", {actor, type, length});
|
|
||||||
|
|
||||||
let serial = this._serial.count++;
|
|
||||||
|
|
||||||
dumpv("Sent bulk packet " + serial + " for actor " + actor);
|
|
||||||
if (!this.other) {
|
|
||||||
let error = new Error("startBulkSend: other side of transport missing");
|
|
||||||
return Promise.reject(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
let pipe = new Pipe(true, true, 0, 0, null);
|
|
||||||
|
|
||||||
executeSoon(() => {
|
|
||||||
dumpv("Received bulk packet " + serial);
|
|
||||||
if (!this.other.hooks) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Receiver
|
|
||||||
let deferred = defer();
|
|
||||||
let packet = {
|
|
||||||
actor,
|
|
||||||
type,
|
|
||||||
length,
|
|
||||||
copyTo: (output) => {
|
|
||||||
let copying =
|
|
||||||
StreamUtils.copyStream(pipe.inputStream, output, length);
|
|
||||||
deferred.resolve(copying);
|
|
||||||
return copying;
|
|
||||||
},
|
|
||||||
stream: pipe.inputStream,
|
|
||||||
done: deferred,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.other.emit("bulkpacket", packet);
|
|
||||||
this.other.hooks.onBulkPacket(packet);
|
|
||||||
|
|
||||||
// Await the result of reading from the stream
|
|
||||||
deferred.promise.then(() => pipe.inputStream.close(), this.close);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sender
|
|
||||||
let sendDeferred = defer();
|
|
||||||
|
|
||||||
// The remote transport is not capable of resolving immediately here,
|
|
||||||
// so we shouldn't be able to either.
|
|
||||||
executeSoon(() => {
|
|
||||||
let copyDeferred = defer();
|
|
||||||
|
|
||||||
sendDeferred.resolve({
|
|
||||||
copyFrom: (input) => {
|
|
||||||
let copying =
|
|
||||||
StreamUtils.copyStream(input, pipe.outputStream, length);
|
|
||||||
copyDeferred.resolve(copying);
|
|
||||||
return copying;
|
|
||||||
},
|
|
||||||
stream: pipe.outputStream,
|
|
||||||
done: copyDeferred,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Await the result of writing to the stream
|
|
||||||
copyDeferred.promise.then(() => pipe.outputStream.close(), this.close);
|
|
||||||
});
|
|
||||||
|
|
||||||
return sendDeferred.promise;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the transport.
|
|
||||||
*/
|
|
||||||
close() {
|
|
||||||
this.emit("close");
|
|
||||||
|
|
||||||
if (this.other) {
|
|
||||||
// Remove the reference to the other endpoint before calling close(), to
|
|
||||||
// avoid infinite recursion.
|
|
||||||
let other = this.other;
|
|
||||||
this.other = null;
|
|
||||||
other.close();
|
|
||||||
}
|
|
||||||
if (this.hooks) {
|
|
||||||
try {
|
|
||||||
this.hooks.onClosed();
|
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
}
|
|
||||||
this.hooks = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An empty method for emulating the DebuggerTransport API.
|
|
||||||
*/
|
|
||||||
ready() {},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function that makes an object fully immutable.
|
|
||||||
*/
|
|
||||||
_deepFreeze(object) {
|
|
||||||
Object.freeze(object);
|
|
||||||
for (let prop in object) {
|
|
||||||
// Freeze the properties that are objects, not on the prototype,
|
|
||||||
// and not already frozen. Note that this might leave an unfrozen
|
|
||||||
// reference somewhere in the object if there is an already frozen
|
|
||||||
// object containing an unfrozen object.
|
|
||||||
if (object.hasOwnProperty(prop) && typeof object === "object" &&
|
|
||||||
!Object.isFrozen(object)) {
|
|
||||||
this._deepFreeze(object[prop]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A transport for the debugging protocol that uses nsIMessageManagers to
|
|
||||||
* exchange packets with servers running in child processes.
|
|
||||||
*
|
|
||||||
* In the parent process, <var>mm</var> should be the nsIMessageSender
|
|
||||||
* for the child process. In a child process, |mm| should be the child
|
|
||||||
* process message manager, which sends packets to the parent.
|
|
||||||
*
|
|
||||||
* <var>prefix</var> is a string included in the message names, to
|
|
||||||
* distinguish multiple servers running in the same child process.
|
|
||||||
*
|
|
||||||
* This transport exchanges messages named <tt>debug:PREFIX:packet</tt>,
|
|
||||||
* where <tt>PREFIX</tt> is <var>prefix</var>, whose data is the protocol
|
|
||||||
* packet.
|
|
||||||
*/
|
|
||||||
function ChildDebuggerTransport(mm, prefix) {
|
|
||||||
EventEmitter.decorate(this);
|
|
||||||
|
|
||||||
this._mm = mm;
|
|
||||||
this._messageName = "debug:" + prefix + ":packet";
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* To avoid confusion, we use 'message' to mean something that
|
|
||||||
* nsIMessageSender conveys, and 'packet' to mean a remote debugging
|
|
||||||
* protocol packet.
|
|
||||||
*/
|
|
||||||
ChildDebuggerTransport.prototype = {
|
|
||||||
constructor: ChildDebuggerTransport,
|
|
||||||
|
|
||||||
hooks: null,
|
|
||||||
|
|
||||||
_addListener() {
|
|
||||||
this._mm.addMessageListener(this._messageName, this);
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeListener() {
|
|
||||||
try {
|
|
||||||
this._mm.removeMessageListener(this._messageName, this);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.result != Cr.NS_ERROR_NULL_POINTER) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
// In some cases, especially when using messageManagers in non-e10s
|
|
||||||
// mode, we reach this point with a dead messageManager which only
|
|
||||||
// throws errors but does not seem to indicate in any other way that
|
|
||||||
// it is dead.
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
ready() {
|
|
||||||
this._addListener();
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this._removeListener();
|
|
||||||
this.emit("close");
|
|
||||||
this.hooks.onClosed();
|
|
||||||
},
|
|
||||||
|
|
||||||
receiveMessage({data}) {
|
|
||||||
this.emit("packet", data);
|
|
||||||
this.hooks.onPacket(data);
|
|
||||||
},
|
|
||||||
|
|
||||||
send(packet) {
|
|
||||||
this.emit("send", packet);
|
|
||||||
try {
|
|
||||||
this._mm.sendAsyncMessage(this._messageName, packet);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.result != Cr.NS_ERROR_NULL_POINTER) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
// In some cases, especially when using messageManagers in non-e10s
|
|
||||||
// mode, we reach this point with a dead messageManager which only
|
|
||||||
// throws errors but does not seem to indicate in any other way that
|
|
||||||
// it is dead.
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
startBulkSend() {
|
|
||||||
throw new Error("Can't send bulk data to child processes.");
|
|
||||||
},
|
|
||||||
|
|
||||||
swapBrowser(mm) {
|
|
||||||
this._removeListener();
|
|
||||||
this._mm = mm;
|
|
||||||
this._addListener();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// WorkerDebuggerTransport is defined differently depending on whether we are
|
|
||||||
// on the main thread or a worker thread. In the former case, we are required
|
|
||||||
// by the devtools loader, and isWorker will be false. Otherwise, we are
|
|
||||||
// required by the worker loader, and isWorker will be true.
|
|
||||||
//
|
|
||||||
// Each worker debugger supports only a single connection to the main thread.
|
|
||||||
// However, its theoretically possible for multiple servers to connect to the
|
|
||||||
// same worker. Consequently, each transport has a connection id, to allow
|
|
||||||
// messages from multiple connections to be multiplexed on a single channel.
|
|
||||||
|
|
||||||
if (!this.isWorker) {
|
|
||||||
// Main thread
|
|
||||||
(function() {
|
|
||||||
/**
|
|
||||||
* A transport that uses a WorkerDebugger to send packets from the main
|
|
||||||
* thread to a worker thread.
|
|
||||||
*
|
|
||||||
* @class WorkerDebuggerTransport
|
|
||||||
*/
|
|
||||||
function WorkerDebuggerTransport(dbg, id) {
|
|
||||||
this._dbg = dbg;
|
|
||||||
this._id = id;
|
|
||||||
this.onMessage = this._onMessage.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkerDebuggerTransport.prototype = {
|
|
||||||
constructor: WorkerDebuggerTransport,
|
|
||||||
|
|
||||||
ready() {
|
|
||||||
this._dbg.addListener(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this._dbg.removeListener(this);
|
|
||||||
if (this.hooks) {
|
|
||||||
this.hooks.onClosed();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
send(packet) {
|
|
||||||
this._dbg.postMessage(JSON.stringify({
|
|
||||||
type: "message",
|
|
||||||
id: this._id,
|
|
||||||
message: packet,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
startBulkSend() {
|
|
||||||
throw new Error("Can't send bulk data from worker threads!");
|
|
||||||
},
|
|
||||||
|
|
||||||
_onMessage(message) {
|
|
||||||
let packet = JSON.parse(message);
|
|
||||||
if (packet.type !== "message" || packet.id !== this._id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.hooks) {
|
|
||||||
this.hooks.onPacket(packet.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
} else {
|
|
||||||
// Worker thread
|
|
||||||
(function() {
|
|
||||||
/**
|
|
||||||
* A transport that uses a WorkerDebuggerGlobalScope to send packets
|
|
||||||
* from a worker thread to the main thread.
|
|
||||||
*
|
|
||||||
* @class WorkerDebuggerTransportThread
|
|
||||||
*/
|
|
||||||
function WorkerDebuggerTransport(scope, id) {
|
|
||||||
this._scope = scope;
|
|
||||||
this._id = id;
|
|
||||||
this._onMessage = this._onMessage.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
WorkerDebuggerTransport.prototype = {
|
|
||||||
constructor: WorkerDebuggerTransport,
|
|
||||||
|
|
||||||
ready() {
|
|
||||||
this._scope.addEventListener("message", this._onMessage);
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this._scope.removeEventListener("message", this._onMessage);
|
|
||||||
if (this.hooks) {
|
|
||||||
this.hooks.onClosed();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
send(packet) {
|
|
||||||
this._scope.postMessage(JSON.stringify({
|
|
||||||
type: "message",
|
|
||||||
id: this._id,
|
|
||||||
message: packet,
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
startBulkSend() {
|
|
||||||
throw new Error("Can't send bulk data from worker threads!");
|
|
||||||
},
|
|
||||||
|
|
||||||
_onMessage(event) {
|
|
||||||
let packet = JSON.parse(event.data);
|
|
||||||
if (packet.type !== "message" || packet.id !== this._id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.hooks) {
|
|
||||||
this.hooks.onPacket(packet.message);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
}).call(this);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue