Source code

Revision control

Copy as Markdown

Other Tools

/* 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";
/*
* Target actor for any of the various kinds of workers.
*
* See devtools/docs/backend/actor-hierarchy.md for more details.
*/
// protocol.js uses objects as exceptions in order to define
// error packets.
/* eslint-disable no-throw-literal */
const { Actor } = require("resource://devtools/shared/protocol.js");
const {
workerDescriptorSpec,
const {
DevToolsServer,
const { XPCOMUtils } = ChromeUtils.importESModule(
{ global: "contextual" }
);
const {
createWorkerSessionContext,
loader.lazyRequireGetter(
this,
"connectToWorker",
true
);
XPCOMUtils.defineLazyServiceGetter(
this,
"swm",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager"
);
class WorkerDescriptorActor extends Actor {
constructor(conn, dbg) {
super(conn, workerDescriptorSpec);
this._dbg = dbg;
this._threadActor = null;
this._transport = null;
this._dbgListener = {
onClose: this._onWorkerClose.bind(this),
onError: this._onWorkerError.bind(this),
};
this._dbg.addListener(this._dbgListener);
this._attached = true;
}
form() {
const form = {
actor: this.actorID,
consoleActor: this._consoleActor,
threadActor: this._threadActor,
tracerActor: this._tracerActor,
id: this._dbg.id,
url: this._dbg.url,
traits: {},
type: this._dbg.type,
};
if (this._dbg.type === Ci.nsIWorkerDebugger.TYPE_SERVICE) {
/**
* The ServiceWorkerManager in content processes don't maintain
* ServiceWorkerRegistrations; record the ServiceWorker's ID, and
* this data will be merged with the corresponding registration in
* the parent process.
*/
if (!DevToolsServer.isInChildProcess) {
const registration = this._getServiceWorkerRegistrationInfo();
form.scope = registration.scope;
const newestWorker =
registration.activeWorker ||
registration.waitingWorker ||
registration.installingWorker;
form.fetch = newestWorker?.handlesFetchEvents;
}
}
return form;
}
detach() {
if (!this._attached) {
throw { error: "wrongState" };
}
this.destroy();
}
destroy() {
if (this._attached) {
this._detach();
}
this.emit("descriptor-destroyed");
super.destroy();
}
async getTarget() {
if (!this._attached) {
return { error: "wrongState" };
}
if (this._threadActor !== null) {
return {
type: "connected",
consoleActor: this._consoleActor,
threadActor: this._threadActor,
tracerActor: this._tracerActor,
};
}
try {
const { transport, workerTargetForm } = await connectToWorker(
this.conn,
this._dbg,
this.actorID,
{
sessionContext: createWorkerSessionContext(),
}
);
this._consoleActor = workerTargetForm.consoleActor;
this._threadActor = workerTargetForm.threadActor;
this._tracerActor = workerTargetForm.tracerActor;
this._transport = transport;
return {
type: "connected",
consoleActor: this._consoleActor,
threadActor: this._threadActor,
tracerActor: this._tracerActor,
url: this._dbg.url,
};
} catch (error) {
return { error: error.toString() };
}
}
_onWorkerClose() {
this.destroy();
}
_onWorkerError(filename, lineno, message) {
console.error("ERROR:", filename, ":", lineno, ":", message);
}
_getServiceWorkerRegistrationInfo() {
return swm.getRegistrationByPrincipal(this._dbg.principal, this._dbg.url);
}
_detach() {
if (this._threadActor !== null) {
this._transport.close();
this._transport = null;
this._threadActor = null;
}
this._dbg.removeListener(this._dbgListener);
this._attached = false;
}
}
exports.WorkerDescriptorActor = WorkerDescriptorActor;