summaryrefslogtreecommitdiffstats
path: root/devtools/client/aboutdebugging/components/workers
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /devtools/client/aboutdebugging/components/workers
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'devtools/client/aboutdebugging/components/workers')
-rw-r--r--devtools/client/aboutdebugging/components/workers/moz.build9
-rw-r--r--devtools/client/aboutdebugging/components/workers/panel.js193
-rw-r--r--devtools/client/aboutdebugging/components/workers/service-worker-target.js231
-rw-r--r--devtools/client/aboutdebugging/components/workers/target.js57
4 files changed, 490 insertions, 0 deletions
diff --git a/devtools/client/aboutdebugging/components/workers/moz.build b/devtools/client/aboutdebugging/components/workers/moz.build
new file mode 100644
index 000000000..ff33a5b28
--- /dev/null
+++ b/devtools/client/aboutdebugging/components/workers/moz.build
@@ -0,0 +1,9 @@
+# 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/.
+
+DevToolsModules(
+ 'panel.js',
+ 'service-worker-target.js',
+ 'target.js',
+)
diff --git a/devtools/client/aboutdebugging/components/workers/panel.js b/devtools/client/aboutdebugging/components/workers/panel.js
new file mode 100644
index 000000000..b1bab2b99
--- /dev/null
+++ b/devtools/client/aboutdebugging/components/workers/panel.js
@@ -0,0 +1,193 @@
+/* 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/. */
+/* globals window */
+"use strict";
+
+loader.lazyImporter(this, "PrivateBrowsingUtils",
+ "resource://gre/modules/PrivateBrowsingUtils.jsm");
+
+const { Ci } = require("chrome");
+const { createClass, createFactory, DOM: dom, PropTypes } =
+ require("devtools/client/shared/vendor/react");
+const { getWorkerForms } = require("../../modules/worker");
+const Services = require("Services");
+
+const PanelHeader = createFactory(require("../panel-header"));
+const TargetList = createFactory(require("../target-list"));
+const WorkerTarget = createFactory(require("./target"));
+const ServiceWorkerTarget = createFactory(require("./service-worker-target"));
+
+loader.lazyImporter(this, "PrivateBrowsingUtils",
+ "resource://gre/modules/PrivateBrowsingUtils.jsm");
+
+loader.lazyRequireGetter(this, "DebuggerClient",
+ "devtools/shared/client/main", true);
+
+const Strings = Services.strings.createBundle(
+ "chrome://devtools/locale/aboutdebugging.properties");
+
+const WorkerIcon = "chrome://devtools/skin/images/debugging-workers.svg";
+const MORE_INFO_URL = "https://developer.mozilla.org/en-US/docs/Tools/about%3Adebugging";
+
+module.exports = createClass({
+ displayName: "WorkersPanel",
+
+ propTypes: {
+ client: PropTypes.instanceOf(DebuggerClient).isRequired,
+ id: PropTypes.string.isRequired
+ },
+
+ getInitialState() {
+ return {
+ workers: {
+ service: [],
+ shared: [],
+ other: []
+ }
+ };
+ },
+
+ componentDidMount() {
+ let client = this.props.client;
+ client.addListener("workerListChanged", this.update);
+ client.addListener("serviceWorkerRegistrationListChanged", this.update);
+ client.addListener("processListChanged", this.update);
+ client.addListener("registration-changed", this.update);
+
+ this.update();
+ },
+
+ componentWillUnmount() {
+ let client = this.props.client;
+ client.removeListener("processListChanged", this.update);
+ client.removeListener("serviceWorkerRegistrationListChanged", this.update);
+ client.removeListener("workerListChanged", this.update);
+ client.removeListener("registration-changed", this.update);
+ },
+
+ update() {
+ let workers = this.getInitialState().workers;
+
+ getWorkerForms(this.props.client).then(forms => {
+ forms.registrations.forEach(form => {
+ workers.service.push({
+ icon: WorkerIcon,
+ name: form.url,
+ url: form.url,
+ scope: form.scope,
+ registrationActor: form.actor,
+ active: form.active
+ });
+ });
+
+ forms.workers.forEach(form => {
+ let worker = {
+ icon: WorkerIcon,
+ name: form.url,
+ url: form.url,
+ workerActor: form.actor
+ };
+ switch (form.type) {
+ case Ci.nsIWorkerDebugger.TYPE_SERVICE:
+ let registration = this.getRegistrationForWorker(form, workers.service);
+ if (registration) {
+ // 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;
+ } else {
+ // If a service worker registration could not be found, this means we are in
+ // e10s, and registrations are not forwarded to other processes until they
+ // reach the activated state. Augment the worker as a registration worker to
+ // display it in aboutdebugging.
+ worker.scope = form.scope;
+ worker.active = false;
+ workers.service.push(worker);
+ }
+ break;
+ case Ci.nsIWorkerDebugger.TYPE_SHARED:
+ workers.shared.push(worker);
+ break;
+ default:
+ 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 });
+ });
+ },
+
+ getRegistrationForWorker(form, registrations) {
+ for (let registration of registrations) {
+ if (registration.scope === form.scope) {
+ return registration;
+ }
+ }
+ return null;
+ },
+
+ render() {
+ let { client, id } = this.props;
+ let { workers } = this.state;
+
+ let isWindowPrivate = PrivateBrowsingUtils.isContentWindowPrivate(window);
+ let isPrivateBrowsingMode = PrivateBrowsingUtils.permanentPrivateBrowsing;
+ let isServiceWorkerDisabled = !Services.prefs
+ .getBoolPref("dom.serviceWorkers.enabled");
+ let errorMsg = isWindowPrivate || isPrivateBrowsingMode ||
+ isServiceWorkerDisabled ?
+ dom.p({ className: "service-worker-disabled" },
+ dom.div({ className: "warning" }),
+ Strings.GetStringFromName("configurationIsNotCompatible"),
+ " (",
+ dom.a({ href: MORE_INFO_URL, target: "_blank" },
+ Strings.GetStringFromName("moreInfo")),
+ ")"
+ ) : "";
+
+ return dom.div({
+ id: id + "-panel",
+ className: "panel",
+ role: "tabpanel",
+ "aria-labelledby": id + "-header"
+ },
+ PanelHeader({
+ id: id + "-header",
+ name: Strings.GetStringFromName("workers")
+ }),
+ dom.div({ id: "workers", className: "inverted-icons" },
+ TargetList({
+ client,
+ error: errorMsg,
+ id: "service-workers",
+ name: Strings.GetStringFromName("serviceWorkers"),
+ sort: true,
+ targetClass: ServiceWorkerTarget,
+ targets: workers.service
+ }),
+ TargetList({
+ client,
+ id: "shared-workers",
+ name: Strings.GetStringFromName("sharedWorkers"),
+ sort: true,
+ targetClass: WorkerTarget,
+ targets: workers.shared
+ }),
+ TargetList({
+ client,
+ id: "other-workers",
+ name: Strings.GetStringFromName("otherWorkers"),
+ sort: true,
+ targetClass: WorkerTarget,
+ targets: workers.other
+ })
+ ));
+ }
+});
diff --git a/devtools/client/aboutdebugging/components/workers/service-worker-target.js b/devtools/client/aboutdebugging/components/workers/service-worker-target.js
new file mode 100644
index 000000000..d46f6f20f
--- /dev/null
+++ b/devtools/client/aboutdebugging/components/workers/service-worker-target.js
@@ -0,0 +1,231 @@
+/* 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/. */
+
+/* eslint-env browser */
+
+"use strict";
+
+const { createClass, DOM: dom, PropTypes } =
+ require("devtools/client/shared/vendor/react");
+const { debugWorker } = require("../../modules/worker");
+const Services = require("Services");
+
+loader.lazyRequireGetter(this, "DebuggerClient",
+ "devtools/shared/client/main", true);
+
+const Strings = Services.strings.createBundle(
+ "chrome://devtools/locale/aboutdebugging.properties");
+
+module.exports = createClass({
+ displayName: "ServiceWorkerTarget",
+
+ propTypes: {
+ client: PropTypes.instanceOf(DebuggerClient).isRequired,
+ debugDisabled: PropTypes.bool,
+ target: PropTypes.shape({
+ active: PropTypes.bool,
+ icon: PropTypes.string,
+ name: PropTypes.string.isRequired,
+ url: PropTypes.string,
+ scope: PropTypes.string.isRequired,
+ // registrationActor can be missing in e10s.
+ registrationActor: PropTypes.string,
+ workerActor: PropTypes.string
+ }).isRequired
+ },
+
+ getInitialState() {
+ return {
+ pushSubscription: null
+ };
+ },
+
+ componentDidMount() {
+ let { client } = this.props;
+ client.addListener("push-subscription-modified", this.onPushSubscriptionModified);
+ this.updatePushSubscription();
+ },
+
+ componentDidUpdate(oldProps, oldState) {
+ let wasActive = oldProps.target.active;
+ if (!wasActive && this.isActive()) {
+ // While the service worker isn't active, any calls to `updatePushSubscription`
+ // won't succeed. If we just became active, make sure we didn't miss a push
+ // subscription change by updating it now.
+ this.updatePushSubscription();
+ }
+ },
+
+ componentWillUnmount() {
+ let { client } = this.props;
+ client.removeListener("push-subscription-modified", this.onPushSubscriptionModified);
+ },
+
+ debug() {
+ if (!this.isRunning()) {
+ // If the worker is not running, we can't debug it.
+ return;
+ }
+
+ let { client, target } = this.props;
+ debugWorker(client, target.workerActor);
+ },
+
+ push() {
+ if (!this.isActive() || !this.isRunning()) {
+ // If the worker is not running, we can't push to it.
+ // If the worker is not active, the registration might be unavailable and the
+ // push will not succeed.
+ return;
+ }
+
+ let { client, target } = this.props;
+ client.request({
+ to: target.workerActor,
+ type: "push"
+ });
+ },
+
+ start() {
+ if (!this.isActive() || this.isRunning()) {
+ // If the worker is not active or if it is already running, we can't start it.
+ return;
+ }
+
+ let { client, target } = this.props;
+ client.request({
+ to: target.registrationActor,
+ type: "start"
+ });
+ },
+
+ unregister() {
+ let { client, target } = this.props;
+ client.request({
+ to: target.registrationActor,
+ type: "unregister"
+ });
+ },
+
+ onPushSubscriptionModified(type, data) {
+ let { target } = this.props;
+ if (data.from === target.registrationActor) {
+ this.updatePushSubscription();
+ }
+ },
+
+ updatePushSubscription() {
+ if (!this.props.target.registrationActor) {
+ // A valid registrationActor is needed to retrieve the push subscription.
+ return;
+ }
+
+ let { client, target } = this.props;
+ client.request({
+ to: target.registrationActor,
+ type: "getPushSubscription"
+ }, ({ subscription }) => {
+ this.setState({ pushSubscription: subscription });
+ });
+ },
+
+ isRunning() {
+ // We know the target is running if it has a worker actor.
+ return !!this.props.target.workerActor;
+ },
+
+ isActive() {
+ return this.props.target.active;
+ },
+
+ getServiceWorkerStatus() {
+ if (this.isActive() && this.isRunning()) {
+ return "running";
+ } else if (this.isActive()) {
+ return "stopped";
+ }
+ // We cannot get service worker registrations unless the registration is in
+ // ACTIVE state. Unable to know the actual state ("installing", "waiting"), we
+ // display a custom state "registering" for now. See Bug 1153292.
+ return "registering";
+ },
+
+ renderButtons() {
+ let pushButton = dom.button({
+ className: "push-button",
+ onClick: this.push
+ }, Strings.GetStringFromName("push"));
+
+ let debugButton = dom.button({
+ className: "debug-button",
+ onClick: this.debug,
+ disabled: this.props.debugDisabled
+ }, Strings.GetStringFromName("debug"));
+
+ let startButton = dom.button({
+ className: "start-button",
+ onClick: this.start,
+ }, Strings.GetStringFromName("start"));
+
+ if (this.isRunning()) {
+ if (this.isActive()) {
+ return [pushButton, debugButton];
+ }
+ // Only debug button is available if the service worker is not active.
+ return debugButton;
+ }
+ return startButton;
+ },
+
+ renderUnregisterLink() {
+ if (!this.isActive()) {
+ // If not active, there might be no registrationActor available.
+ return null;
+ }
+
+ return dom.a({
+ onClick: this.unregister,
+ className: "unregister-link"
+ }, Strings.GetStringFromName("unregister"));
+ },
+
+ render() {
+ let { target } = this.props;
+ let { pushSubscription } = this.state;
+ let status = this.getServiceWorkerStatus();
+
+ return dom.div({ className: "target-container" },
+ dom.img({
+ className: "target-icon",
+ role: "presentation",
+ src: target.icon
+ }),
+ dom.span({ className: `target-status target-status-${status}` },
+ Strings.GetStringFromName(status)),
+ dom.div({ className: "target" },
+ dom.div({ className: "target-name", title: target.name }, target.name),
+ dom.ul({ className: "target-details" },
+ (pushSubscription ?
+ dom.li({ className: "target-detail" },
+ dom.strong(null, Strings.GetStringFromName("pushService")),
+ dom.span({
+ className: "service-worker-push-url",
+ title: pushSubscription.endpoint
+ }, pushSubscription.endpoint)) :
+ null
+ ),
+ dom.li({ className: "target-detail" },
+ dom.strong(null, Strings.GetStringFromName("scope")),
+ dom.span({
+ className: "service-worker-scope",
+ title: target.scope
+ }, target.scope),
+ this.renderUnregisterLink()
+ )
+ )
+ ),
+ this.renderButtons()
+ );
+ }
+});
diff --git a/devtools/client/aboutdebugging/components/workers/target.js b/devtools/client/aboutdebugging/components/workers/target.js
new file mode 100644
index 000000000..c1f6420ac
--- /dev/null
+++ b/devtools/client/aboutdebugging/components/workers/target.js
@@ -0,0 +1,57 @@
+/* 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/. */
+
+/* eslint-env browser */
+
+"use strict";
+
+const { createClass, DOM: dom, PropTypes } =
+ require("devtools/client/shared/vendor/react");
+const { debugWorker } = require("../../modules/worker");
+const Services = require("Services");
+
+loader.lazyRequireGetter(this, "DebuggerClient",
+ "devtools/shared/client/main", true);
+
+const Strings = Services.strings.createBundle(
+ "chrome://devtools/locale/aboutdebugging.properties");
+
+module.exports = createClass({
+ displayName: "WorkerTarget",
+
+ propTypes: {
+ client: PropTypes.instanceOf(DebuggerClient).isRequired,
+ debugDisabled: PropTypes.bool,
+ target: PropTypes.shape({
+ icon: PropTypes.string,
+ name: PropTypes.string.isRequired,
+ workerActor: PropTypes.string
+ }).isRequired
+ },
+
+ debug() {
+ let { client, target } = this.props;
+ debugWorker(client, target.workerActor);
+ },
+
+ render() {
+ let { target, debugDisabled } = this.props;
+
+ return dom.li({ className: "target-container" },
+ dom.img({
+ className: "target-icon",
+ role: "presentation",
+ src: target.icon
+ }),
+ dom.div({ className: "target" },
+ dom.div({ className: "target-name", title: target.name }, target.name)
+ ),
+ dom.button({
+ className: "debug-button",
+ onClick: this.debug,
+ disabled: debugDisabled
+ }, Strings.GetStringFromName("debug"))
+ );
+ }
+});