Bug 1403895 - split main.js in mulitple files; r=ochameau.

This patch keeps the main.js file so  we don't have to change
consumer code that uses objects fom this file.

MozReview-Commit-ID: KhFoPPApE2L

--HG--
rename : devtools/shared/client/main.js => devtools/shared/client/addon-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/array-buffer-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/breakpoint-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/constants.js
rename : devtools/shared/client/main.js => devtools/shared/client/debugger-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/environment-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/event-source.js
rename : devtools/shared/client/main.js => devtools/shared/client/long-string-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/object-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/property-iterator-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/root-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/source-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/symbol-iterator-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/tab-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/thread-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/trace-client.js
rename : devtools/shared/client/main.js => devtools/shared/client/worker-client.js
extra : rebase_source : e5f6978cb3e543af7073e234320af1f3afde356d
This commit is contained in:
Nicolas Chevobbe 2017-09-28 17:29:55 +02:00
Родитель cd53268372
Коммит 320161a4ad
19 изменённых файлов: 3652 добавлений и 3417 удалений

Просмотреть файл

@ -0,0 +1,43 @@
/* 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";
const {DebuggerClient} = require("./debugger-client");
function AddonClient(client, actor) {
this._client = client;
this._actor = actor;
this.request = this._client.request;
this.events = [];
}
AddonClient.prototype = {
get actor() {
return this._actor;
},
get _transport() {
return this._client._transport;
},
/**
* Detach the client from the addon actor.
*
* @param function onResponse
* Called with the response packet.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function (response) {
if (this._client.activeAddon === this) {
this._client.activeAddon = null;
}
this._client.unregisterClient(this);
return response;
},
})
};
module.exports = AddonClient;

Просмотреть файл

@ -0,0 +1,43 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
/**
* A ArrayBufferClient provides a way to access ArrayBuffer from the
* debugger server.
*
* @param client DebuggerClient
* The debugger client parent.
* @param grip Object
* A pause-lifetime ArrayBuffer grip returned by the protocol.
*/
function ArrayBufferClient(client, grip) {
this._grip = grip;
this._client = client;
this.request = this._client.request;
}
ArrayBufferClient.prototype = {
get actor() {
return this._grip.actor;
},
get length() {
return this._grip.length;
},
get _transport() {
return this._client._transport;
},
valid: true,
slice: DebuggerClient.requester({
type: "slice",
start: arg(0),
count: arg(1)
}),
};
module.exports = ArrayBufferClient;

Просмотреть файл

@ -0,0 +1,134 @@
/* 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";
const { Cu } = require("chrome");
const promise = Cu.import("resource://devtools/shared/deprecated-sync-thenables.js", {}).Promise;
const eventSource = require("./event-source");
const {DebuggerClient} = require("./debugger-client");
/**
* Breakpoint clients are used to remove breakpoints that are no longer used.
*
* @param client DebuggerClient
* The debugger client parent.
* @param sourceClient SourceClient
* The source where this breakpoint exists
* @param actor string
* The actor ID for this breakpoint.
* @param location object
* The location of the breakpoint. This is an object with two properties:
* url and line.
* @param condition string
* The conditional expression of the breakpoint
*/
function BreakpointClient(client, sourceClient, actor, location, condition) {
this._client = client;
this._actor = actor;
this.location = location;
this.location.actor = sourceClient.actor;
this.location.url = sourceClient.url;
this.source = sourceClient;
this.request = this._client.request;
// The condition property should only exist if it's a truthy value
if (condition) {
this.condition = condition;
}
}
BreakpointClient.prototype = {
_actor: null,
get actor() {
return this._actor;
},
get _transport() {
return this._client._transport;
},
/**
* Remove the breakpoint from the server.
*/
remove: DebuggerClient.requester({
type: "delete"
}),
/**
* Determines if this breakpoint has a condition
*/
hasCondition: function () {
let root = this._client.mainRoot;
// XXX bug 990137: We will remove support for client-side handling of
// conditional breakpoints
if (root.traits.conditionalBreakpoints) {
return "condition" in this;
}
return "conditionalExpression" in this;
},
/**
* Get the condition of this breakpoint. Currently we have to
* support locally emulated conditional breakpoints until the
* debugger servers are updated (see bug 990137). We used a
* different property when moving it server-side to ensure that we
* are testing the right code.
*/
getCondition: function () {
let root = this._client.mainRoot;
if (root.traits.conditionalBreakpoints) {
return this.condition;
}
return this.conditionalExpression;
},
/**
* Set the condition of this breakpoint
*/
setCondition: function (gThreadClient, condition) {
let root = this._client.mainRoot;
let deferred = promise.defer();
if (root.traits.conditionalBreakpoints) {
let info = {
line: this.location.line,
column: this.location.column,
condition: condition
};
// Remove the current breakpoint and add a new one with the
// condition.
this.remove(response => {
if (response && response.error) {
deferred.reject(response);
return;
}
this.source.setBreakpoint(info, (resp, newBreakpoint) => {
if (resp && resp.error) {
deferred.reject(resp);
} else {
deferred.resolve(newBreakpoint);
}
});
});
} else {
// The property shouldn't even exist if the condition is blank
if (condition === "") {
delete this.conditionalExpression;
} else {
this.conditionalExpression = condition;
}
deferred.resolve(this);
}
return deferred.promise;
}
};
eventSource(BreakpointClient.prototype);
module.exports = BreakpointClient;

Просмотреть файл

