Bug 1005755 - Stop using Connector as a singleton; r=rickychien

MozReview-Commit-ID: tQKFiKDozA

--HG--
extra : rebase_source : f1392a9c909464d812e868dc3760e2f0d69fc8ae
This commit is contained in:
Jan Odvarko 2017-10-16 14:42:25 +02:00
Родитель 2b9694966e
Коммит b27a14a02a
25 изменённых файлов: 362 добавлений и 231 удалений

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

@ -14,7 +14,8 @@
<script>
"use strict";
const { BrowserLoader } = Components.utils.import("resource://devtools/client/shared/browser-loader.js", {});
const { BrowserLoader } = Components.utils.import(
"resource://devtools/client/shared/browser-loader.js", {});
const require = window.windowRequire = BrowserLoader({
baseURI: "resource://devtools/client/netmonitor/",
window,
@ -25,15 +26,23 @@
const { render, unmountComponentAtNode } = require("devtools/client/shared/vendor/react-dom");
const Provider = createFactory(require("devtools/client/shared/vendor/react-redux").Provider);
const { bindActionCreators } = require("devtools/client/shared/vendor/redux");
const { Connector } = require("./src/connector/index");
const { configureStore } = require("./src/utils/create-store");
const store = configureStore();
const actions = bindActionCreators(require("./src/actions/index"), store.dispatch);
const { onFirefoxConnect, onDisconnect } = require("./src/connector/index");
const App = createFactory(require("./src/components/app"));
const { getDisplayedRequestById } = require("./src/selectors/index");
const { EVENTS } = require("./src/constants");
// Inject EventEmitter into global window.
EventEmitter.decorate(window);
// Configure store/state object.
let connector = new Connector();
const store = configureStore(connector);
const actions = bindActionCreators(require("./src/actions/index"), store.dispatch);
// Inject to global window for testing
window.store = store;
window.connector = connector;
window.Netmonitor = {
bootstrap({ toolbox }) {
@ -53,17 +62,57 @@
top.openUILinkIn(link, "tab");
};
const App = createFactory(require("./src/components/app"));
// Render the root Application component.
const sourceMapService = toolbox.sourceMapURLService;
const app = App({ sourceMapService, openLink });
const app = App({ connector, openLink, sourceMapService });
render(Provider({ store }, app), this.mount);
return onFirefoxConnect(connection, actions, store.getState);
// Connect to the Firefox backend by default.
return connector.connectFirefox(connection, actions, store.getState);
},
destroy() {
unmountComponentAtNode(this.mount);
return onDisconnect();
return connector.disconnect();
},
/**
* Selects the specified request in the waterfall and opens the details view.
* This is a firefox toolbox specific API, which providing an ability to inspect
* a network request directly from other internal toolbox panel.
*
* @param {string} requestId The actor ID of the request to inspect.
* @return {object} A promise resolved once the task finishes.
*/
inspectRequest(requestId) {
// Look for the request in the existing ones or wait for it to appear, if
// the network monitor is still loading.
return new Promise((resolve) => {
let request = null;
let inspector = () => {
request = getDisplayedRequestById(store.getState(), requestId);
if (!request) {
// Reset filters so that the request is visible.
actions.toggleRequestFilterType("all");
request = getDisplayedRequestById(store.getState(), requestId);
}
// If the request was found, select it. Otherwise this function will be
// called again once new requests arrive.
if (request) {
window.off(EVENTS.REQUEST_ADDED, inspector);
actions.selectRequest(request.id);
resolve();
}
};
inspector();
if (!request) {
window.on(EVENTS.REQUEST_ADDED, inspector);
}
});
}
};
// Implement support for:

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

@ -13,7 +13,6 @@ const React = require("react");
const ReactDOM = require("react-dom");
const { bindActionCreators } = require("redux");
const { bootstrap, renderRoot } = require("devtools-launchpad");
const EventEmitter = require("devtools-modules/src/utils/event-emitter");
const { Services: { appinfo, pref }} = require("devtools-modules");
// Initialize preferences as early as possible
@ -39,15 +38,17 @@ pref("devtools.netmonitor.har.enableAutoExportToFile", false);
pref("devtools.netmonitor.persistlog", false);
pref("devtools.styleeditor.enabled", true);
const { configureStore } = require("./src/utils/create-store");
require("./src/assets/styles/netmonitor.css");
const EventEmitter = require("devtools-modules/src/utils/event-emitter");
EventEmitter.decorate(window);
const { configureStore } = require("./src/utils/create-store");
const App = require("./src/components/app");
const store = configureStore();
const { Connector } = require("./src/connector/index");
const connector = new Connector();
const store = configureStore(connector);
const actions = bindActionCreators(require("./src/actions"), store.dispatch);
const { onConnect } = require("./src/connector");
// Inject to global window for testing
window.store = store;
@ -80,6 +81,7 @@ bootstrap(React, ReactDOM).then((connection) => {
if (!connection) {
return;
}
renderRoot(React, ReactDOM, App, store);
onConnect(connection, actions, store.getState);
renderRoot(React, ReactDOM, App, store, {connector});
connector.connect(connection, actions, store.getState);
});

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

@ -4,7 +4,6 @@
"use strict";
const { sendHTTPRequest } = require("../connector/index");
const {
ADD_REQUEST,
CLEAR_REQUESTS,
@ -47,7 +46,7 @@ function cloneSelectedRequest() {
/**
* Send a new HTTP request using the data in the custom request form.
*/
function sendCustomRequest() {
function sendCustomRequest(connector) {
return (dispatch, getState) => {
const selected = getSelectedRequest(getState());
@ -68,7 +67,7 @@ function sendCustomRequest() {
data.body = selected.requestPostData.postData.text;
}
sendHTTPRequest(data, (response) => {
connector.sendHTTPRequest(data, (response) => {
return dispatch({
type: SEND_CUSTOM_REQUEST,
id: response.eventActor.actor,

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

@ -15,7 +15,6 @@ const {
TOGGLE_COLUMN,
WATERFALL_RESIZE,
} = require("../constants");
const { triggerActivity } = require("../connector/index");
/**
* Change network details panel.
@ -56,11 +55,12 @@ function disableBrowserCache(disabled) {
/**
* Change performance statistics panel open state.
*
* @param {Object} connector - connector object to the backend
* @param {boolean} visible - expected performance statistics panel open state
*/
function openStatistics(open) {
function openStatistics(connector, open) {
if (open) {
triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
connector.triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_ENABLED);
}
return {
type: OPEN_STATISTICS,
@ -139,9 +139,9 @@ function toggleBrowserCache() {
/**
* Toggle performance statistics panel.
*/
function toggleStatistics() {
function toggleStatistics(connector) {
return (dispatch, getState) =>
dispatch(openStatistics(!getState().ui.statisticsOpen));
dispatch(openStatistics(connector, !getState().ui.statisticsOpen));
}
module.exports = {

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

@ -17,18 +17,25 @@ const StatisticsPanel = createFactory(require("./statistics-panel"));
const { div } = DOM;
/*
/**
* App component
* The top level component for representing main panel
*/
function App({
connector,
openLink,
sourceMapService,
statisticsOpen,
}) {
return (
div({ className: "network-monitor" },
!statisticsOpen ? MonitorPanel({ openLink, sourceMapService }) : StatisticsPanel()
!statisticsOpen ? MonitorPanel({
connector,
sourceMapService,
openLink,
}) : StatisticsPanel({
connector
})
)
);
}
@ -36,9 +43,13 @@ function App({
App.displayName = "App";
App.propTypes = {
// The backend connector object.
connector: PropTypes.object.isRequired,
// Callback for opening links in the UI
openLink: PropTypes.func,
// Service to enable the source map feature.
sourceMapService: PropTypes.object,
// True if the stats panel is opened.
statisticsOpen: PropTypes.bool.isRequired,
};

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

@ -148,6 +148,7 @@ function CustomRequestPanel({
CustomRequestPanel.displayName = "CustomRequestPanel";
CustomRequestPanel.propTypes = {
connector: PropTypes.object.isRequired,
removeSelectedCustomRequest: PropTypes.func.isRequired,
request: PropTypes.object,
sendCustomRequest: PropTypes.func.isRequired,
@ -249,9 +250,9 @@ function updateCustomRequestFields(evt, request, updateRequest) {
module.exports = connect(
(state) => ({ request: getSelectedRequest(state) }),
(dispatch) => ({
(dispatch, props) => ({
removeSelectedCustomRequest: () => dispatch(Actions.removeSelectedCustomRequest()),
sendCustomRequest: () => dispatch(Actions.sendCustomRequest()),
sendCustomRequest: () => dispatch(Actions.sendCustomRequest(props.connector)),
updateRequest: (id, data, batch) => dispatch(Actions.updateRequest(id, data, batch)),
})
)(CustomRequestPanel);

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

@ -14,7 +14,6 @@ const {
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
const Actions = require("../actions/index");
const { getLongString } = require("../connector/index");
const { getFormDataSections } = require("../utils/request-utils");
const { getSelectedRequest } = require("../selectors/index");
@ -26,7 +25,7 @@ const Toolbar = createFactory(require("./toolbar"));
const { div } = DOM;
const MediaQueryList = window.matchMedia("(min-width: 700px)");
/*
/**
* Monitor panel component
* The main panel for displaying various network request information
*/
@ -34,11 +33,11 @@ const MonitorPanel = createClass({
displayName: "MonitorPanel",
propTypes: {
connector: PropTypes.object.isRequired,
isEmpty: PropTypes.bool.isRequired,
networkDetailsOpen: PropTypes.bool.isRequired,
openNetworkDetails: PropTypes.func.isRequired,
request: PropTypes.object,
// Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
updateRequest: PropTypes.func.isRequired,
@ -72,7 +71,7 @@ const MonitorPanel = createClass({
requestHeaders,
requestHeadersFromUploadStream,
requestPostData,
getLongString,
this.props.connector.getLongString,
).then((newFormDataSections) => {
updateRequest(
request.id,
@ -106,6 +105,7 @@ const MonitorPanel = createClass({
render() {
let {
connector,
isEmpty,
networkDetailsOpen,
sourceMapService,
@ -126,9 +126,10 @@ const MonitorPanel = createClass({
minSize: "50px",
maxSize: "80%",
splitterSize: "1px",
startPanel: RequestList({ isEmpty }),
startPanel: RequestList({ isEmpty, connector }),
endPanel: networkDetailsOpen && NetworkDetailsPanel({
ref: "endPanel",
connector,
sourceMapService,
openLink,
}),

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

@ -19,10 +19,11 @@ const TabboxPanel = createFactory(require("./tabbox-panel"));
const { div } = DOM;
/*
/**
* Network details panel component
*/
function NetworkDetailsPanel({
connector,
activeTabId,
cloneSelectedRequest,
request,
@ -40,12 +41,14 @@ function NetworkDetailsPanel({
TabboxPanel({
activeTabId,
cloneSelectedRequest,
connector,
openLink,
request,
selectTab,
sourceMapService,
openLink,
}) :
CustomRequestPanel({
connector,
request,
})
)
@ -55,12 +58,12 @@ function NetworkDetailsPanel({
NetworkDetailsPanel.displayName = "NetworkDetailsPanel";
NetworkDetailsPanel.propTypes = {
connector: PropTypes.object.isRequired,
activeTabId: PropTypes.string,
cloneSelectedRequest: PropTypes.func.isRequired,
open: PropTypes.bool,
request: PropTypes.object,
selectTab: PropTypes.func.isRequired,
// Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
};

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

@ -35,6 +35,7 @@ const RequestListContent = createClass({
displayName: "RequestListContent",
propTypes: {
connector: PropTypes.object.isRequired,
columns: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired,
displayedRequests: PropTypes.object.isRequired,
@ -51,10 +52,12 @@ const RequestListContent = createClass({
},
componentWillMount() {
const { dispatch } = this.props;
const { dispatch, connector } = this.props;
this.contextMenu = new RequestListContextMenu({
cloneSelectedRequest: () => dispatch(Actions.cloneSelectedRequest()),
openStatistics: (open) => dispatch(Actions.openStatistics(open)),
getTabTarget: connector.getTabTarget,
getLongString: connector.getLongString,
openStatistics: (open) => dispatch(Actions.openStatistics(connector, open)),
});
this.tooltip = new HTMLTooltip(window.parent.document, { type: "arrow" });
},
@ -156,8 +159,9 @@ const RequestListContent = createClass({
return false;
}
let { connector } = this.props;
if (requestItem.responseContent && target.closest(".requests-list-icon")) {
return setTooltipImageContent(tooltip, itemEl, requestItem);
return setTooltipImageContent(connector, tooltip, itemEl, requestItem);
}
return false;

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

@ -12,7 +12,6 @@ const {
} = require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const Actions = require("../actions/index");
const { triggerActivity } = require("../connector/index");
const { ACTIVITY_TYPE } = require("../constants");
const { L10N } = require("../utils/l10n");
const { getPerformanceAnalysisURL } = require("../utils/mdn-utils");
@ -37,6 +36,7 @@ const RequestListEmptyNotice = createClass({
displayName: "RequestListEmptyNotice",
propTypes: {
connector: PropTypes.object.isRequired,
onReloadClick: PropTypes.func.isRequired,
onPerfClick: PropTypes.func.isRequired,
},
@ -75,8 +75,9 @@ const RequestListEmptyNotice = createClass({
module.exports = connect(
undefined,
dispatch => ({
onPerfClick: () => dispatch(Actions.openStatistics(true)),
onReloadClick: () => triggerActivity(ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
(dispatch, props) => ({
onPerfClick: () => dispatch(Actions.openStatistics(props.connector, true)),
onReloadClick: () => props.connector.triggerActivity(
ACTIVITY_TYPE.RELOAD.WITH_CACHE_DEFAULT),
})
)(RequestListEmptyNotice);

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

@ -21,12 +21,15 @@ const { div } = DOM;
/**
* Request panel component
*/
function RequestList({ isEmpty }) {
function RequestList({
connector,
isEmpty,
}) {
return (
div({ className: "request-list-container" },
RequestListHeader(),
isEmpty ? RequestListEmptyNotice() : RequestListContent(),
StatusBar(),
isEmpty ? RequestListEmptyNotice({connector}) : RequestListContent({connector}),
StatusBar({connector}),
)
);
}
@ -34,6 +37,7 @@ function RequestList({ isEmpty }) {
RequestList.displayName = "RequestList";
RequestList.propTypes = {
connector: PropTypes.object.isRequired,
isEmpty: PropTypes.bool.isRequired,
};

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

@ -9,14 +9,18 @@ const {
DOM,
PropTypes,
} = require("devtools/client/shared/vendor/react");
const { viewSourceInDebugger } = require("../connector/index");
const { div } = DOM;
// Components
const StackTrace = createFactory(require("devtools/client/shared/components/StackTrace"));
/**
* This component represents a side panel responsible for
* rendering stack-trace info for selected request.
*/
function StackTracePanel({
connector,
openLink,
request,
sourceMapService,
@ -27,7 +31,9 @@ function StackTracePanel({
div({ className: "panel-container" },
StackTrace({
stacktrace,
onViewSourceInDebugger: ({ url, line }) => viewSourceInDebugger(url, line),
onViewSourceInDebugger: ({ url, line }) => {
return connector.viewSourceInDebugger(url, line);
},
sourceMapService,
openLink,
}),
@ -38,8 +44,8 @@ function StackTracePanel({
StackTracePanel.displayName = "StackTracePanel";
StackTracePanel.propTypes = {
connector: PropTypes.object.isRequired,
request: PropTypes.object.isRequired,
// Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
};

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

@ -44,6 +44,7 @@ const StatisticsPanel = createClass({
displayName: "StatisticsPanel",
propTypes: {
connector: PropTypes.object.isRequired,
closeStatistics: PropTypes.func.isRequired,
enableRequestFilterTypeOnly: PropTypes.func.isRequired,
requests: PropTypes.object,
@ -302,8 +303,8 @@ module.exports = connect(
(state) => ({
requests: state.requests.requests.valueSeq(),
}),
(dispatch) => ({
closeStatistics: () => dispatch(Actions.openStatistics(false)),
(dispatch, props) => ({
closeStatistics: () => dispatch(Actions.openStatistics(props.connector, false)),
enableRequestFilterTypeOnly: (label) =>
dispatch(Actions.enableRequestFilterTypeOnly(label)),
})

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

@ -88,6 +88,7 @@ function StatusBar({ summary, openStatistics, timingMarkers }) {
StatusBar.displayName = "StatusBar";
StatusBar.propTypes = {
connector: PropTypes.object.isRequired,
openStatistics: PropTypes.func.isRequired,
summary: PropTypes.object.isRequired,
timingMarkers: PropTypes.object.isRequired,
@ -102,7 +103,7 @@ module.exports = connect(
load: getDisplayedTimingMarker(state, "firstDocumentLoadTimestamp"),
},
}),
(dispatch) => ({
openStatistics: () => dispatch(Actions.openStatistics(true)),
(dispatch, props) => ({
openStatistics: () => dispatch(Actions.openStatistics(props.connector, true)),
}),
)(StatusBar);

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

@ -31,17 +31,18 @@ const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
const STACK_TRACE_TITLE = L10N.getStr("netmonitor.tab.stackTrace");
const TIMINGS_TITLE = L10N.getStr("netmonitor.tab.timings");
/*
/**
* Tabbox panel component
* Display the network request details
*/
function TabboxPanel({
activeTabId,
cloneSelectedRequest = ()=>{},
cloneSelectedRequest = () => {},
connector,
openLink,
request,
selectTab,
sourceMapService,
openLink,
}) {
if (!request) {
return null;
@ -90,7 +91,7 @@ function TabboxPanel({
id: PANELS.STACK_TRACE,
title: STACK_TRACE_TITLE,
},
StackTracePanel({ request, sourceMapService, openLink }),
StackTracePanel({ request, sourceMapService, openLink, connector }),
),
request.securityState && request.securityState !== "insecure" &&
TabPanel({
@ -108,11 +109,11 @@ TabboxPanel.displayName = "TabboxPanel";
TabboxPanel.propTypes = {
activeTabId: PropTypes.string,
cloneSelectedRequest: PropTypes.func,
connector: PropTypes.object.isRequired,
openLink: PropTypes.func,
request: PropTypes.object,
selectTab: PropTypes.func.isRequired,
// Service to enable the source map feature.
sourceMapService: PropTypes.object,
openLink: PropTypes.func,
};
module.exports = connect()(TabboxPanel);

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

@ -35,6 +35,14 @@ class ChromeConnector {
this.connector.disconnect();
}
pause() {
this.disconnect();
}
resume() {
this.setup();
}
/**
* currently all events are about "navigation" is not support on CDP
*/

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

@ -7,7 +7,6 @@
const Services = require("Services");
const { TimelineFront } = require("devtools/shared/fronts/timeline");
const { ACTIVITY_TYPE, EVENTS } = require("../constants");
const { getDisplayedRequestById } = require("../selectors/index");
const FirefoxDataProvider = require("./firefox-data-provider");
class FirefoxConnector {
@ -21,7 +20,6 @@ class FirefoxConnector {
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
this.setPreferences = this.setPreferences.bind(this);
this.triggerActivity = this.triggerActivity.bind(this);
this.inspectRequest = this.inspectRequest.bind(this);
this.getTabTarget = this.getTabTarget.bind(this);
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
@ -43,12 +41,7 @@ class FirefoxConnector {
actions: this.actions,
});
this.tabTarget.on("will-navigate", this.willNavigate);
this.tabTarget.on("close", this.disconnect);
this.webConsoleClient.on("networkEvent",
this.dataProvider.onNetworkEvent);
this.webConsoleClient.on("networkEventUpdate",
this.dataProvider.onNetworkEventUpdate);
this.addListeners();
// Don't start up waiting for timeline markers if the server isn't
// recent enough to emit the markers we're interested in.
@ -71,16 +64,38 @@ class FirefoxConnector {
await this.timelineFront.destroy();
}
this.tabTarget.off("will-navigate");
this.tabTarget.off("close");
this.removeListeners();
this.tabTarget = null;
this.webConsoleClient.off("networkEvent");
this.webConsoleClient.off("networkEventUpdate");
this.webConsoleClient = null;
this.timelineFront = null;
this.dataProvider = null;
}
pause() {
this.removeListeners();
}
resume() {
this.addListeners();
}
addListeners() {
this.tabTarget.on("will-navigate", this.willNavigate);
this.tabTarget.on("close", this.disconnect);
this.webConsoleClient.on("networkEvent",
this.dataProvider.onNetworkEvent);
this.webConsoleClient.on("networkEventUpdate",
this.dataProvider.onNetworkEventUpdate);
}
removeListeners() {
this.tabTarget.off("will-navigate");
this.tabTarget.off("close");
this.webConsoleClient.off("networkEvent");
this.webConsoleClient.off("networkEventUpdate");
}
willNavigate() {
if (!Services.prefs.getBoolPref("devtools.netmonitor.persistlog")) {
this.actions.batchReset();
@ -214,42 +229,6 @@ class FirefoxConnector {
return Promise.reject(new Error("Invalid activity type"));
}
/**
* Selects the specified request in the waterfall and opens the details view.
*
* @param {string} requestId The actor ID of the request to inspect.
* @return {object} A promise resolved once the task finishes.
*/
inspectRequest(requestId) {
// Look for the request in the existing ones or wait for it to appear, if
// the network monitor is still loading.
return new Promise((resolve) => {
let request = null;
let inspector = () => {
request = getDisplayedRequestById(this.getState(), requestId);
if (!request) {
// Reset filters so that the request is visible.
this.actions.toggleRequestFilterType("all");
request = getDisplayedRequestById(this.getState(), requestId);
}
// If the request was found, select it. Otherwise this function will be
// called again once new requests arrive.
if (request) {
window.off(EVENTS.REQUEST_ADDED, inspector);
this.actions.selectRequest(request.id);
resolve();
}
};
inspector();
if (!request) {
window.on(EVENTS.REQUEST_ADDED, inspector);
}
});
}
/**
* Fetches the network information packet from actor server
*

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

@ -3,83 +3,101 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
let connector = {};
function onConnect(connection, actions, getState) {
if (!connection || !connection.tab) {
return;
/**
* Generic connector wrapper object that is responsible for
* instantiating specific connector implementation according
* to the client type.
*/
class Connector {
constructor() {
this.connector = null;
// Bind public API
this.connect = this.connect.bind(this);
this.disconnect = this.disconnect.bind(this);
this.connectChrome = this.connectChrome.bind(this);
this.connectFirefox = this.connectFirefox.bind(this);
this.getLongString = this.getLongString.bind(this);
this.getNetworkRequest = this.getNetworkRequest.bind(this);
this.getTabTarget = this.getTabTarget.bind(this);
this.sendHTTPRequest = this.sendHTTPRequest.bind(this);
this.setPreferences = this.setPreferences.bind(this);
this.triggerActivity = this.triggerActivity.bind(this);
this.viewSourceInDebugger = this.viewSourceInDebugger.bind(this);
}
let { clientType } = connection.tab;
switch (clientType) {
case "chrome":
onChromeConnect(connection, actions, getState);
break;
case "firefox":
onFirefoxConnect(connection, actions, getState);
break;
default:
throw Error(`Unknown client type - ${clientType}`);
// Connect/Disconnect API
connect(connection, actions, getState) {
if (!connection || !connection.tab) {
return;
}
let { clientType } = connection.tab;
switch (clientType) {
case "chrome":
this.connectChrome(connection, actions, getState);
break;
case "firefox":
this.connectFirefox(connection, actions, getState);
break;
default:
throw Error(`Unknown client type - ${clientType}`);
}
}
disconnect() {
this.connector && this.connector.disconnect();
}
connectChrome(connection, actions, getState) {
this.connector = require("./chrome-connector");
this.connector.connect(connection, actions, getState);
}
connectFirefox(connection, actions, getState) {
this.connector = require("./firefox-connector");
this.connector.connect(connection, actions, getState);
}
pause() {
this.connector.pause();
}
resume() {
this.connector.resume();
}
// Public API
getLongString() {
return this.connector.getLongString(...arguments);
}
getNetworkRequest() {
return this.connector.getNetworkRequest(...arguments);
}
getTabTarget() {
return this.connector.getTabTarget();
}
sendHTTPRequest() {
return this.connector.sendHTTPRequest(...arguments);
}
setPreferences() {
return this.connector.setPreferences(...arguments);
}
triggerActivity() {
return this.connector.triggerActivity(...arguments);
}
viewSourceInDebugger() {
return this.connector.viewSourceInDebugger(...arguments);
}
}
function onDisconnect() {
connector && connector.disconnect();
}
function onChromeConnect(connection, actions, getState) {
connector = require("./chrome-connector");
connector.connect(connection, actions, getState);
}
function onFirefoxConnect(connection, actions, getState) {
connector = require("./firefox-connector");
connector.connect(connection, actions, getState);
}
function inspectRequest() {
return connector.inspectRequest(...arguments);
}
function getLongString() {
return connector.getLongString(...arguments);
}
function getNetworkRequest() {
return connector.getNetworkRequest(...arguments);
}
function getTabTarget() {
return connector.getTabTarget();
}
function sendHTTPRequest() {
return connector.sendHTTPRequest(...arguments);
}
function setPreferences() {
return connector.setPreferences(...arguments);
}
function triggerActivity() {
return connector.triggerActivity(...arguments);
}
function viewSourceInDebugger() {
return connector.viewSourceInDebugger(...arguments);
}
module.exports = {
onConnect,
onChromeConnect,
onFirefoxConnect,
onDisconnect,
getLongString,
getNetworkRequest,
getTabTarget,
inspectRequest,
sendHTTPRequest,
setPreferences,
triggerActivity,
viewSourceInDebugger,
};
module.exports.Connector = Connector;

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

@ -16,10 +16,9 @@ function* throttleUploadTest(actuallyThrottle) {
info("Starting test... (actuallyThrottle = " + actuallyThrottle + ")");
let { store, windowRequire } = monitor.panelWin;
let { connector, store, windowRequire } = monitor.panelWin;
let Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
let { setPreferences } =
windowRequire("devtools/client/netmonitor/src/connector/index");
let setPreferences = () => connector.setPreferences;
let RequestListContextMenu = windowRequire(
"devtools/client/netmonitor/src/request-list-context-menu");

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

@ -8,15 +8,32 @@ const {
TOGGLE_RECORDING,
} = require("../constants");
const {
getRecordingState,
} = require("../selectors/index");
/**
* Start/stop HTTP traffic recording.
*
* The UI state of the toolbar toggle button is stored in UI
* reducer and the backend connection is managed here in the
* middleware.
*/
function recordingMiddleware(store) {
return next => action => {
function recordingMiddleware(connector) {
return store => next => action => {
const res = next(action);
// Pause/resume HTTP monitoring according to
// the user action.
if (action.type === TOGGLE_RECORDING) {
// TODO connect/disconnect the backend.
let recording = getRecordingState(store.getState());
if (recording) {
connector.resume();
} else {
connector.pause();
}
}
return res;
};
}

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

@ -10,10 +10,6 @@ const { gDevTools } = require("devtools/client/framework/devtools");
const { saveAs } = require("devtools/client/shared/file-saver");
const { copyString } = require("devtools/shared/platform/clipboard");
const { HarExporter } = require("./har/har-exporter");
const {
getLongString,
getTabTarget,
} = require("./connector/index");
const {
getSelectedRequest,
getSortedRequests,
@ -28,9 +24,13 @@ const {
function RequestListContextMenu({
cloneSelectedRequest,
getLongString,
getTabTarget,
openStatistics,
}) {
this.cloneSelectedRequest = cloneSelectedRequest;
this.getLongString = getLongString;
this.getTabTarget = getTabTarget;
this.openStatistics = openStatistics;
}
@ -239,7 +239,7 @@ RequestListContextMenu.prototype = {
* Opens selected item in the debugger
*/
openInDebugger() {
let toolbox = gDevTools.getToolbox(getTabTarget());
let toolbox = gDevTools.getToolbox(this.getTabTarget());
toolbox.viewSourceInDebugger(this.selectedRequest.url, 0);
},
@ -247,7 +247,7 @@ RequestListContextMenu.prototype = {
* Opens selected item in the style editor
*/
openInStyleEditor() {
let toolbox = gDevTools.getToolbox(getTabTarget());
let toolbox = gDevTools.getToolbox(this.getTabTarget());
toolbox.viewSourceInStyleEditor(this.selectedRequest.url, 0);
},
@ -387,11 +387,11 @@ RequestListContextMenu.prototype = {
},
getDefaultHarOptions() {
let form = getTabTarget().form;
let form = this.getTabTarget().form;
let title = form.title || form.url;
return {
getString: getLongString,
getString: this.getLongString,
items: this.sortedRequests,
title: title
};

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

@ -8,19 +8,18 @@ const {
setImageTooltip,
getImageDimensions,
} = require("devtools/client/shared/widgets/tooltip/ImageTooltipHelper");
const { getLongString } = require("./connector/index");
const { formDataURI } = require("./utils/request-utils");
const REQUESTS_TOOLTIP_IMAGE_MAX_DIM = 400; // px
async function setTooltipImageContent(tooltip, itemEl, requestItem) {
async function setTooltipImageContent(connector, tooltip, itemEl, requestItem) {
let { mimeType, text, encoding } = requestItem.responseContent.content;
if (!mimeType || !mimeType.includes("image/")) {
return false;
}
let string = await getLongString(text);
let string = await connector.getLongString(text);
let src = formDataURI(mimeType, encoding, string);
let maxDim = REQUESTS_TOOLTIP_IMAGE_MAX_DIM;
let { naturalWidth, naturalHeight } = await getImageDimensions(tooltip.doc, src);

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

@ -6,9 +6,14 @@
const Services = require("Services");
const { applyMiddleware, createStore } = require("devtools/client/shared/vendor/redux");
// Middleware
const batching = require("../middleware/batching");
const prefs = require("../middleware/prefs");
const thunk = require("../middleware/thunk");
const recording = require("../middleware/recording");
// Reducers
const rootReducer = require("../reducers/index");
const { FilterTypes, Filters } = require("../reducers/filters");
const { Requests } = require("../reducers/requests");
@ -16,21 +21,40 @@ const { Sort } = require("../reducers/sort");
const { TimingMarkers } = require("../reducers/timing-markers");
const { UI, Columns } = require("../reducers/ui");
function configureStore() {
const getPref = (pref) => {
try {
return JSON.parse(Services.prefs.getCharPref(pref));
} catch (_) {
return [];
}
/**
* Configure state and middleware for the Network monitor tool.
*/
function configureStore(connector) {
// Prepare initial state.
const initialState = {
filters: new Filters({
requestFilterTypes: getFilterState()
}),
requests: new Requests(),
sort: new Sort(),
timingMarkers: new TimingMarkers(),
ui: new UI({
columns: getColumnState()
}),
};
let activeFilters = {};
let filters = getPref("devtools.netmonitor.filters");
filters.forEach((filter) => {
activeFilters[filter] = true;
});
// Prepare middleware.
let middleware = applyMiddleware(
thunk,
prefs,
batching,
recording(connector)
);
return createStore(rootReducer, initialState, middleware);
}
// Helpers
/**
* Get column state from preferences.
*/
function getColumnState() {
let columns = new Columns();
let visibleColumns = getPref("devtools.netmonitor.visibleColumns");
@ -40,19 +64,27 @@ function configureStore() {
});
}
const initialState = {
filters: new Filters({
requestFilterTypes: new FilterTypes(activeFilters)
}),
requests: new Requests(),
sort: new Sort(),
timingMarkers: new TimingMarkers(),
ui: new UI({
columns,
}),
};
return columns;
}
return createStore(rootReducer, initialState, applyMiddleware(thunk, prefs, batching));
/**
* Get filter state from preferences.
*/
function getFilterState() {
let activeFilters = {};
let filters = getPref("devtools.netmonitor.filters");
filters.forEach((filter) => {
activeFilters[filter] = true;
});
return new FilterTypes(activeFilters);
}
function getPref(pref) {
try {
return JSON.parse(Services.prefs.getCharPref(pref));
} catch (_) {
return [];
}
}
exports.configureStore = configureStore;

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

@ -139,9 +139,7 @@ NewConsoleOutputWrapper.prototype = {
),
openNetworkPanel: (requestId) => {
return this.toolbox.selectTool("netmonitor").then((panel) => {
let { inspectRequest } = panel.panelWin.windowRequire(
"devtools/client/netmonitor/src/connector/index");
return inspectRequest(requestId);
return panel.panelWin.Netmonitor.inspectRequest(requestId);
});
},
sourceMapService: this.toolbox ? this.toolbox.sourceMapURLService : null,

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

@ -1849,14 +1849,11 @@ WebConsoleFrame.prototype = {
openNetworkPanel: function (requestId) {
let toolbox = gDevTools.getToolbox(this.owner.target);
// The browser console doesn't have a toolbox.
if (!toolbox) {
return;
if (toolbox) {
return toolbox.selectTool("netmonitor").then(panel => {
return panel.panelWin.Netmonitor.inspectRequest(requestId);
});
}
return toolbox.selectTool("netmonitor").then(panel => {
let { inspectRequest } = panel.panelWin.windowRequire(
"devtools/client/netmonitor/src/connector/index");
return inspectRequest(requestId);
});
},
/**