Bug 1212797 - Show all registered service workers in about:debugging. r=ochameau

This commit is contained in:
Jan Keromnes 2016-02-24 06:30:00 +01:00
Родитель ea10bbdb0c
Коммит eb7e62b31c
4 изменённых файлов: 126 добавлений и 60 удалений

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

@ -26,47 +26,60 @@ const Strings = Services.strings.createBundle(
exports.Target = React.createClass({
displayName: "Target",
debug() {
let { client, target } = this.props;
switch (target.type) {
case "extension":
BrowserToolboxProcess.init({ addonID: target.addonID });
break;
case "serviceworker":
// Fall through.
case "sharedworker":
// Fall through.
case "worker":
let workerActor = this.props.target.actorID;
client.attachWorker(workerActor, (response, workerClient) => {
gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
"jsdebugger", Toolbox.HostType.WINDOW)
.then(toolbox => {
toolbox.once("destroy", () => workerClient.detach());
});
});
break;
default:
alert("Not implemented yet!");
}
},
render() {
let { target, debugDisabled } = this.props;
let isServiceWorker = (target.type === "serviceworker");
let isRunning = (!isServiceWorker || target.workerActor);
return React.createElement("div", { className: "target" },
React.createElement("img", {
className: "target-icon",
role: "presentation",
src: target.icon }),
React.createElement("div", { className: "target-details" },
React.createElement("div", { className: "target-name" }, target.name),
React.createElement("div", { className: "target-url" }, target.url)
React.createElement("div", { className: "target-name" }, target.name)
),
React.createElement("button", {
className: "debug-button",
onClick: this.debug,
disabled: debugDisabled,
}, Strings.GetStringFromName("debug"))
(isRunning ?
React.createElement("button", {
className: "debug-button",
onClick: this.debug,
disabled: debugDisabled,
}, Strings.GetStringFromName("debug")) :
null
)
);
},
debug() {
let { target } = this.props;
switch (target.type) {
case "extension":
BrowserToolboxProcess.init({ addonID: target.addonID });
break;
case "serviceworker":
if (target.workerActor) {
this.openWorkerToolbox(target.workerActor);
}
break;
case "sharedworker":
this.openWorkerToolbox(target.workerActor);
break;
case "worker":
this.openWorkerToolbox(target.workerActor);
break;
default:
alert("Not implemented yet!");
break;
}
},
openWorkerToolbox(workerActor) {
let { client } = this.props;
client.attachWorker(workerActor, (response, workerClient) => {
gDevTools.showToolbox(TargetFactory.forWorker(workerClient),
"jsdebugger", Toolbox.HostType.WINDOW)
.then(toolbox => {
toolbox.once("destroy", () => workerClient.detach());
});
});
},
});

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