@ -0,0 +1,71 @@
/* 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";
/**
* Set of protocol messages that affect thread state, and the
* state the actor is in after each message.
*/
const ThreadStateTypes = {
"paused": "paused",
"resumed": "attached",
"detached": "detached",
"running": "attached"
};
/**
* Set of protocol messages that are sent by the server without a prior request
* by the client.
*/
const UnsolicitedNotifications = {
"consoleAPICall": "consoleAPICall",
"eventNotification": "eventNotification",
"fileActivity": "fileActivity",
"lastPrivateContextExited": "lastPrivateContextExited",
"logMessage": "logMessage",
"networkEvent": "networkEvent",
"networkEventUpdate": "networkEventUpdate",
"newGlobal": "newGlobal",
"newScript": "newScript",
"tabDetached": "tabDetached",
"tabListChanged": "tabListChanged",
"reflowActivity": "reflowActivity",
"addonListChanged": "addonListChanged",
"workerListChanged": "workerListChanged",
"serviceWorkerRegistrationListChanged": "serviceWorkerRegistrationList",
"tabNavigated": "tabNavigated",
"frameUpdate": "frameUpdate",
"pageError": "pageError",
"documentLoad": "documentLoad",
"enteredFrame": "enteredFrame",
"exitedFrame": "exitedFrame",
"appOpen": "appOpen",
"appClose": "appClose",
"appInstall": "appInstall",
"appUninstall": "appUninstall",
"evaluationResult": "evaluationResult",
"newSource": "newSource",
"updatedSource": "updatedSource",
"inspectObject": "inspectObject"
};
/**
* Set of pause types that are sent by the server and not as an immediate
* response to a client request.
*/
const UnsolicitedPauses = {
"resumeLimit": "resumeLimit",
"debuggerStatement": "debuggerStatement",
"breakpoint": "breakpoint",
"DOMEvent": "DOMEvent",
"watchpoint": "watchpoint",
"exception": "exception"
};
module.exports = {
ThreadStateTypes,
UnsolicitedNotifications,
UnsolicitedPauses,
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,54 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
const eventSource = require("./event-source");
/**
* Environment clients are used to manipulate the lexical environment actors.
*
* @param client DebuggerClient
* The debugger client parent.
* @param form Object
* The form sent across the remote debugging protocol.
*/
function EnvironmentClient(client, form) {
this._client = client;
this._form = form;
this.request = this._client.request;
}
exports.EnvironmentClient = EnvironmentClient;
EnvironmentClient.prototype = {
get actor() {
return this._form.actor;
},
get _transport() {
return this._client._transport;
},
/**
* Fetches the bindings introduced by this lexical environment.
*/
getBindings: DebuggerClient.requester({
type: "bindings"
}),
/**
* Changes the value of the identifier whose name is name (a string) to that
* represented by value (a grip).
*/
assign: DebuggerClient.requester({
type: "assign",
name: arg(0),
value: arg(1)
})
};
eventSource(EnvironmentClient.prototype);
module.exports = EnvironmentClient;

Просмотреть файл

@ -0,0 +1,126 @@
/* 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";
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
/**
* TODO: Get rid of this API in favor of EventTarget (bug 1042642)
*
* Add simple event notification to a prototype object. Any object that has
* some use for event notifications or the observer pattern in general can be
* augmented with the necessary facilities by passing its prototype to this
* function.
*
* @param proto object
* The prototype object that will be modified.
*/
function eventSource(proto) {
/**
* Add a listener to the event source for a given event.
*
* @param name string
* The event to listen for.
* @param listener function
* Called when the event is fired. If the same listener
* is added more than once, it will be called once per
* addListener call.
*/
proto.addListener = function (name, listener) {
if (typeof listener != "function") {
throw TypeError("Listeners must be functions.");
}
if (!this._listeners) {
this._listeners = {};
}
this._getListeners(name).push(listener);
};
/**
* Add a listener to the event source for a given event. The
* listener will be removed after it is called for the first time.
*
* @param name string
* The event to listen for.
* @param listener function
* Called when the event is fired.
*/
proto.addOneTimeListener = function (name, listener) {
let l = (...args) => {
this.removeListener(name, l);
listener.apply(null, args);
};
this.addListener(name, l);
};
/**
* Remove a listener from the event source previously added with
* addListener().
*
* @param name string
* The event name used during addListener to add the listener.
* @param listener function
* The callback to remove. If addListener was called multiple
* times, all instances will be removed.
*/
proto.removeListener = function (name, listener) {
if (!this._listeners || (listener && !this._listeners[name])) {
return;
}
if (!listener) {
this._listeners[name] = [];
} else {
this._listeners[name] =
this._listeners[name].filter(l => l != listener);
}
};
/**
* Returns the listeners for the specified event name. If none are defined it
* initializes an empty list and returns that.
*
* @param name string
* The event name.
*/
proto._getListeners = function (name) {
if (name in this._listeners) {
return this._listeners[name];
}
this._listeners[name] = [];
return this._listeners[name];
};
/**
* Notify listeners of an event.
*
* @param name string
* The event to fire.
* @param arguments
* All arguments will be passed along to the listeners,
* including the name argument.
*/
proto.emit = function () {
if (!this._listeners) {
return;
}
let name = arguments[0];
let listeners = this._getListeners(name).slice(0);
for (let listener of listeners) {
try {
listener.apply(null, arguments);
} catch (e) {
// Prevent a bad listener from interfering with the others.
DevToolsUtils.reportException("notify event '" + name + "'", e);
}
}
};
}
module.exports = eventSource;

Просмотреть файл

@ -0,0 +1,56 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
/**
* A LongStringClient provides a way to access "very long" strings from the
* debugger server.
*
* @param client DebuggerClient
* The debugger client parent.
* @param grip Object
* A pause-lifetime long string grip returned by the protocol.
*/
function LongStringClient(client, grip) {
this._grip = grip;
this._client = client;
this.request = this._client.request;
}
LongStringClient.prototype = {
get actor() {
return this._grip.actor;
},
get length() {
return this._grip.length;
},
get initial() {
return this._grip.initial;
},
get _transport() {
return this._client._transport;
},
valid: true,
/**
* Get the substring of this LongString from start to end.
*
* @param start Number
* The starting index.
* @param end Number
* The ending index.
* @param callback Function
* The function called when we receive the substring.
*/
substring: DebuggerClient.requester({
type: "substring",
start: arg(0),
end: arg(1)
}),
};
module.exports = LongStringClient;

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -5,6 +5,23 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'addon-client.js',
'array-buffer-client.js',
'breakpoint-client.js',
'connection-manager.js',
'constants.js',
'debugger-client.js',
'environment-client.js',
'event-source.js',
'long-string-client.js',
'main.js',
)
'object-client.js',
'property-iterator-client.js',
'root-client.js',
'source-client.js',
'symbol-iterator-client.js',
'tab-client.js',
'thread-client.js',
'trace-client.js',
'worker-client.js',
)

Просмотреть файл

