Backed out 7 changesets (bug 1497457) for devtools failure at devtools/client/aboutdebugging-new/test/browser/browser_aboutdebugging_sidebar_usb_runtime_refresh.js on a CLOSED TREE

Backed out changeset d3b46f3a0306 (bug 1497457)
Backed out changeset bd490139b395 (bug 1497457)
Backed out changeset b2830500918c (bug 1497457)
Backed out changeset 9923755ee205 (bug 1497457)
Backed out changeset f2a39a18f2f6 (bug 1497457)
Backed out changeset 95365a2d7470 (bug 1497457)
Backed out changeset 0e93acc09952 (bug 1497457)

--HG--
extra : amend_source : cc8af90091ef2da669704e6a56a893bd5c72e136
This commit is contained in:
Daniel Varga 2018-11-27 00:59:34 +02:00
Родитель 37e525df6c
Коммит 2be7e87387
20 изменённых файлов: 42 добавлений и 356 удалений

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

@ -99,9 +99,6 @@ const AboutDebugging = {
await this.actions.unwatchRuntime(currentRuntimeId); await this.actions.unwatchRuntime(currentRuntimeId);
} }
// Remove all client listeners.
this.actions.removeRuntimeListeners();
removeNetworkLocationsObserver(this.onNetworkLocationsUpdated); removeNetworkLocationsObserver(this.onNetworkLocationsUpdated);
removeUSBRuntimesObserver(this.onUSBRuntimesUpdated); removeUSBRuntimesObserver(this.onUSBRuntimesUpdated);
disableUSBRuntimes(); disableUSBRuntimes();

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