@ -38,6 +38,7 @@ exports.WorkersTab = React.createClass({
componentDidMount() {
let client = this.props.client;
client.addListener("workerListChanged", this.update);
client.addListener("serviceWorkerRegistrationListChanged", this.update);
client.addListener("processListChanged", this.update);
this.update();
},
@ -45,6 +46,7 @@ exports.WorkersTab = React.createClass({
componentWillUnmount() {
let client = this.props.client;
client.removeListener("processListChanged", this.update);
client.removeListener("serviceWorkerRegistrationListChanged", this.update);
client.removeListener("workerListChanged", this.update);
},
@ -77,52 +79,90 @@ exports.WorkersTab = React.createClass({
update() {
let workers = this.getInitialState().workers;
this.getWorkerForms().then(forms => {
forms.forEach(form => {
let worker = {
name: form.url,
forms.registrations.forEach(form => {
workers.service.push({
type: "serviceworker",
icon: WorkerIcon,
actorID: form.actor
name: form.url,
url: form.url,
scope: form.scope,
registrationActor: form.actor
});
});
forms.workers.forEach(form => {
let worker = {
type: "worker",
icon: WorkerIcon,
name: form.url,
url: form.url,
workerActor: form.actor
};
switch (form.type) {
case Ci.nsIWorkerDebugger.TYPE_SERVICE:
worker.type = "serviceworker";
workers.service.push(worker);
for (let registration of workers.service) {
if (registration.scope === form.scope) {
// XXX: Race, sometimes a ServiceWorkerRegistrationInfo doesn't
// have a scriptSpec, but its associated WorkerDebugger does.
if (!registration.url) {
registration.name = registration.url = form.url;
}
registration.workerActor = form.actor;
break;
}
}
break;
case Ci.nsIWorkerDebugger.TYPE_SHARED:
worker.type = "sharedworker";
workers.shared.push(worker);
break;
default:
worker.type = "worker";
workers.other.push(worker);
}
});
// XXX: Filter out the service worker registrations for which we couldn't
// find the scriptSpec.
workers.service = workers.service.filter(reg => !!reg.url);
this.setState({ workers });
});
},
getWorkerForms: Task.async(function*() {
let client = this.props.client;
let registrations = [];
let workers = [];
// List workers from the Parent process
let result = yield client.mainRoot.listWorkers();
let forms = result.workers;
try {
// List service worker registrations
({ registrations } =
yield client.mainRoot.listServiceWorkerRegistrations());
// And then from the Child processes
let { processes } = yield client.mainRoot.listProcesses();
for (let process of processes) {
// Ignore parent process
if (process.parent) {
continue;
// List workers from the Parent process
({ workers } = yield client.mainRoot.listWorkers());
// And then from the Child processes
let { processes } = yield client.mainRoot.listProcesses();
for (let process of processes) {
// Ignore parent process
if (process.parent) {
continue;
}
let { form } = yield client.getProcess(process.id);
let processActor = form.actor;
let response = yield client.request({
to: processActor,
type: "listWorkers"
});
workers = workers.concat(response.workers);
}
let { form } = yield client.getProcess(process.id);
let processActor = form.actor;
let { workers } = yield client.request({to: processActor,
type: "listWorkers"});
forms = forms.concat(workers);
} catch (e) {
// Something went wrong, maybe our client is disconnected?
}
return forms;
return { registrations, workers };
}),
});

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

@ -67,7 +67,8 @@ add_task(function* () {
let names = [...document.querySelectorAll("#service-workers .target-name")];
let name = names.filter(element => element.textContent === SERVICE_WORKER)[0];
ok(name, "Found the service worker in the list");
let debugBtn = name.parentNode.parentNode.querySelector("button");
let targetElement = name.parentNode.parentNode;
let debugBtn = targetElement.querySelector(".debug-button");
ok(debugBtn, "Found its debug button");
// Click on it and wait for the toolbox to be ready
@ -88,16 +89,18 @@ add_task(function* () {
});
assertHasWorker(true, document, "service-workers", SERVICE_WORKER);
ok(targetElement.querySelector(".debug-button"),
"The debug button is still there");
yield toolbox.destroy();
toolbox = null;
// Now ensure that the worker is correctly destroyed
// after we destroy the toolbox.
// The list should update once it get destroyed.
yield waitForMutation(serviceWorkersElement, { childList: true });
assertHasWorker(false, document, "service-workers", SERVICE_WORKER);
// The DEBUG button should disappear once the worker is destroyed.
yield waitForMutation(targetElement, { childList: true });
ok(!targetElement.querySelector(".debug-button"),
"The debug button was removed when the worker was killed");
// Finally, unregister the service worker itself
// Use message manager to work with e10s
@ -124,6 +127,11 @@ add_task(function* () {
});
ok(true, "Service worker registration unregistered");
// Now ensure that the worker registration is correctly removed.
// The list should update once the registration is destroyed.
yield waitForMutation(serviceWorkersElement, { childList: true });
assertHasWorker(false, document, "service-workers", SERVICE_WORKER);
yield removeTab(swTab);
yield closeAboutDebugging(tab);
});

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

@ -53,12 +53,17 @@ let WorkerActor = protocol.ActorClass({
if (detail === "actorid") {
return this.actorID;
}
return {
let form = {
actor: this.actorID,
consoleActor: this._consoleActor,
url: this._dbg.url,
type: this._dbg.type
};
if (this._dbg.type === Ci.nsIWorkerDebugger.TYPE_SERVICE) {
let registration = this._getServiceWorkerRegistrationInfo();
form.scope = registration.scope;
}
return form;
},
attach: method(function () {