@ -0,0 +1,278 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
loader.lazyRequireGetter(this, "PropertyIteratorClient", "devtools/shared/client/property-iterator-client");
loader.lazyRequireGetter(this, "SymbolIteratorClient", "devtools/shared/client/symbol-iterator-client");
/**
* Grip clients are used to retrieve information about the relevant object.
*
* @param client DebuggerClient
* The debugger client parent.
* @param grip object
* A pause-lifetime object grip returned by the protocol.
*/
function ObjectClient(client, grip) {
this._grip = grip;
this._client = client;
this.request = this._client.request;
}
ObjectClient.prototype = {
get actor() {
return this._grip.actor;
},
get _transport() {
return this._client._transport;
},
valid: true,
get isFrozen() {
return this._grip.frozen;
},
get isSealed() {
return this._grip.sealed;
},
get isExtensible() {
return this._grip.extensible;
},
getDefinitionSite: DebuggerClient.requester({
type: "definitionSite"
}, {
before: function (packet) {
if (this._grip.class != "Function") {
throw new Error("getDefinitionSite is only valid for function grips.");
}
return packet;
}
}),
/**
* Request the names of a function's formal parameters.
*
* @param onResponse function
* Called with an object of the form:
* { parameterNames:[<parameterName>, ...] }
* where each <parameterName> is the name of a parameter.
*/
getParameterNames: DebuggerClient.requester({
type: "parameterNames"
}, {
before: function (packet) {
if (this._grip.class !== "Function") {
throw new Error("getParameterNames is only valid for function grips.");
}
return packet;
},
}),
/**
* Request the names of the properties defined on the object and not its
* prototype.
*
* @param onResponse function Called with the request's response.
*/
getOwnPropertyNames: DebuggerClient.requester({
type: "ownPropertyNames"
}),
/**
* Request the prototype and own properties of the object.
*
* @param onResponse function Called with the request's response.
*/
getPrototypeAndProperties: DebuggerClient.requester({
type: "prototypeAndProperties"
}),
/**
* Request a PropertyIteratorClient instance to ease listing
* properties for this object.
*
* @param options Object
* A dictionary object with various boolean attributes:
* - ignoreIndexedProperties Boolean
* If true, filters out Array items.
* e.g. properties names between `0` and `object.length`.
* - ignoreNonIndexedProperties Boolean
* If true, filters out items that aren't array items
* e.g. properties names that are not a number between `0`
* and `object.length`.
* - sort Boolean
* If true, the iterator will sort the properties by name
* before dispatching them.
* @param onResponse function Called with the client instance.
*/
enumProperties: DebuggerClient.requester({
type: "enumProperties",
options: arg(0)
}, {
after: function (response) {
if (response.iterator) {
return { iterator: new PropertyIteratorClient(this._client, response.iterator) };
}
return response;
},
}),
/**
* Request a PropertyIteratorClient instance to enumerate entries in a
* Map/Set-like object.
*
* @param onResponse function Called with the request's response.
*/
enumEntries: DebuggerClient.requester({
type: "enumEntries"
}, {
before: function (packet) {
if (!["Map", "WeakMap", "Set", "WeakSet"].includes(this._grip.class)) {
throw new Error("enumEntries is only valid for Map/Set-like grips.");
}
return packet;
},
after: function (response) {
if (response.iterator) {
return {
iterator: new PropertyIteratorClient(this._client, response.iterator)
};
}
return response;
}
}),
/**
* Request a SymbolIteratorClient instance to enumerate symbols in an object.
*
* @param onResponse function Called with the request's response.
*/
enumSymbols: DebuggerClient.requester({
type: "enumSymbols"
}, {
before: function (packet) {
if (this._grip.type !== "object") {
throw new Error("enumSymbols is only valid for objects grips.");
}
return packet;
},
after: function (response) {
if (response.iterator) {
return {
iterator: new SymbolIteratorClient(this._client, response.iterator)
};
}
return response;
}
}),
/**
* Request the property descriptor of the object's specified property.
*
* @param name string The name of the requested property.
* @param onResponse function Called with the request's response.
*/
getProperty: DebuggerClient.requester({
type: "property",
name: arg(0)
}),
/**
* Request the prototype of the object.
*
* @param onResponse function Called with the request's response.
*/
getPrototype: DebuggerClient.requester({
type: "prototype"
}),
/**
* Request the display string of the object.
*
* @param onResponse function Called with the request's response.
*/
getDisplayString: DebuggerClient.requester({
type: "displayString"
}),
/**
* Request the scope of the object.
*
* @param onResponse function Called with the request's response.
*/
getScope: DebuggerClient.requester({
type: "scope"
}, {
before: function (packet) {
if (this._grip.class !== "Function") {
throw new Error("scope is only valid for function grips.");
}
return packet;
},
}),
/**
* Request the promises directly depending on the current promise.
*/
getDependentPromises: DebuggerClient.requester({
type: "dependentPromises"
}, {
before: function (packet) {
if (this._grip.class !== "Promise") {
throw new Error("getDependentPromises is only valid for promise " +
"grips.");
}
return packet;
}
}),
/**
* Request the stack to the promise's allocation point.
*/
getPromiseAllocationStack: DebuggerClient.requester({
type: "allocationStack"
}, {
before: function (packet) {
if (this._grip.class !== "Promise") {
throw new Error("getAllocationStack is only valid for promise grips.");
}
return packet;
}
}),
/**
* Request the stack to the promise's fulfillment point.
*/
getPromiseFulfillmentStack: DebuggerClient.requester({
type: "fulfillmentStack"
}, {
before: function (packet) {
if (this._grip.class !== "Promise") {
throw new Error("getPromiseFulfillmentStack is only valid for " +
"promise grips.");
}
return packet;
}
}),
/**
* Request the stack to the promise's rejection point.
*/
getPromiseRejectionStack: DebuggerClient.requester({
type: "rejectionStack"
}, {
before: function (packet) {
if (this._grip.class !== "Promise") {
throw new Error("getPromiseRejectionStack is only valid for " +
"promise grips.");
}
return packet;
}
})
};
module.exports = ObjectClient;

Просмотреть файл

@ -0,0 +1,81 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
/**
* A PropertyIteratorClient provides a way to access to property names and
* values of an object efficiently, slice by slice.
* Note that the properties can be sorted in the backend,
* this is controled while creating the PropertyIteratorClient
* from ObjectClient.enumProperties.
*
* @param client DebuggerClient
* The debugger client parent.
* @param grip Object
* A PropertyIteratorActor grip returned by the protocol via
* TabActor.enumProperties request.
*/
function PropertyIteratorClient(client, grip) {
this._grip = grip;
this._client = client;
this.request = this._client.request;
}
PropertyIteratorClient.prototype = {
get actor() {
return this._grip.actor;
},
/**
* Get the total number of properties available in the iterator.
*/
get count() {
return this._grip.count;
},
/**
* Get one or more property names that correspond to the positions in the
* indexes parameter.
*
* @param indexes Array
* An array of property indexes.
* @param callback Function
* The function called when we receive the property names.
*/
names: DebuggerClient.requester({
type: "names",
indexes: arg(0)
}, {}),
/**
* Get a set of following property value(s).
*
* @param start Number
* The index of the first property to fetch.
* @param count Number
* The number of properties to fetch.
* @param callback Function
* The function called when we receive the property values.
*/
slice: DebuggerClient.requester({
type: "slice",
start: arg(0),
count: arg(1)
}, {}),
/**
* Get all the property values.
*
* @param callback Function
* The function called when we receive the property values.
*/
all: DebuggerClient.requester({
type: "all"
}, {}),
};
module.exports = PropertyIteratorClient;

Просмотреть файл