@ -6,8 +6,6 @@
const { AddonManager } = require("resource://gre/modules/AddonManager.jsm"); const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
const { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser"); const { gDevToolsBrowser } = require("devtools/client/framework/devtools-browser");
const { remoteClientManager } =
require("devtools/client/shared/remote-debugging/remote-client-manager");
const { l10n } = require("../modules/l10n"); const { l10n } = require("../modules/l10n");
@ -46,10 +44,9 @@ function inspectDebugTarget(type, id) {
case DEBUG_TARGETS.TAB: { case DEBUG_TARGETS.TAB: {
// Open tab debugger in new window. // Open tab debugger in new window.
if (runtimeType === RUNTIMES.NETWORK || runtimeType === RUNTIMES.USB) { if (runtimeType === RUNTIMES.NETWORK || runtimeType === RUNTIMES.USB) {
// Pass the remote id from the client manager so that about:devtools-toolbox can const { host, port } = runtimeDetails.transportDetails;
// retrieve the connected client directly. window.open(`about:devtools-toolbox?type=tab&id=${id}` +
const remoteId = remoteClientManager.getRemoteId(runtime.id, runtime.type); `&host=${host}&port=${port}`);
window.open(`about:devtools-toolbox?type=tab&id=${id}&remoteId=${remoteId}`);
} else if (runtimeType === RUNTIMES.THIS_FIREFOX) { } else if (runtimeType === RUNTIMES.THIS_FIREFOX) {
window.open(`about:devtools-toolbox?type=tab&id=${id}`); window.open(`about:devtools-toolbox?type=tab&id=${id}`);
} }

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

@ -16,9 +16,6 @@ const { isSupportedDebugTarget } = require("../modules/debug-target-support");
const { createClientForRuntime } = require("../modules/runtime-client-factory"); const { createClientForRuntime } = require("../modules/runtime-client-factory");
const { remoteClientManager } =
require("devtools/client/shared/remote-debugging/remote-client-manager");
const { const {
CONNECT_RUNTIME_FAILURE, CONNECT_RUNTIME_FAILURE,
CONNECT_RUNTIME_START, CONNECT_RUNTIME_START,
@ -71,7 +68,7 @@ function connectRuntime(id) {
dispatch({ type: CONNECT_RUNTIME_START }); dispatch({ type: CONNECT_RUNTIME_START });
try { try {
const runtime = findRuntimeById(id, getState().runtimes); const runtime = findRuntimeById(id, getState().runtimes);
const clientWrapper = await createClientForRuntime(runtime); const { clientWrapper, transportDetails } = await createClientForRuntime(runtime);
const info = await getRuntimeInfo(runtime, clientWrapper); const info = await getRuntimeInfo(runtime, clientWrapper);
const promptPrefName = RUNTIME_PREFERENCE.CONNECTION_PROMPT; const promptPrefName = RUNTIME_PREFERENCE.CONNECTION_PROMPT;
@ -80,6 +77,7 @@ function connectRuntime(id) {
clientWrapper, clientWrapper,
connectionPromptEnabled, connectionPromptEnabled,
info, info,
transportDetails,
}; };
if (runtime.type === RUNTIMES.USB) { if (runtime.type === RUNTIMES.USB) {
@ -230,38 +228,12 @@ function updateUSBRuntimes(runtimes) {
} }
dispatch({ type: USB_RUNTIMES_UPDATED, runtimes }); dispatch({ type: USB_RUNTIMES_UPDATED, runtimes });
for (const runtime of getState().runtimes.usbRuntimes) {
const isConnected = !!runtime.runtimeDetails;
const hasConnectedClient = remoteClientManager.hasClient(runtime.id, runtime.type);
if (!isConnected && hasConnectedClient) {
await dispatch(connectRuntime(runtime.id));
}
}
};
}
/**
* Remove all the listeners added on client objects. Since those objects are persisted
* regardless of the about:debugging lifecycle, all the added events should be removed
* before leaving about:debugging.
*/
function removeRuntimeListeners() {
return (dispatch, getState) => {
const { usbRuntimes } = getState().runtimes;
for (const runtime of usbRuntimes) {
if (runtime.runtimeDetails) {
const { clientWrapper } = runtime.runtimeDetails;
clientWrapper.removeListener("closed", onUSBDebuggerClientClosed);
}
}
}; };
} }
module.exports = { module.exports = {
connectRuntime, connectRuntime,
disconnectRuntime, disconnectRuntime,
removeRuntimeListeners,
unwatchRuntime, unwatchRuntime,
updateConnectionPromptSetting, updateConnectionPromptSetting,
updateUSBRuntimes, updateUSBRuntimes,

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

@ -8,8 +8,6 @@ const { ADB } = require("devtools/shared/adb/adb");
const { DebuggerClient } = require("devtools/shared/client/debugger-client"); const { DebuggerClient } = require("devtools/shared/client/debugger-client");
const { DebuggerServer } = require("devtools/server/main"); const { DebuggerServer } = require("devtools/server/main");
const { ClientWrapper } = require("./client-wrapper"); const { ClientWrapper } = require("./client-wrapper");
const { remoteClientManager } =
require("devtools/client/shared/remote-debugging/remote-client-manager");
const { RUNTIMES } = require("../constants"); const { RUNTIMES } = require("../constants");
@ -18,14 +16,15 @@ async function createLocalClient() {
DebuggerServer.registerAllActors(); DebuggerServer.registerAllActors();
const client = new DebuggerClient(DebuggerServer.connectPipe()); const client = new DebuggerClient(DebuggerServer.connectPipe());
await client.connect(); await client.connect();
return new ClientWrapper(client); return { clientWrapper: new ClientWrapper(client) };
} }
async function createNetworkClient(host, port) { async function createNetworkClient(host, port) {
const transport = await DebuggerClient.socketConnect({ host, port }); const transportDetails = { host, port };
const transport = await DebuggerClient.socketConnect(transportDetails);
const client = new DebuggerClient(transport); const client = new DebuggerClient(transport);
await client.connect(); await client.connect();
return new ClientWrapper(client); return { clientWrapper: new ClientWrapper(client), transportDetails };
} }
async function createUSBClient(socketPath) { async function createUSBClient(socketPath) {
@ -34,13 +33,10 @@ async function createUSBClient(socketPath) {
} }
async function createClientForRuntime(runtime) { async function createClientForRuntime(runtime) {
const { extra, id, type } = runtime; const { extra, type } = runtime;
if (type === RUNTIMES.THIS_FIREFOX) { if (type === RUNTIMES.THIS_FIREFOX) {
return createLocalClient(); return createLocalClient();
} else if (remoteClientManager.hasClient(id, type)) {
const client = remoteClientManager.getClient(id, type);
return new ClientWrapper(client);
} else if (type === RUNTIMES.NETWORK) { } else if (type === RUNTIMES.NETWORK) {
const { host, port } = extra.connectionParameters; const { host, port } = extra.connectionParameters;
return createNetworkClient(host, port); return createNetworkClient(host, port);

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

@ -19,9 +19,6 @@ const {
findRuntimeById, findRuntimeById,
} = require("../modules/runtimes-state-helper"); } = require("../modules/runtimes-state-helper");
const { remoteClientManager } =
require("devtools/client/shared/remote-debugging/remote-client-manager");
// Map between known runtime types and nodes in the runtimes state. // Map between known runtime types and nodes in the runtimes state.
const TYPE_TO_RUNTIMES_KEY = { const TYPE_TO_RUNTIMES_KEY = {
[RUNTIMES.THIS_FIREFOX]: "thisFirefoxRuntimes", [RUNTIMES.THIS_FIREFOX]: "thisFirefoxRuntimes",
@ -73,14 +70,12 @@ function _updateRuntimeById(runtimeId, updatedRuntime, state) {
function runtimesReducer(state = RuntimesState(), action) { function runtimesReducer(state = RuntimesState(), action) {
switch (action.type) { switch (action.type) {
case CONNECT_RUNTIME_SUCCESS: { case CONNECT_RUNTIME_SUCCESS: {
const { id, runtimeDetails, type } = action.runtime; const { id, runtimeDetails } = action.runtime;
remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client);
return _updateRuntimeById(id, { runtimeDetails }, state); return _updateRuntimeById(id, { runtimeDetails }, state);
} }
case DISCONNECT_RUNTIME_SUCCESS: { case DISCONNECT_RUNTIME_SUCCESS: {
const { id, type } = action.runtime; const { id } = action.runtime;
remoteClientManager.removeClient(id, type);
return _updateRuntimeById(id, { runtimeDetails: null }, state); return _updateRuntimeById(id, { runtimeDetails: null }, state);
} }
@ -117,8 +112,8 @@ function runtimesReducer(state = RuntimesState(), action) {
const { runtimes } = action; const { runtimes } = action;
const usbRuntimes = runtimes.map(runtime => { const usbRuntimes = runtimes.map(runtime => {
const existingRuntime = findRuntimeById(runtime.id, state); const existingRuntime = findRuntimeById(runtime.id, state);
const existingRuntimeDetails = existingRuntime ? const existingRuntimeDetails =
existingRuntime.runtimeDetails : null; existingRuntime ? existingRuntime.runtimeDetails : null;
return { return {
id: runtime.id, id: runtime.id,

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

@ -22,6 +22,14 @@ const runtimeInfo = {
version: PropTypes.string.isRequired, version: PropTypes.string.isRequired,
}; };
const runtimeTransportDetails = {
// host name of tcp connection to debugger server
host: PropTypes.string.isRequired,
// port number of tcp connection to debugger server
port: PropTypes.number.isRequired,
};
const runtimeDetails = { const runtimeDetails = {
// ClientWrapper built using a DebuggerClient for the runtime // ClientWrapper built using a DebuggerClient for the runtime
clientWrapper: PropTypes.instanceOf(ClientWrapper).isRequired, clientWrapper: PropTypes.instanceOf(ClientWrapper).isRequired,
@ -31,6 +39,10 @@ const runtimeDetails = {
// runtime information // runtime information
info: PropTypes.shape(runtimeInfo).isRequired, info: PropTypes.shape(runtimeInfo).isRequired,
// tcp connection information,
// unavailable on this-firefox runtime
transportDetails: PropTypes.shape(runtimeTransportDetails),
}; };
const networkRuntimeConnectionParameter = { const networkRuntimeConnectionParameter = {

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

@ -27,7 +27,6 @@ skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug
[browser_aboutdebugging_debug-target-pane_empty.js] [browser_aboutdebugging_debug-target-pane_empty.js]
[browser_aboutdebugging_debug-target-pane_usb_runtime.js] [browser_aboutdebugging_debug-target-pane_usb_runtime.js]
[browser_aboutdebugging_navigate.js] [browser_aboutdebugging_navigate.js]
[browser_aboutdebugging_persist_connection.js]
[browser_aboutdebugging_sidebar_network_runtimes.js] [browser_aboutdebugging_sidebar_network_runtimes.js]
[browser_aboutdebugging_sidebar_usb_runtime.js] [browser_aboutdebugging_sidebar_usb_runtime.js]
[browser_aboutdebugging_sidebar_usb_runtime_connect.js] [browser_aboutdebugging_sidebar_usb_runtime_connect.js]

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

@ -1,50 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const RUNTIME_ID = "test-runtime-id";
const RUNTIME_DEVICE_NAME = "test device name";
const RUNTIME_APP_NAME = "TestApp";
/* import-globals-from mocks/head-usb-mocks.js */
Services.scriptloader.loadSubScript(CHROME_URL_ROOT + "mocks/head-usb-mocks.js", this);
// Test that remote runtime connections are persisted across about:debugging reloads.
add_task(async function() {
const usbMocks = new UsbMocks();
usbMocks.enableMocks();
registerCleanupFunction(() => usbMocks.disableMocks());
let { document, tab } = await openAboutDebugging();
const usbClient = usbMocks.createRuntime(RUNTIME_ID, {
name: RUNTIME_APP_NAME,
deviceName: RUNTIME_DEVICE_NAME,
});
usbMocks.emitUpdate();
await connectToRuntime(RUNTIME_DEVICE_NAME, RUNTIME_APP_NAME, document);
info("Reload about:debugging");
document = await reloadAboutDebugging(tab);
usbMocks.emitUpdate();
info("Wait until the remote runtime appears as connected");
await waitUntil(() => {
const sidebarItem = findSidebarItemByText(RUNTIME_DEVICE_NAME, document);
return sidebarItem && !sidebarItem.querySelector(".js-connect-button");
});
// Remove the runtime without emitting an update.
// This is what happens today when we simply close Firefox for Android.
info("Remove the runtime from the list of USB runtimes");
usbMocks.removeRuntime(RUNTIME_ID);
info("Emit 'closed' on the client and wait for the sidebar item to disappear");
usbClient._eventEmitter.emit("closed");
await waitUntil(() => !findSidebarItemByText(RUNTIME_DEVICE_NAME, document));
info("Remove the tab");
await removeTab(tab);
});

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

@ -59,7 +59,7 @@ function setupThisFirefoxMock() {
runtimeClientFactoryMock.createClientForRuntime = runtime => { runtimeClientFactoryMock.createClientForRuntime = runtime => {
const { RUNTIMES } = require("devtools/client/aboutdebugging-new/src/constants"); const { RUNTIMES } = require("devtools/client/aboutdebugging-new/src/constants");
if (runtime.id === RUNTIMES.THIS_FIREFOX) { if (runtime.id === RUNTIMES.THIS_FIREFOX) {
return thisFirefoxClient; return { clientWrapper: thisFirefoxClient };
} }
throw new Error("Unexpected runtime id " + runtime.id); throw new Error("Unexpected runtime id " + runtime.id);
}; };

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

@ -23,7 +23,7 @@ add_task(async function() {
runtimeClientFactoryMock.createClientForRuntime = runtime => { runtimeClientFactoryMock.createClientForRuntime = runtime => {
const { RUNTIMES } = require("devtools/client/aboutdebugging-new/src/constants"); const { RUNTIMES } = require("devtools/client/aboutdebugging-new/src/constants");
if (runtime.id === RUNTIMES.THIS_FIREFOX) { if (runtime.id === RUNTIMES.THIS_FIREFOX) {
return thisFirefoxClient; return { clientWrapper: thisFirefoxClient };
} }
throw new Error("Unexpected runtime id " + runtime.id); throw new Error("Unexpected runtime id " + runtime.id);
}; };

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

@ -32,10 +32,6 @@ registerCleanupFunction(async function() {
} }
const { ADB } = require("devtools/shared/adb/adb"); const { ADB } = require("devtools/shared/adb/adb");
await ADB.kill(); await ADB.kill();
const { remoteClientManager } =
require("devtools/client/shared/remote-debugging/remote-client-manager");
await remoteClientManager.removeAllClients();
}); });
/** /**
@ -50,37 +46,19 @@ async function openAboutDebugging(page, win) {
await enableNewAboutDebugging(); await enableNewAboutDebugging();
info("opening about:debugging"); info("opening about:debugging");
const tab = await addTab("about:debugging", { window: win }); const tab = await addTab("about:debugging", { window: win });
const browser = tab.linkedBrowser; const browser = tab.linkedBrowser;
const document = browser.contentDocument; const document = browser.contentDocument;
const window = browser.contentWindow; const window = browser.contentWindow;
await waitForInitialDispatch(window); const { AboutDebugging } = window;
return { tab, document, window }; await Promise.all([
}
async function reloadAboutDebugging(tab) {
info("reload about:debugging");
await refreshTab(tab);
const browser = tab.linkedBrowser;
const document = browser.contentDocument;
const window = browser.contentWindow;
await waitForInitialDispatch(window);
return document;
}
function waitForInitialDispatch(win) {
info("wait for the initial about debugging actions to be dispatched");
const { AboutDebugging } = win;
return Promise.all([
waitForDispatch(AboutDebugging.store, "REQUEST_EXTENSIONS_SUCCESS"), waitForDispatch(AboutDebugging.store, "REQUEST_EXTENSIONS_SUCCESS"),
waitForDispatch(AboutDebugging.store, "REQUEST_TABS_SUCCESS"), waitForDispatch(AboutDebugging.store, "REQUEST_TABS_SUCCESS"),
waitForDispatch(AboutDebugging.store, "REQUEST_WORKERS_SUCCESS"), waitForDispatch(AboutDebugging.store, "REQUEST_WORKERS_SUCCESS"),
]); ]);
return { tab, document, window };
} }
/** /**

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

@ -35,19 +35,6 @@ function createClientMock() {
removeListener: (evt, listener) => { removeListener: (evt, listener) => {
eventEmitter.off(evt, listener); eventEmitter.off(evt, listener);
}, },
client: {
addOneTimeListener: (evt, listener) => {
eventEmitter.once(evt, listener);
},
addListener: (evt, listener) => {
eventEmitter.on(evt, listener);
},
removeListener: (evt, listener) => {
eventEmitter.off(evt, listener);
},
},
// no-op // no-op
close: () => {}, close: () => {},
// no-op // no-op

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

@ -28,12 +28,6 @@ class UsbMocks {
return this._runtimes; return this._runtimes;
}; };
// refreshUSBRuntimes normally starts scan, which should ultimately fire the
// "runtime-list-updated" event.
this.usbRuntimesMock.refreshUSBRuntimes = () => {
this.emitUpdate();
};
// Prepare a fake observer to be able to emit events from this mock. // Prepare a fake observer to be able to emit events from this mock.
this._observerMock = addObserverMock(this.usbRuntimesMock); this._observerMock = addObserverMock(this.usbRuntimesMock);
@ -41,7 +35,7 @@ class UsbMocks {
this.runtimeClientFactoryMock = createRuntimeClientFactoryMock(); this.runtimeClientFactoryMock = createRuntimeClientFactoryMock();
this._clients = {}; this._clients = {};
this.runtimeClientFactoryMock.createClientForRuntime = runtime => { this.runtimeClientFactoryMock.createClientForRuntime = runtime => {
return this._clients[runtime.id]; return { clientWrapper: this._clients[runtime.id] };
}; };
// Add a client for THIS_FIREFOX, since about:debugging will start on the This Firefox // Add a client for THIS_FIREFOX, since about:debugging will start on the This Firefox

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

@ -7,8 +7,6 @@
const { TargetFactory } = require("devtools/client/framework/target"); const { TargetFactory } = require("devtools/client/framework/target");
const { DebuggerServer } = require("devtools/server/main"); const { DebuggerServer } = require("devtools/server/main");
const { DebuggerClient } = require("devtools/shared/client/debugger-client"); const { DebuggerClient } = require("devtools/shared/client/debugger-client");
const { remoteClientManager } =
require("devtools/client/shared/remote-debugging/remote-client-manager");
/** /**
* Construct a Target for a given URL object having various query parameters: * Construct a Target for a given URL object having various query parameters:
@ -41,14 +39,9 @@ const { remoteClientManager } =
*/ */
exports.targetFromURL = async function targetFromURL(url) { exports.targetFromURL = async function targetFromURL(url) {
const client = await clientFromURL(url); const client = await clientFromURL(url);
await client.connect();
const params = url.searchParams; const params = url.searchParams;
// Clients retrieved from the remote-client-manager are already connected.
if (!params.get("remoteId")) {
// Connect any other client.
await client.connect();
}
const type = params.get("type"); const type = params.get("type");
if (!type) { if (!type) {
throw new Error("targetFromURL, missing type parameter"); throw new Error("targetFromURL, missing type parameter");
@ -123,8 +116,6 @@ exports.targetFromURL = async function targetFromURL(url) {
* {String} The hostname or IP address to connect to. * {String} The hostname or IP address to connect to.
* port: * port:
* {Number} The TCP port to connect to, to use with `host` argument. * {Number} The TCP port to connect to, to use with `host` argument.
* remoteId:
* {String} Remote client id, for runtimes from the remote-client-manager
* ws: * ws:
* {Boolean} If true, connect via websocket instead of regular TCP connection. * {Boolean} If true, connect via websocket instead of regular TCP connection.
* *
@ -134,13 +125,6 @@ exports.targetFromURL = async function targetFromURL(url) {
*/ */
async function clientFromURL(url) { async function clientFromURL(url) {
const params = url.searchParams; const params = url.searchParams;
// If a remote id was provided we should already have a connected client available.
const remoteId = params.get("remoteId");
if (remoteId) {
return remoteClientManager.getClientByRemoteId(remoteId);
}
const host = params.get("host"); const host = params.get("host");
const port = params.get("port"); const port = params.get("port");
const webSocket = !!params.get("ws"); const webSocket = !!params.get("ws");

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

@ -13,7 +13,6 @@ TEST_HARNESS_FILES.xpcshell.devtools.client.shared.test += [
DIRS += [ DIRS += [
'components', 'components',
'redux', 'redux',
'remote-debugging',
'source-map', 'source-map',
'vendor', 'vendor',
'webpack', 'webpack',

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

@ -1,12 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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(
'remote-client-manager.js',
)
with Files('**'):
BUG_COMPONENT = ('DevTools', 'about:debugging')

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

@ -1,90 +0,0 @@
/* 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";
/**
* This class is designed to be a singleton shared by all DevTools to get access to
* existing clients created for remote debugging.
*/
class RemoteClientManager {
constructor() {
this._clients = new Map();
this._onClientClosed = this._onClientClosed.bind(this);
}
/**
* Store a remote client that is already connected.
*
* @param {String} id
* Remote runtime id (see devtools/client/aboutdebugging-new/src/types).
* @param {String} type
* Remote runtime type (see devtools/client/aboutdebugging-new/src/types).
* @param {DebuggerClient} client
*/
setClient(id, type, client) {
const key = this._getKey(id, type);
this._clients.set(key, client);
client.addOneTimeListener("closed", this._onClientClosed);
}
// See JSDoc for id, type from setClient.
hasClient(id, type) {
return this._clients.has(this._getKey(id, type));
}
// See JSDoc for id, type from setClient.
getClient(id, type) {
return this._clients.get(this._getKey(id, type));
}
// See JSDoc for id, type from setClient.
removeClient(id, type) {
const key = this._getKey(id, type);
this._removeClientByKey(key);
}
removeAllClients() {
const keys = [...this._clients.keys()];
for (const key of keys) {
this._removeClientByKey(key);
}
}
getRemoteId(id, type) {
return encodeURIComponent(this._getKey(id, type));
}
getClientByRemoteId(remoteId) {
const key = decodeURIComponent(remoteId);
return this._clients.get(key);
}
_getKey(id, type) {
return id + "-" + type;
}
_removeClientByKey(key) {
if (this.hasClient(key)) {
this.getClient(key).removeListener("closed", this._onClientClosed);
this._clients.delete(key);
}
}
/**
* Cleanup all closed clients when a "closed" notification is received from a client.
*/
_onClientClosed() {
const closedClientKeys = [...this._clients.keys()].filter(key => {
return this._clients.get(key)._closed;
});
for (const key of closedClientKeys) {
this._removeClientByKey(key);
}
}
}
// Expose a singleton of RemoteClientManager.
exports.remoteClientManager = new RemoteClientManager();

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

@ -27,12 +27,8 @@ function eventSource(proto) {
* Called when the event is fired. If the same listener * Called when the event is fired. If the same listener
* is added more than once, it will be called once per * is added more than once, it will be called once per
* addListener call. * addListener call.
* @param key function (optional)
* Key to use for removeListener, defaults to the listener. Used by helper method
* addOneTimeListener, which creates a custom listener. Use the original listener
* as key to allow to remove oneTimeListeners.
*/ */
proto.addListener = function(name, listener, key = listener) { proto.addListener = function(name, listener) {
if (typeof listener != "function") { if (typeof listener != "function") {
throw TypeError("Listeners must be functions."); throw TypeError("Listeners must be functions.");
} }
@ -41,7 +37,7 @@ function eventSource(proto) {
this._listeners = {}; this._listeners = {};
} }
this._getListeners(name).push({ key, callback: listener }); this._getListeners(name).push(listener);
}; };
/** /**
@ -57,14 +53,14 @@ function eventSource(proto) {
*/ */
proto.addOneTimeListener = function(name, listener) { proto.addOneTimeListener = function(name, listener) {
return new Promise(resolve => { return new Promise(resolve => {
const oneTimeListener = (eventName, ...rest) => { const l = (eventName, ...rest) => {
this.removeListener(name, listener); this.removeListener(name, l);
if (listener) { if (listener) {
listener(eventName, ...rest); listener(eventName, ...rest);
} }
resolve(rest[0]); resolve(rest[0]);
}; };
this.addListener(name, oneTimeListener, listener); this.addListener(name, l);
}); });
}; };
@ -87,7 +83,7 @@ function eventSource(proto) {
this._listeners[name] = []; this._listeners[name] = [];
} else { } else {
this._listeners[name] = this._listeners[name] =
this._listeners[name].filter(l => l.key != listener); this._listeners[name].filter(l => l != listener);
} }
}; };
@ -125,7 +121,7 @@ function eventSource(proto) {
for (const listener of listeners) { for (const listener of listeners) {
try { try {
listener.callback.apply(null, arguments); listener.apply(null, arguments);
} catch (e) { } catch (e) {
// Prevent a bad listener from interfering with the others. // Prevent a bad listener from interfering with the others.
DevToolsUtils.reportException("notify event '" + name + "'", e); DevToolsUtils.reportException("notify event '" + name + "'", e);

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

@ -1,67 +0,0 @@
/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const eventSource = require("devtools/shared/client/event-source");
// Test basic event-source APIs:
// - addListener
// - removeListener
// - addOneTimeListener
add_task(function() {
// Create a basic test object that can emit events using event-source.js
class TestClass {}
eventSource(TestClass.prototype);
const testObject = new TestClass();
testBasicAddRemoveListener(testObject);
info("Check that one time listeners are only triggered once");
testOneTimeListener(testObject);
info("Check that one time listeners can be removed");
testRemoveOneTimeListener(testObject);
});
function testBasicAddRemoveListener(testObject) {
let eventsReceived = 0;
const onTestEvent = () => eventsReceived++;
testObject.addListener("event-testBasicAddRemoveListener", onTestEvent);
testObject.emit("event-testBasicAddRemoveListener");
ok(eventsReceived === 1, "Event listener was triggered");
testObject.emit("event-testBasicAddRemoveListener");
ok(eventsReceived === 2, "Event listener was triggered again");
testObject.removeListener("event-testBasicAddRemoveListener", onTestEvent);
testObject.emit("event-testBasicAddRemoveListener");
ok(eventsReceived === 2, "Event listener was not triggered anymore");
}
function testOneTimeListener(testObject) {
let eventsReceived = 0;
const onTestEvent = () => eventsReceived++;
testObject.addOneTimeListener("event-testOneTimeListener", onTestEvent);
testObject.emit("event-testOneTimeListener");
ok(eventsReceived === 1, "Event listener was triggered");
testObject.emit("event-testOneTimeListener");
ok(eventsReceived === 1, "Event listener was not triggered again");
testObject.removeListener("event-testOneTimeListener", onTestEvent);
}
function testRemoveOneTimeListener(testObject) {
let eventsReceived = 0;
const onTestEvent = () => eventsReceived++;
testObject.addOneTimeListener("event-testRemoveOneTimeListener", onTestEvent);
testObject.removeListener("event-testRemoveOneTimeListener", onTestEvent);
testObject.emit("event-testRemoveOneTimeListener");
ok(eventsReceived === 0, "Event listener was already removed");
}

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

@ -16,7 +16,6 @@ support-files =
run-if = nightly_build run-if = nightly_build
[test_eventemitter_basic.js] [test_eventemitter_basic.js]
[test_eventemitter_static.js] [test_eventemitter_static.js]
[test_eventsource.js]
[test_fetch-bom.js] [test_fetch-bom.js]
[test_fetch-chrome.js] [test_fetch-chrome.js]
[test_fetch-file.js] [test_fetch-file.js]