@ -0,0 +1,179 @@
/* 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";
const { Ci } = require("chrome");
const {DebuggerClient} = require("./debugger-client");
/**
* A RootClient object represents a root actor on the server. Each
* DebuggerClient keeps a RootClient instance representing the root actor
* for the initial connection; DebuggerClient's 'listTabs' and
* 'listChildProcesses' methods forward to that root actor.
*
* @param client object
* The client connection to which this actor belongs.
* @param greeting string
* The greeting packet from the root actor we're to represent.
*
* Properties of a RootClient instance:
*
* @property actor string
* The name of this child's root actor.
* @property applicationType string
* The application type, as given in the root actor's greeting packet.
* @property traits object
* The traits object, as given in the root actor's greeting packet.
*/
function RootClient(client, greeting) {
this._client = client;
this.actor = greeting.from;
this.applicationType = greeting.applicationType;
this.traits = greeting.traits;
}
exports.RootClient = RootClient;
RootClient.prototype = {
constructor: RootClient,
/**
* Gets the "root" form, which lists all the global actors that affect the entire
* browser. This can replace usages of `listTabs` that only wanted the global actors
* and didn't actually care about tabs.
*/
getRoot: DebuggerClient.requester({ type: "getRoot" }),
/**
* List the open tabs.
*
* @param function onResponse
* Called with the response packet.
*/
listTabs: DebuggerClient.requester({ type: "listTabs" }),
/**
* List the installed addons.
*
* @param function onResponse
* Called with the response packet.
*/
listAddons: DebuggerClient.requester({ type: "listAddons" }),
/**
* List the registered workers.
*
* @param function onResponse
* Called with the response packet.
*/
listWorkers: DebuggerClient.requester({ type: "listWorkers" }),
/**
* List the registered service workers.
*
* @param function onResponse
* Called with the response packet.
*/
listServiceWorkerRegistrations: DebuggerClient.requester({
type: "listServiceWorkerRegistrations"
}),
/**
* List the running processes.
*
* @param function onResponse
* Called with the response packet.
*/
listProcesses: DebuggerClient.requester({ type: "listProcesses" }),
/**
* Fetch the TabActor for the currently selected tab, or for a specific
* tab given as first parameter.
*
* @param [optional] object filter
* A dictionary object with following optional attributes:
* - outerWindowID: used to match tabs in parent process
* - tabId: used to match tabs in child processes
* - tab: a reference to xul:tab element
* If nothing is specified, returns the actor for the currently
* selected tab.
*/
getTab: function (filter) {
let packet = {
to: this.actor,
type: "getTab"
};
if (filter) {
if (typeof (filter.outerWindowID) == "number") {
packet.outerWindowID = filter.outerWindowID;
} else if (typeof (filter.tabId) == "number") {
packet.tabId = filter.tabId;
} else if ("tab" in filter) {
let browser = filter.tab.linkedBrowser;
if (browser.frameLoader.tabParent) {
// Tabs in child process
packet.tabId = browser.frameLoader.tabParent.tabId;
} else if (browser.outerWindowID) {
// <xul:browser> tabs in parent process
packet.outerWindowID = browser.outerWindowID;
} else {
// <iframe mozbrowser> tabs in parent process
let windowUtils = browser.contentWindow
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
packet.outerWindowID = windowUtils.outerWindowID;
}
} else {
// Throw if a filter object have been passed but without
// any clearly idenfified filter.
throw new Error("Unsupported argument given to getTab request");
}
}
return this.request(packet);
},
/**
* Fetch the WindowActor for a specific window, like a browser window in
* Firefox, but it can be used to reach any window in the process.
*
* @param number outerWindowID
* The outerWindowID of the top level window you are looking for.
*/
getWindow: function ({ outerWindowID }) {
if (!outerWindowID) {
throw new Error("Must specify outerWindowID");
}
let packet = {
to: this.actor,
type: "getWindow",
outerWindowID,
};
return this.request(packet);
},
/**
* Description of protocol's actors and methods.
*
* @param function onResponse
* Called with the response packet.
*/
protocolDescription: DebuggerClient.requester({ type: "protocolDescription" }),
/*
* Methods constructed by DebuggerClient.requester require these forwards
* on their 'this'.
*/
get _transport() {
return this._client._transport;
},
get request() {
return this._client.request;
}
};
module.exports = RootClient;

Просмотреть файл

@ -0,0 +1,282 @@
/* 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";
const {DebuggerClient} = require("./debugger-client");
loader.lazyRequireGetter(this, "BreakpointClient", "devtools/shared/client/breakpoint-client");
const noop = () => {};
/**
* A SourceClient provides a way to access the source text of a script.
*
* @param client ThreadClient
* The thread client parent.
* @param form Object
* The form sent across the remote debugging protocol.
*/
function SourceClient(client, form) {
this._form = form;
this._isBlackBoxed = form.isBlackBoxed;
this._isPrettyPrinted = form.isPrettyPrinted;
this._activeThread = client;
this._client = client.client;
}
SourceClient.prototype = {
get _transport() {
return this._client._transport;
},
get isBlackBoxed() {
return this._isBlackBoxed;
},
get isPrettyPrinted() {
return this._isPrettyPrinted;
},
get actor() {
return this._form.actor;
},
get request() {
return this._client.request;
},
get url() {
return this._form.url;
},
/**
* Black box this SourceClient's source.
*
* @param callback Function
* The callback function called when we receive the response from the server.
*/
blackBox: DebuggerClient.requester({
type: "blackbox"
}, {
after: function (response) {
if (!response.error) {
this._isBlackBoxed = true;
if (this._activeThread) {
this._activeThread.emit("blackboxchange", this);
}
}
return response;
}
}),
/**
* Un-black box this SourceClient's source.
*
* @param callback Function
* The callback function called when we receive the response from the server.
*/
unblackBox: DebuggerClient.requester({
type: "unblackbox"
}, {
after: function (response) {
if (!response.error) {
this._isBlackBoxed = false;
if (this._activeThread) {
this._activeThread.emit("blackboxchange", this);
}
}
return response;
}
}),
/**
* Get Executable Lines from a source
*
* @param callback Function
* The callback function called when we receive the response from the server.
*/
getExecutableLines: function (cb = noop) {
let packet = {
to: this._form.actor,
type: "getExecutableLines"
};
return this._client.request(packet).then(res => {
cb(res.lines);
return res.lines;
});
},
/**
* Get a long string grip for this SourceClient's source.
*/
source: function (callback = noop) {
let packet = {
to: this._form.actor,
type: "source"
};
return this._client.request(packet).then(response => {
return this._onSourceResponse(response, callback);
});
},
/**
* Pretty print this source's text.
*/
prettyPrint: function (indent, callback = noop) {
const packet = {
to: this._form.actor,
type: "prettyPrint",
indent
};
return this._client.request(packet).then(response => {
if (!response.error) {
this._isPrettyPrinted = true;
this._activeThread._clearFrames();
this._activeThread.emit("prettyprintchange", this);
}
return this._onSourceResponse(response, callback);
});
},
/**
* Stop pretty printing this source's text.
*/
disablePrettyPrint: function (callback = noop) {
const packet = {
to: this._form.actor,
type: "disablePrettyPrint"
};
return this._client.request(packet).then(response => {
if (!response.error) {
this._isPrettyPrinted = false;
this._activeThread._clearFrames();
this._activeThread.emit("prettyprintchange", this);
}
return this._onSourceResponse(response, callback);
});
},
_onSourceResponse: function (response, callback) {
if (response.error) {
callback(response);
return response;
}
if (typeof response.source === "string") {
callback(response);
return response;
}
let { contentType, source } = response;
if (source.type === "arrayBuffer") {
let arrayBuffer = this._activeThread.threadArrayBuffer(source);
return arrayBuffer.slice(0, arrayBuffer.length).then(function (resp) {
if (resp.error) {
callback(resp);
return resp;
}
// Keeping str as a string, ArrayBuffer/Uint8Array will not survive
// setIn/mergeIn operations.
const str = atob(resp.encoded);
let newResponse = {
source: {
binary: str,
toString: () => "[wasm]",
},
contentType,
};
callback(newResponse);
return newResponse;
});
}
let longString = this._activeThread.threadLongString(source);
return longString.substring(0, longString.length).then(function (resp) {
if (resp.error) {
callback(resp);
return resp;
}
let newResponse = {
source: resp.substring,
contentType: contentType
};
callback(newResponse);
return newResponse;
});
},
/**
* Request to set a breakpoint in the specified location.
*
* @param object location
* The location and condition of the breakpoint in
* the form of { line[, column, condition] }.
* @param function onResponse
* Called with the thread's response.
*/
setBreakpoint: function ({ line, column, condition, noSliding }, onResponse = noop) {
// A helper function that sets the breakpoint.
let doSetBreakpoint = callback => {
let root = this._client.mainRoot;
let location = {
line,
column,
};
let packet = {
to: this.actor,
type: "setBreakpoint",
location,
condition,
noSliding,
};
// Backwards compatibility: send the breakpoint request to the
// thread if the server doesn't support Debugger.Source actors.
if (!root.traits.debuggerSourceActors) {
packet.to = this._activeThread.actor;
packet.location.url = this.url;
}
return this._client.request(packet).then(response => {
// Ignoring errors, since the user may be setting a breakpoint in a
// dead script that will reappear on a page reload.
let bpClient;
if (response.actor) {
bpClient = new BreakpointClient(
this._client,
this,
response.actor,
location,
root.traits.conditionalBreakpoints ? condition : undefined
);
}
onResponse(response, bpClient);
if (callback) {
callback();
}
return [response, bpClient];
});
};
// If the debuggee is paused, just set the breakpoint.
if (this._activeThread.paused) {
return doSetBreakpoint();
}
// Otherwise, force a pause in order to set the breakpoint.
return this._activeThread.interrupt().then(response => {
if (response.error) {
// Can't set the breakpoint if pausing failed.
onResponse(response);
return response;
}
const { type, why } = response;
const cleanUp = type == "paused" && why.type == "interrupted"
? () => this._activeThread.resume()
: noop;
return doSetBreakpoint(cleanUp);
});
}
};
module.exports = SourceClient;

Просмотреть файл

@ -0,0 +1,64 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
/**
* A SymbolIteratorClient provides a way to access to symbols
* of an object efficiently, slice by slice.
*
* @param client DebuggerClient
* The debugger client parent.
* @param grip Object
* A SymbolIteratorActor grip returned by the protocol via
* TabActor.enumSymbols request.
*/
function SymbolIteratorClient(client, grip) {
this._grip = grip;
this._client = client;
this.request = this._client.request;
}
SymbolIteratorClient.prototype = {
get actor() {
return this._grip.actor;
},
/**
* Get the total number of symbols available in the iterator.
*/
get count() {
return this._grip.count;
},
/**
* Get a set of following symbols.
*
* @param start Number
* The index of the first symbol to fetch.
* @param count Number
* The number of symbols to fetch.
* @param callback Function
* The function called when we receive the symbols.
*/
slice: DebuggerClient.requester({
type: "slice",
start: arg(0),
count: arg(1)
}, {}),
/**
* Get all the symbols.
*
* @param callback Function
* The function called when we receive the symbols.
*/
all: DebuggerClient.requester({
type: "all"
}, {}),
};
module.exports = SymbolIteratorClient;

Просмотреть файл

@ -0,0 +1,156 @@
/* 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";
const { Cu } = require("chrome");
const promise = Cu.import("resource://devtools/shared/deprecated-sync-thenables.js", {}).Promise;
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const eventSource = require("./event-source");
const {arg, DebuggerClient} = require("./debugger-client");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
const noop = () => {};
/**
* Creates a tab client for the remote debugging protocol server. This client
* is a front to the tab actor created in the server side, hiding the protocol
* details in a traditional JavaScript API.
*
* @param client DebuggerClient
* The debugger client parent.
* @param form object
* The protocol form for this tab.
*/
function TabClient(client, form) {
this.client = client;
this._actor = form.from;
this._threadActor = form.threadActor;
this.javascriptEnabled = form.javascriptEnabled;
this.cacheDisabled = form.cacheDisabled;
this.thread = null;
this.request = this.client.request;
this.traits = form.traits || {};
this.events = ["workerListChanged"];
}
TabClient.prototype = {
get actor() {
return this._actor;
},
get _transport() {
return this.client._transport;
},
/**
* Attach to a thread actor.
*
* @param object options
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
* @param function onResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
*/
attachThread: function (options = {}, onResponse = noop) {
if (this.thread) {
DevToolsUtils.executeSoon(() => onResponse({}, this.thread));
return promise.resolve([{}, this.thread]);
}
let packet = {
to: this._threadActor,
type: "attach",
options,
};
return this.request(packet).then(response => {
if (!response.error) {
this.thread = new ThreadClient(this, this._threadActor);
this.client.registerClient(this.thread);
}
onResponse(response, this.thread);
return [response, this.thread];
});
},
/**
* Detach the client from the tab actor.
*
* @param function onResponse
* Called with the response packet.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
before: function (packet) {
if (this.thread) {
this.thread.detach();
}
return packet;
},
after: function (response) {
this.client.unregisterClient(this);
return response;
},
}),
/**
* Bring the window to the front.
*/
focus: DebuggerClient.requester({
type: "focus"
}, {}),
/**
* Reload the page in this tab.
*
* @param [optional] object options
* An object with a `force` property indicating whether or not
* this reload should skip the cache
*/
reload: function (options = { force: false }) {
return this._reload(options);
},
_reload: DebuggerClient.requester({
type: "reload",
options: arg(0)
}),
/**
* Navigate to another URL.
*
* @param string url
* The URL to navigate to.
*/
navigateTo: DebuggerClient.requester({
type: "navigateTo",
url: arg(0)
}),
/**
* Reconfigure the tab actor.
*
* @param object options
* A dictionary object of the new options to use in the tab actor.
* @param function onResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: arg(0)
}),
listWorkers: DebuggerClient.requester({
type: "listWorkers"
}),
attachWorker: function (workerActor, onResponse) {
return this.client.attachWorker(workerActor, onResponse);
},
};
eventSource(TabClient.prototype);
module.exports = TabClient;

Просмотреть файл

@ -0,0 +1,663 @@
/* 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";
const { Cu } = require("chrome");
const promise = Cu.import("resource://devtools/shared/deprecated-sync-thenables.js", {}).Promise;
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const {arg, DebuggerClient} = require("./debugger-client");
const eventSource = require("./event-source");
const {ThreadStateTypes} = require("./constants");
loader.lazyRequireGetter(this, "ArrayBufferClient", "devtools/shared/client/array-buffer-client");
loader.lazyRequireGetter(this, "EnvironmentClient", "devtools/shared/client/environment-client");
loader.lazyRequireGetter(this, "LongStringClient", "devtools/shared/client/long-string-client");
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client");
loader.lazyRequireGetter(this, "SourceClient", "devtools/shared/client/source-client");
const noop = () => {};
/**
* Creates a thread client for the remote debugging protocol server. This client
* is a front to the thread actor created in the server side, hiding the
* protocol details in a traditional JavaScript API.
*
* @param client DebuggerClient|TabClient
* The parent of the thread (tab for tab-scoped debuggers, DebuggerClient
* for chrome debuggers).
* @param actor string
* The actor ID for this thread.
*/
function ThreadClient(client, actor) {
this._parent = client;
this.client = client instanceof DebuggerClient ? client : client.client;
this._actor = actor;
this._frameCache = [];
this._scriptCache = {};
this._pauseGrips = {};
this._threadGrips = {};
this.request = this.client.request;
}
ThreadClient.prototype = {
_state: "paused",
get state() {
return this._state;
},
get paused() {
return this._state === "paused";
},
_pauseOnExceptions: false,
_ignoreCaughtExceptions: false,
_pauseOnDOMEvents: null,
_actor: null,
get actor() {
return this._actor;
},
get _transport() {
return this.client._transport;
},
_assertPaused: function (command) {
if (!this.paused) {
throw Error(command + " command sent while not paused. Currently " + this._state);
}
},
/**
* Resume a paused thread. If the optional limit parameter is present, then
* the thread will also pause when that limit is reached.
*
* @param [optional] object limit
* An object with a type property set to the appropriate limit (next,
* step, or finish) per the remote debugging protocol specification.
* Use null to specify no limit.
* @param function onResponse
* Called with the response packet.
*/
_doResume: DebuggerClient.requester({
type: "resume",
resumeLimit: arg(0)
}, {
before: function (packet) {
this._assertPaused("resume");
// Put the client in a tentative "resuming" state so we can prevent
// further requests that should only be sent in the paused state.
this._previousState = this._state;
this._state = "resuming";
if (this._pauseOnExceptions) {
packet.pauseOnExceptions = this._pauseOnExceptions;
}
if (this._ignoreCaughtExceptions) {
packet.ignoreCaughtExceptions = this._ignoreCaughtExceptions;
}
if (this._pauseOnDOMEvents) {
packet.pauseOnDOMEvents = this._pauseOnDOMEvents;
}
return packet;
},
after: function (response) {
if (response.error && this._state == "resuming") {
// There was an error resuming, update the state to the new one
// reported by the server, if given (only on wrongState), otherwise
// reset back to the previous state.
if (response.state) {
this._state = ThreadStateTypes[response.state];
} else {
this._state = this._previousState;
}
}
delete this._previousState;
return response;
},
}),
/**
* Reconfigure the thread actor.
*
* @param object options
* A dictionary object of the new options to use in the thread actor.
* @param function onResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: arg(0)
}),
/**
* Resume a paused thread.
*/
resume: function (onResponse) {
return this._doResume(null, onResponse);
},
/**
* Resume then pause without stepping.
*
* @param function onResponse
* Called with the response packet.
*/
resumeThenPause: function (onResponse) {
return this._doResume({ type: "break" }, onResponse);
},
/**
* Step over a function call.
*
* @param function onResponse
* Called with the response packet.
*/
stepOver: function (onResponse) {
return this._doResume({ type: "next" }, onResponse);
},
/**
* Step into a function call.
*
* @param function onResponse
* Called with the response packet.
*/
stepIn: function (onResponse) {
return this._doResume({ type: "step" }, onResponse);
},
/**
* Step out of a function call.
*
* @param function onResponse
* Called with the response packet.
*/
stepOut: function (onResponse) {
return this._doResume({ type: "finish" }, onResponse);
},
/**
* Immediately interrupt a running thread.
*
* @param function onResponse
* Called with the response packet.
*/
interrupt: function (onResponse) {
return this._doInterrupt(null, onResponse);
},
/**
* Pause execution right before the next JavaScript bytecode is executed.
*
* @param function onResponse
* Called with the response packet.
*/
breakOnNext: function (onResponse) {
return this._doInterrupt("onNext", onResponse);
},
/**
* Interrupt a running thread.
*
* @param function onResponse
* Called with the response packet.
*/
_doInterrupt: DebuggerClient.requester({
type: "interrupt",
when: arg(0)
}),
/**
* Enable or disable pausing when an exception is thrown.
*
* @param boolean pauseOnExceptions
* Enables pausing if true, disables otherwise.
* @param boolean ignoreCaughtExceptions
* Whether to ignore caught exceptions
* @param function onResponse
* Called with the response packet.
*/
pauseOnExceptions: function (pauseOnExceptions,
ignoreCaughtExceptions,
onResponse = noop) {
this._pauseOnExceptions = pauseOnExceptions;
this._ignoreCaughtExceptions = ignoreCaughtExceptions;
// Otherwise send the flag using a standard resume request.
if (!this.paused) {
return this.interrupt(response => {
if (response.error) {
// Can't continue if pausing failed.
onResponse(response);
return response;
}
return this.resume(onResponse);
});
}
onResponse();
return promise.resolve();
},
/**
* Enable pausing when the specified DOM events are triggered. Disabling
* pausing on an event can be realized by calling this method with the updated
* array of events that doesn't contain it.
*
* @param array|string events
* An array of strings, representing the DOM event types to pause on,
* or "*" to pause on all DOM events. Pass an empty array to
* completely disable pausing on DOM events.
* @param function onResponse
* Called with the response packet in a future turn of the event loop.
*/
pauseOnDOMEvents: function (events, onResponse = noop) {
this._pauseOnDOMEvents = events;
// If the debuggee is paused, the value of the array will be communicated in
// the next resumption. Otherwise we have to force a pause in order to send
// the array.
if (this.paused) {
DevToolsUtils.executeSoon(() => onResponse({}));
return {};
}
return this.interrupt(response => {
// Can't continue if pausing failed.
if (response.error) {
onResponse(response);
return response;
}
return this.resume(onResponse);
});
},
/**
* Send a clientEvaluate packet to the debuggee. Response
* will be a resume packet.
*
* @param string frame
* The actor ID of the frame where the evaluation should take place.
* @param string expression
* The expression that will be evaluated in the scope of the frame
* above.
* @param function onResponse
* Called with the response packet.
*/
eval: DebuggerClient.requester({
type: "clientEvaluate",
frame: arg(0),
expression: arg(1)
}, {
before: function (packet) {
this._assertPaused("eval");
// Put the client in a tentative "resuming" state so we can prevent
// further requests that should only be sent in the paused state.
this._state = "resuming";
return packet;
},
after: function (response) {
if (response.error) {
// There was an error resuming, back to paused state.
this._state = "paused";
}
return response;
},
}),
/**
* Detach from the thread actor.
*
* @param function onResponse
* Called with the response packet.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function (response) {
this.client.unregisterClient(this);
this._parent.thread = null;
return response;
},
}),
/**
* Release multiple thread-lifetime object actors. If any pause-lifetime
* actors are included in the request, a |notReleasable| error will return,
* but all the thread-lifetime ones will have been released.
*
* @param array actors
* An array with actor IDs to release.
*/
releaseMany: DebuggerClient.requester({
type: "releaseMany",
actors: arg(0),
}),
/**
* Promote multiple pause-lifetime object actors to thread-lifetime ones.
*
* @param array actors
* An array with actor IDs to promote.
*/
threadGrips: DebuggerClient.requester({
type: "threadGrips",
actors: arg(0)
}),
/**
* Return the event listeners defined on the page.
*
* @param onResponse Function
* Called with the thread's response.
*/
eventListeners: DebuggerClient.requester({
type: "eventListeners"
}),
/**
* Request the loaded sources for the current thread.
*
* @param onResponse Function
* Called with the thread's response.
*/
getSources: DebuggerClient.requester({
type: "sources"
}),
/**
* Clear the thread's source script cache. A scriptscleared event
* will be sent.
*/
_clearScripts: function () {
if (Object.keys(this._scriptCache).length > 0) {
this._scriptCache = {};
this.emit("scriptscleared");
}
},
/**
* Request frames from the callstack for the current thread.
*
* @param start integer
* The number of the youngest stack frame to return (the youngest
* frame is 0).
* @param count integer
* The maximum number of frames to return, or null to return all
* frames.
* @param onResponse function
* Called with the thread's response.
*/
getFrames: DebuggerClient.requester({
type: "frames",
start: arg(0),
count: arg(1)
}),
/**
* An array of cached frames. Clients can observe the framesadded and
* framescleared event to keep up to date on changes to this cache,
* and can fill it using the fillFrames method.
*/
get cachedFrames() {
return this._frameCache;
},
/**
* true if there are more stack frames available on the server.
*/
get moreFrames() {
return this.paused && (!this._frameCache || this._frameCache.length == 0
|| !this._frameCache[this._frameCache.length - 1].oldest);
},
/**
* Request the frame environment.
*
* @param frameId string
*/
getEnvironment: function (frameId) {
return this.request({ to: frameId, type: "getEnvironment" });
},
/**
* Ensure that at least total stack frames have been loaded in the
* ThreadClient's stack frame cache. A framesadded event will be
* sent when the stack frame cache is updated.
*
* @param total number
* The minimum number of stack frames to be included.
* @param callback function
* Optional callback function called when frames have been loaded
* @returns true if a framesadded notification should be expected.
*/
fillFrames: function (total, callback = noop) {
this._assertPaused("fillFrames");
if (this._frameCache.length >= total) {
return false;
}
let numFrames = this._frameCache.length;
this.getFrames(numFrames, total - numFrames, (response) => {
if (response.error) {
callback(response);
return;
}
let threadGrips = DevToolsUtils.values(this._threadGrips);
for (let i in response.frames) {
let frame = response.frames[i];
if (!frame.where.source) {
// Older servers use urls instead, so we need to resolve
// them to source actors
for (let grip of threadGrips) {
if (grip instanceof SourceClient && grip.url === frame.url) {
frame.where.source = grip._form;
}
}
}
this._frameCache[frame.depth] = frame;
}
// If we got as many frames as we asked for, there might be more
// frames available.
this.emit("framesadded");
callback(response);
});
return true;
},
/**
* Clear the thread's stack frame cache. A framescleared event
* will be sent.
*/
_clearFrames: function () {
if (this._frameCache.length > 0) {
this._frameCache = [];
this.emit("framescleared");
}
},
/**
* Return a ObjectClient object for the given object grip.
*
* @param grip object
* A pause-lifetime object grip returned by the protocol.
*/
pauseGrip: function (grip) {
if (grip.actor in this._pauseGrips) {
return this._pauseGrips[grip.actor];
}
let client = new ObjectClient(this.client, grip);
this._pauseGrips[grip.actor] = client;
return client;
},
/**
* Get or create a long string client, checking the grip client cache if it
* already exists.
*
* @param grip Object
* The long string grip returned by the protocol.
* @param gripCacheName String
* The property name of the grip client cache to check for existing
* clients in.
*/
_longString: function (grip, gripCacheName) {
if (grip.actor in this[gripCacheName]) {
return this[gripCacheName][grip.actor];
}
let client = new LongStringClient(this.client, grip);
this[gripCacheName][grip.actor] = client;
return client;
},
/**
* Return an instance of LongStringClient for the given long string grip that
* is scoped to the current pause.
*
* @param grip Object
* The long string grip returned by the protocol.
*/
pauseLongString: function (grip) {
return this._longString(grip, "_pauseGrips");
},
/**
* Return an instance of LongStringClient for the given long string grip that
* is scoped to the thread lifetime.
*
* @param grip Object
* The long string grip returned by the protocol.
*/
threadLongString: function (grip) {
return this._longString(grip, "_threadGrips");
},
/**
* Get or create an ArrayBuffer client, checking the grip client cache if it
* already exists.
*
* @param grip Object
* The ArrayBuffer grip returned by the protocol.
* @param gripCacheName String
* The property name of the grip client cache to check for existing
* clients in.
*/
_arrayBuffer: function (grip, gripCacheName) {
if (grip.actor in this[gripCacheName]) {
return this[gripCacheName][grip.actor];
}
let client = new ArrayBufferClient(this.client, grip);
this[gripCacheName][grip.actor] = client;
return client;
},
/**
* Return an instance of ArrayBufferClient for the given ArrayBuffer grip that
* is scoped to the thread lifetime.
*
* @param grip Object
* The ArrayBuffer grip returned by the protocol.
*/
threadArrayBuffer: function (grip) {
return this._arrayBuffer(grip, "_threadGrips");
},
/**
* Clear and invalidate all the grip clients from the given cache.
*
* @param gripCacheName
* The property name of the grip cache we want to clear.
*/
_clearObjectClients: function (gripCacheName) {
for (let id in this[gripCacheName]) {
this[gripCacheName][id].valid = false;
}
this[gripCacheName] = {};
},
/**
* Invalidate pause-lifetime grip clients and clear the list of current grip
* clients.
*/
_clearPauseGrips: function () {
this._clearObjectClients("_pauseGrips");
},
/**
* Invalidate thread-lifetime grip clients and clear the list of current grip
* clients.
*/
_clearThreadGrips: function () {
this._clearObjectClients("_threadGrips");
},
/**
* Handle thread state change by doing necessary cleanup and notifying all
* registered listeners.
*/
_onThreadState: function (packet) {
this._state = ThreadStateTypes[packet.type];
// The debugger UI may not be initialized yet so we want to keep
// the packet around so it knows what to pause state to display
// when it's initialized
this._lastPausePacket = packet.type === "resumed" ? null : packet;
this._clearFrames();
this._clearPauseGrips();
packet.type === ThreadStateTypes.detached && this._clearThreadGrips();
this.client._eventsEnabled && this.emit(packet.type, packet);
},
getLastPausePacket: function () {
return this._lastPausePacket;
},
/**
* Return an EnvironmentClient instance for the given environment actor form.
*/
environment: function (form) {
return new EnvironmentClient(this.client, form);
},
/**
* Return an instance of SourceClient for the given source actor form.
*/
source: function (form) {
if (form.actor in this._threadGrips) {
return this._threadGrips[form.actor];
}
this._threadGrips[form.actor] = new SourceClient(this, form);
return this._threadGrips[form.actor];
},
/**
* Request the prototype and own properties of mutlipleObjects.
*
* @param onResponse function
* Called with the request's response.
* @param actors [string]
* List of actor ID of the queried objects.
*/
getPrototypesAndProperties: DebuggerClient.requester({
type: "prototypesAndProperties",
actors: arg(0)
}),
events: ["newSource"]
};
eventSource(ThreadClient.prototype);
module.exports = ThreadClient;

Просмотреть файл

@ -0,0 +1,112 @@
/* 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";
const {arg, DebuggerClient} = require("./debugger-client");
/**
* Creates a tracing profiler client for the remote debugging protocol
* server. This client is a front to the trace actor created on the
* server side, hiding the protocol details in a traditional
* JavaScript API.
*
* @param client DebuggerClient
* The debugger client parent.
* @param actor string
* The actor ID for this thread.
*/
function TraceClient(client, actor) {
this._client = client;
this._actor = actor;
this._activeTraces = new Set();
this._waitingPackets = new Map();
this._expectedPacket = 0;
this.request = this._client.request;
this.events = [];
}
TraceClient.prototype = {
get actor() {
return this._actor;
},
get tracing() {
return this._activeTraces.size > 0;
},
get _transport() {
return this._client._transport;
},
/**
* Detach from the trace actor.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function (response) {
this._client.unregisterClient(this);
return response;
},
}),
/**
* Start a new trace.
*
* @param trace [string]
* An array of trace types to be recorded by the new trace.
*
* @param name string
* The name of the new trace.
*
* @param onResponse function
* Called with the request's response.
*/
startTrace: DebuggerClient.requester({
type: "startTrace",
name: arg(1),
trace: arg(0)
}, {
after: function (response) {
if (response.error) {
return response;
}
if (!this.tracing) {
this._waitingPackets.clear();
this._expectedPacket = 0;
}
this._activeTraces.add(response.name);
return response;
},
}),
/**
* End a trace. If a name is provided, stop the named
* trace. Otherwise, stop the most recently started trace.
*
* @param name string
* The name of the trace to stop.
*
* @param onResponse function
* Called with the request's response.
*/
stopTrace: DebuggerClient.requester({
type: "stopTrace",
name: arg(0)
}, {
after: function (response) {
if (response.error) {
return response;
}
this._activeTraces.delete(response.name);
return response;
},
})
};
module.exports = TraceClient;

Просмотреть файл

@ -0,0 +1,120 @@
/* 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";
const {DebuggerClient} = require("./debugger-client");
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const eventSource = require("./event-source");
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/thread-client");
const noop = () => {};
function WorkerClient(client, form) {
this.client = client;
this._actor = form.from;
this._isClosed = false;
this._url = form.url;
this._onClose = this._onClose.bind(this);
this.addListener("close", this._onClose);
this.traits = {};
}
WorkerClient.prototype = {
get _transport() {
return this.client._transport;
},
get request() {
return this.client.request;
},
get actor() {
return this._actor;
},
get url() {
return this._url;
},
get isClosed() {
return this._isClosed;
},
detach: DebuggerClient.requester({ type: "detach" }, {
after: function (response) {
if (this.thread) {
this.client.unregisterClient(this.thread);
}
this.client.unregisterClient(this);
return response;
},
}),
attachThread: function (options = {}, onResponse = noop) {
if (this.thread) {
let response = [{
type: "connected",
threadActor: this.thread._actor,
consoleActor: this.consoleActor,
}, this.thread];
DevToolsUtils.executeSoon(() => onResponse(response));
return response;
}
// The connect call on server doesn't attach the thread as of version 44.
return this.request({
to: this._actor,
type: "connect",
options,
}).then(connectResponse => {
if (connectResponse.error) {
onResponse(connectResponse, null);
return [connectResponse, null];
}
return this.request({
to: connectResponse.threadActor,
type: "attach",
options,
}).then(attachResponse => {
if (attachResponse.error) {
onResponse(attachResponse, null);
}
this.thread = new ThreadClient(this, connectResponse.threadActor);
this.consoleActor = connectResponse.consoleActor;
this.client.registerClient(this.thread);
onResponse(connectResponse, this.thread);
return [connectResponse, this.thread];
});
}, error => {
onResponse(error, null);
});
},
_onClose: function () {
this.removeListener("close", this._onClose);
if (this.thread) {
this.client.unregisterClient(this.thread);
}
this.client.unregisterClient(this);
this._isClosed = true;
},
reconfigure: function () {
return Promise.resolve();
},
events: ["close"]
};
eventSource(WorkerClient.prototype);
module.exports = WorkerClient;