mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 753401 - The debugger server root and tab actors should be easily extensible; r=rcampbell
--HG-- rename : browser/devtools/debugger/test/browser_dbg_contextactor-02.js => browser/devtools/debugger/test/browser_dbg_globalactor-01.js
This commit is contained in:
parent
e092c900f4
commit
6658636165
@ -469,7 +469,6 @@ ChromeDebuggerProcess.prototype = {
|
||||
DebuggerServer.init(this._allowConnection);
|
||||
DebuggerServer.addBrowserActors();
|
||||
}
|
||||
DebuggerServer.closeListener();
|
||||
DebuggerServer.openListener(DebuggerPreferences.remotePort);
|
||||
},
|
||||
|
||||
@ -493,7 +492,7 @@ ChromeDebuggerProcess.prototype = {
|
||||
return true;
|
||||
}
|
||||
if (result == 2) {
|
||||
DebuggerServer.closeListener();
|
||||
DebuggerServer.closeListener(true);
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", false);
|
||||
}
|
||||
return false;
|
||||
|
@ -20,8 +20,7 @@ MOCHITEST_BROWSER_TESTS = \
|
||||
browser_dbg_listtabs.js \
|
||||
browser_dbg_tabactor-01.js \
|
||||
browser_dbg_tabactor-02.js \
|
||||
browser_dbg_contextactor-01.js \
|
||||
browser_dbg_contextactor-02.js \
|
||||
browser_dbg_globalactor-01.js \
|
||||
testactors.js \
|
||||
browser_dbg_nav-01.js \
|
||||
browser_dbg_propertyview-01.js \
|
||||
|
@ -1,49 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added context actor lifetimes.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "testContextActor1" }, function(aResponse) {
|
||||
ok(aResponse.actor, "testContextActor1 request should return an actor.");
|
||||
ok(aResponse.actor.indexOf("testone") >= 0,
|
||||
"testContextActor's actorPrefix should be used.");
|
||||
gClient.request({ to: aResponse.actor, type: "ping" }, function(aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should response to requests.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
removeTab(gTab1);
|
||||
finish();
|
||||
});
|
||||
};
|
@ -1,59 +0,0 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added context actor lifetimes.
|
||||
*/
|
||||
|
||||
var gTab1 = null;
|
||||
var gTab1Actor = null;
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
get_tab();
|
||||
});
|
||||
}
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
get_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: gTab1Actor, type: "attach" }, function(aResponse) {
|
||||
gClient.request({ to: gTab1Actor, type: "testContextActor1" }, function(aResponse) {
|
||||
navigate_tab(aResponse.actor);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function navigate_tab(aTestActor)
|
||||
{
|
||||
gClient.addOneTimeListener("tabNavigated", function(aEvent, aResponse) {
|
||||
gClient.request({ to: aTestActor, type: "ping" }, function(aResponse) {
|
||||
// TODO: Currently the client is supposed to clean up after tabNavigated
|
||||
// events. We should remove this check, or even better, remove the whole
|
||||
// test.
|
||||
todo(aResponse.error, "noSuchActor", "testContextActor1 should have gone away with the navigation.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
gTab1.linkedBrowser.loadURI(TAB2_URL);
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
removeTab(gTab1);
|
||||
finish();
|
||||
});
|
||||
}
|
36
browser/devtools/debugger/test/browser_dbg_globalactor-01.js
Normal file
36
browser/devtools/debugger/test/browser_dbg_globalactor-01.js
Normal file
@ -0,0 +1,36 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Check extension-added global actor API.
|
||||
*/
|
||||
|
||||
var gClient = null;
|
||||
|
||||
function test()
|
||||
{
|
||||
DebuggerServer.addActors("chrome://mochitests/content/browser/browser/devtools/debugger/test/testactors.js");
|
||||
|
||||
let transport = DebuggerServer.connectPipe();
|
||||
gClient = new DebuggerClient(transport);
|
||||
gClient.connect(function(aType, aTraits) {
|
||||
is(aType, "browser", "Root actor should identify itself as a browser.");
|
||||
gClient.listTabs(function(aResponse) {
|
||||
let globalActor = aResponse.testGlobalActor1;
|
||||
ok(globalActor, "Found the test tab actor.")
|
||||
ok(globalActor.indexOf("testone") >= 0,
|
||||
"testTabActor's actorPrefix should be used.");
|
||||
gClient.request({ to: globalActor, type: "ping" }, function(aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should respond to requests.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
{
|
||||
gClient.close(function() {
|
||||
finish();
|
||||
});
|
||||
}
|
@ -24,17 +24,15 @@ function test()
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function () {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
|
||||
ok(aResponse.actor, "testTabActor1 request should return an actor.");
|
||||
ok(aResponse.actor.indexOf("testone") >= 0,
|
||||
"testTabActor's actorPrefix should be used.");
|
||||
gClient.request({ to: aResponse.actor, type: "ping" }, function (aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should response to requests.");
|
||||
finish_test();
|
||||
});
|
||||
ok(aGrip.testTabActor1, "Found the test tab actor.")
|
||||
ok(aGrip.testTabActor1.indexOf("testone") >= 0,
|
||||
"testTabActor's actorPrefix should be used.");
|
||||
gClient.request({ to: aGrip.testTabActor1, type: "ping" }, function(aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should respond to requests.");
|
||||
finish_test();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -24,10 +24,14 @@ function test()
|
||||
|
||||
function get_tab()
|
||||
{
|
||||
gTab1 = addTab(TAB1_URL, function () {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function (aGrip) {
|
||||
gTab1 = addTab(TAB1_URL, function() {
|
||||
attach_tab_actor_for_url(gClient, TAB1_URL, function(aGrip) {
|
||||
gTab1Actor = aGrip.actor;
|
||||
gClient.request({ to: aGrip.actor, type: "testTabActor1" }, function (aResponse) {
|
||||
ok(aGrip.testTabActor1, "Found the test tab actor.")
|
||||
ok(aGrip.testTabActor1.indexOf("testone") >= 0,
|
||||
"testTabActor's actorPrefix should be used.");
|
||||
gClient.request({ to: aGrip.testTabActor1, type: "ping" }, function(aResponse) {
|
||||
is(aResponse.pong, "pong", "Actor should respond to requests.");
|
||||
close_tab(aResponse.actor);
|
||||
});
|
||||
});
|
||||
@ -37,10 +41,16 @@ function get_tab()
|
||||
function close_tab(aTestActor)
|
||||
{
|
||||
removeTab(gTab1);
|
||||
gClient.request({ to: aTestActor, type: "ping" }, function (aResponse) {
|
||||
is(aResponse.error, "noSuchActor", "testTabActor1 should have gone away with the tab.");
|
||||
try {
|
||||
gClient.request({ to: aTestActor, type: "ping" }, function (aResponse) {
|
||||
is(aResponse, undefined, "testTabActor1 didn't go away with the tab.");
|
||||
finish_test();
|
||||
});
|
||||
} catch (e) {
|
||||
is(e.message, "'ping' request packet has no destination.",
|
||||
"testTabActor1 should have gone away with the tab.");
|
||||
finish_test();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function finish_test()
|
||||
|
@ -24,6 +24,9 @@ let gEnableRemote = Services.prefs.getBoolPref("devtools.debugger.remote-enabled
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", gEnableRemote);
|
||||
|
||||
// Properly shut down the server to avoid memory leaks.
|
||||
DebuggerServer.destroy();
|
||||
});
|
||||
|
||||
if (!DebuggerServer.initialized) {
|
||||
|
@ -1,20 +1,15 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function TestActor1(aConnection, aTab, aOnDisconnect)
|
||||
function TestActor1(aConnection, aTab)
|
||||
{
|
||||
this.conn = aConnection;
|
||||
this.tab = aTab;
|
||||
this.onDisconnect = aOnDisconnect;
|
||||
}
|
||||
|
||||
TestActor1.prototype = {
|
||||
actorPrefix: "testone",
|
||||
|
||||
disconnect: function TA1_disconnect() {
|
||||
this.onDisconnect();
|
||||
},
|
||||
|
||||
grip: function TA1_grip() {
|
||||
return { actor: this.actorID,
|
||||
test: "TestActor1" };
|
||||
@ -29,30 +24,8 @@ TestActor1.prototype.requestTypes = {
|
||||
"ping": TestActor1.prototype.onPing
|
||||
};
|
||||
|
||||
DebuggerServer.addTabRequest("testTabActor1", function (aTab) {
|
||||
if (aTab._testTabActor1) {
|
||||
return aTab._testTabActor1.grip();
|
||||
}
|
||||
|
||||
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
|
||||
delete aTab._testTabActor1;
|
||||
});
|
||||
aTab.tabActorPool.addActor(actor);
|
||||
aTab._testTabActor1 = actor;
|
||||
return actor.grip();
|
||||
});
|
||||
|
||||
|
||||
DebuggerServer.addTabRequest("testContextActor1", function (aTab, aRequest) {
|
||||
if (aTab._testContextActor1) {
|
||||
return aTab._testContextActor1.grip();
|
||||
}
|
||||
|
||||
let actor = new TestActor1(aTab.conn, aTab.browser, function () {
|
||||
delete aTab._testContextActor1;
|
||||
});
|
||||
aTab.contextActorPool.addActor(actor);
|
||||
aTab._testContextActor1 = actor;
|
||||
return actor.grip();
|
||||
});
|
||||
DebuggerServer.removeTabActor(TestActor1);
|
||||
DebuggerServer.removeGlobalActor(TestActor1);
|
||||
|
||||
DebuggerServer.addTabActor(TestActor1, "testTabActor1");
|
||||
DebuggerServer.addGlobalActor(TestActor1, "testGlobalActor1");
|
||||
|
@ -31,20 +31,24 @@ function BrowserRootActor(aConnection)
|
||||
this.conn = aConnection;
|
||||
this._tabActors = new WeakMap();
|
||||
this._tabActorPool = null;
|
||||
this._actorFactories = null;
|
||||
// A map of actor names to actor instances provided by extensions.
|
||||
this._extraActors = {};
|
||||
|
||||
this.onTabClosed = this.onTabClosed.bind(this);
|
||||
windowMediator.addListener(this);
|
||||
}
|
||||
|
||||
BrowserRootActor.prototype = {
|
||||
|
||||
/**
|
||||
* Return a 'hello' packet as specified by the Remote Debugging Protocol.
|
||||
*/
|
||||
sayHello: function BRA_sayHello() {
|
||||
return { from: "root",
|
||||
applicationType: "browser",
|
||||
traits: [] };
|
||||
return {
|
||||
from: "root",
|
||||
applicationType: "browser",
|
||||
traits: {}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
@ -52,6 +56,7 @@ BrowserRootActor.prototype = {
|
||||
*/
|
||||
disconnect: function BRA_disconnect() {
|
||||
windowMediator.removeListener(this);
|
||||
this._extraActors = null;
|
||||
|
||||
// We may have registered event listeners on browser windows to
|
||||
// watch for tab closes, remove those.
|
||||
@ -77,7 +82,7 @@ BrowserRootActor.prototype = {
|
||||
// an ActorPool.
|
||||
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
let actorList = [];
|
||||
let tabActorList = [];
|
||||
|
||||
// Walk over open browser windows.
|
||||
let e = windowMediator.getEnumerator("navigator:browser");
|
||||
@ -95,7 +100,7 @@ BrowserRootActor.prototype = {
|
||||
let browsers = win.getBrowser().browsers;
|
||||
for each (let browser in browsers) {
|
||||
if (browser == selectedBrowser && win == top) {
|
||||
selected = actorList.length;
|
||||
selected = tabActorList.length;
|
||||
}
|
||||
let actor = this._tabActors.get(browser);
|
||||
if (!actor) {
|
||||
@ -104,10 +109,22 @@ BrowserRootActor.prototype = {
|
||||
this._tabActors.set(browser, actor);
|
||||
}
|
||||
actorPool.addActor(actor);
|
||||
actorList.push(actor);
|
||||
tabActorList.push(actor);
|
||||
}
|
||||
}
|
||||
|
||||
// Walk over global actors added by extensions.
|
||||
for (let name in DebuggerServer.globalActorFactories) {
|
||||
let actor = this._extraActors[name];
|
||||
if (!actor) {
|
||||
actor = DebuggerServer.globalActorFactories[name].bind(null, this.conn);
|
||||
actor.prototype = DebuggerServer.globalActorFactories[name].prototype;
|
||||
actor.parentID = this.actorID;
|
||||
this._extraActors[name] = actor;
|
||||
}
|
||||
actorPool.addActor(actor);
|
||||
}
|
||||
|
||||
// Now drop the old actorID -> actor map. Actors that still
|
||||
// mattered were added to the new map, others will go
|
||||
// away.
|
||||
@ -117,10 +134,16 @@ BrowserRootActor.prototype = {
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
|
||||
return { "from": "root",
|
||||
"selected": selected,
|
||||
"tabs": [actor.grip()
|
||||
for each (actor in actorList)] };
|
||||
let response = {
|
||||
"from": "root",
|
||||
"selected": selected,
|
||||
"tabs": [actor.grip() for (actor of tabActorList)]
|
||||
};
|
||||
for (let name in this._extraActors) {
|
||||
let actor = this._extraActors[name];
|
||||
response[name] = actor.actorID;
|
||||
}
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -203,6 +226,9 @@ function BrowserTabActor(aConnection, aBrowser, aTabBrowser)
|
||||
this.conn = aConnection;
|
||||
this._browser = aBrowser;
|
||||
this._tabbrowser = aTabBrowser;
|
||||
this._tabActorPool = null;
|
||||
// A map of actor names to actor instances provided by extensions.
|
||||
this._extraActors = {};
|
||||
|
||||
this._onWindowCreated = this.onWindowCreated.bind(this);
|
||||
}
|
||||
@ -245,6 +271,7 @@ BrowserTabActor.prototype = {
|
||||
this.conn.removeActor(aActor);
|
||||
},
|
||||
|
||||
// A constant prefix that will be used to form the actor ID by the server.
|
||||
actorPrefix: "tab",
|
||||
|
||||
grip: function BTA_grip() {
|
||||
@ -252,9 +279,35 @@ BrowserTabActor.prototype = {
|
||||
"grip() shouldn't be called on exited browser actor.");
|
||||
dbg_assert(this.actorID,
|
||||
"tab should have an actorID.");
|
||||
return { actor: this.actorID,
|
||||
title: this.browser.contentTitle,
|
||||
url: this.browser.currentURI.spec }
|
||||
|
||||
let response = {
|
||||
actor: this.actorID,
|
||||
title: this.browser.contentTitle,
|
||||
url: this.browser.currentURI.spec
|
||||
};
|
||||
|
||||
// Walk over tab actors added by extensions and add them to a new ActorPool.
|
||||
let actorPool = new ActorPool(this.conn);
|
||||
for (let name in DebuggerServer.tabActorFactories) {
|
||||
let actor = this._extraActors[name];
|
||||
if (!actor) {
|
||||
actor = DebuggerServer.tabActorFactories[name].bind(null, this.conn);
|
||||
actor.prototype = DebuggerServer.tabActorFactories[name].prototype;
|
||||
actor.parentID = this.actorID;
|
||||
this._extraActors[name] = actor;
|
||||
}
|
||||
actorPool.addActor(actor);
|
||||
}
|
||||
if (!actorPool.isEmpty()) {
|
||||
this._tabActorPool = actorPool;
|
||||
this.conn.addActorPool(this._tabActorPool);
|
||||
}
|
||||
|
||||
for (let name in this._extraActors) {
|
||||
let actor = this._extraActors[name];
|
||||
response[name] = actor.actorID;
|
||||
}
|
||||
return response;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -266,6 +319,7 @@ BrowserTabActor.prototype = {
|
||||
if (this._progressListener) {
|
||||
this._progressListener.destroy();
|
||||
}
|
||||
this._extraActors = null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -370,6 +424,10 @@ BrowserTabActor.prototype = {
|
||||
// Shut down actors that belong to this tab's pool.
|
||||
this.conn.removeActorPool(this._tabPool);
|
||||
this._tabPool = null;
|
||||
if (this._tabActorPool) {
|
||||
this.conn.removeActorPool(this._tabActorPool);
|
||||
this._tabActorPool = null;
|
||||
}
|
||||
|
||||
this._attached = false;
|
||||
},
|
||||
@ -535,9 +593,14 @@ DebuggerProgressListener.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
// DebuggerServer extension API.
|
||||
|
||||
/**
|
||||
* Registers handlers for new request types defined dynamically. This is used
|
||||
* for example by add-ons to augment the functionality of the tab actor.
|
||||
* Registers handlers for new tab-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the tab
|
||||
* actor.
|
||||
* TODO: remove this API in the next release after bug 753401 lands, once all
|
||||
* our experimental add-ons have been converted to the new API.
|
||||
*
|
||||
* @param aName string
|
||||
* The name of the new request type.
|
||||
@ -552,3 +615,79 @@ DebuggerServer.addTabRequest = function DS_addTabRequest(aName, aFunction) {
|
||||
return aFunction(this, aRequest);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers handlers for new tab-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the tab
|
||||
* actor.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
* @param aName string [optional]
|
||||
* The name of the new request type. If this is not present, the
|
||||
* actorPrefix property of the constructor prototype is used.
|
||||
*/
|
||||
DebuggerServer.addTabActor = function DS_addTabActor(aFunction, aName) {
|
||||
let name = aName ? aName : aFunction.prototype.actorPrefix;
|
||||
if (["title", "url", "actor"].indexOf(name) != -1) {
|
||||
throw Error(name + " is not allowed");
|
||||
}
|
||||
if (DebuggerServer.tabActorFactories.hasOwnProperty(name)) {
|
||||
throw Error(name + " already exists");
|
||||
}
|
||||
DebuggerServer.tabActorFactories[name] = aFunction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified tab-scoped request type.
|
||||
* This may be used for example by add-ons when shutting down or upgrading.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
*/
|
||||
DebuggerServer.removeTabActor = function DS_removeTabActor(aFunction) {
|
||||
for (let name in DebuggerServer.tabActorFactories) {
|
||||
let handler = DebuggerServer.tabActorFactories[name];
|
||||
if (handler.name == aFunction.name) {
|
||||
delete DebuggerServer.tabActorFactories[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers handlers for new browser-scoped request types defined dynamically.
|
||||
* This is used for example by add-ons to augment the functionality of the root
|
||||
* actor.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
* @param aName string [optional]
|
||||
* The name of the new request type. If this is not present, the
|
||||
* actorPrefix property of the constructor prototype is used.
|
||||
*/
|
||||
DebuggerServer.addGlobalActor = function DS_addGlobalActor(aFunction, aName) {
|
||||
let name = aName ? aName : aFunction.prototype.actorPrefix;
|
||||
if (["from", "tabs", "selected"].indexOf(name) != -1) {
|
||||
throw Error(name + " is not allowed");
|
||||
}
|
||||
if (DebuggerServer.globalActorFactories.hasOwnProperty(name)) {
|
||||
throw Error(name + " already exists");
|
||||
}
|
||||
DebuggerServer.globalActorFactories[name] = aFunction;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregisters the handler for the specified browser-scoped request type.
|
||||
* This may be used for example by add-ons when shutting down or upgrading.
|
||||
*
|
||||
* @param aFunction function
|
||||
* The constructor function for this request type.
|
||||
*/
|
||||
DebuggerServer.removeGlobalActor = function DS_removeGlobalActor(aFunction) {
|
||||
for (let name in DebuggerServer.globalActorFactories) {
|
||||
let handler = DebuggerServer.globalActorFactories[name];
|
||||
if (handler.name == aFunction.name) {
|
||||
delete DebuggerServer.globalActorFactories[name];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -60,6 +60,12 @@ var DebuggerServer = {
|
||||
_transportInitialized: false,
|
||||
xpcInspector: null,
|
||||
_allowConnection: null,
|
||||
// Number of currently open TCP connections.
|
||||
_socketConnections: 0,
|
||||
// Map of global actor names to actor constructors provided by extensions.
|
||||
globalActorFactories: null,
|
||||
// Map of tab actor names to actor constructors provided by extensions.
|
||||
tabActorFactories: null,
|
||||
|
||||
LONG_STRING_LENGTH: 10000,
|
||||
LONG_STRING_INITIAL_LENGTH: 1000,
|
||||
@ -79,6 +85,9 @@ var DebuggerServer = {
|
||||
this.xpcInspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
|
||||
this.initTransport(aAllowConnectionCallback);
|
||||
this.addActors("chrome://global/content/devtools/dbg-script-actors.js");
|
||||
|
||||
this.globalActorFactories = {};
|
||||
this.tabActorFactories = {};
|
||||
},
|
||||
|
||||
/**
|
||||
@ -100,7 +109,22 @@ var DebuggerServer = {
|
||||
this._allowConnection = aAllowConnectionCallback;
|
||||
},
|
||||
|
||||
get initialized() { return !!this.xpcInspector; },
|
||||
get initialized() { return !!this.globalActorFactories; },
|
||||
|
||||
/**
|
||||
* Performs cleanup tasks before shutting down the debugger server, if no
|
||||
* connections are currently open. Such tasks include clearing any actor
|
||||
* constructors added at runtime. This method should be called whenever a
|
||||
* debugger server is no longer useful, to avoid memory leaks. After this
|
||||
* method returns, the debugger server must be initialized again before use.
|
||||
*/
|
||||
destroy: function DH_destroy() {
|
||||
if (Object.keys(this._connections).length == 0) {
|
||||
dumpn("Shutting down debugger server.");
|
||||
delete this.globalActorFactories;
|
||||
delete this.tabActorFactories;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Load a subscript into the debugging global.
|
||||
@ -133,8 +157,9 @@ var DebuggerServer = {
|
||||
}
|
||||
this._checkInit();
|
||||
|
||||
// Return early if the server is already listening.
|
||||
if (this._listener) {
|
||||
throw "Debugging listener already open.";
|
||||
return true;
|
||||
}
|
||||
|
||||
let localOnly = false;
|
||||
@ -151,22 +176,32 @@ var DebuggerServer = {
|
||||
dumpn("Could not start debugging listener on port " + aPort + ": " + e);
|
||||
throw Cr.NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
this._socketConnections++;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Close a previously-opened TCP listener.
|
||||
*
|
||||
* @param aForce boolean [optional]
|
||||
* If set to true, then the socket will be closed, regardless of the
|
||||
* number of open connections.
|
||||
*/
|
||||
closeListener: function DH_closeListener() {
|
||||
closeListener: function DH_closeListener(aForce) {
|
||||
this._checkInit();
|
||||
|
||||
if (!this._listener) {
|
||||
if (!this._listener || this._socketConnections == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
// Only close the listener when the last connection is closed, or if the
|
||||
// aForce flag is passed.
|
||||
if (--this._socketConnections == 0 || aForce) {
|
||||
this._listener.close();
|
||||
this._listener = null;
|
||||
this._socketConnections = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
@ -244,10 +279,12 @@ var DebuggerServer = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove the connection from the debugging server.
|
||||
* Remove the connection from the debugging server and shut down the server
|
||||
* if no other connections are open.
|
||||
*/
|
||||
_connectionClosed: function DH_connectionClosed(aConnection) {
|
||||
delete this._connections[aConnection.prefix];
|
||||
this.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
@ -278,7 +315,11 @@ ActorPool.prototype = {
|
||||
addActor: function AP_addActor(aActor) {
|
||||
aActor.conn = this.conn;
|
||||
if (!aActor.actorID) {
|
||||
aActor.actorID = this.conn.allocID(aActor.actorPrefix || undefined);
|
||||
let prefix = aActor.actorPrefix;
|
||||
if (typeof aActor == "function") {
|
||||
prefix = aActor.prototype.actorPrefix;
|
||||
}
|
||||
aActor.actorID = this.conn.allocID(prefix || undefined);
|
||||
}
|
||||
|
||||
if (aActor.registeredPool) {
|
||||
@ -300,6 +341,13 @@ ActorPool.prototype = {
|
||||
return aActorID in this._actors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if the pool is empty.
|
||||
*/
|
||||
isEmpty: function AP_isEmpty() {
|
||||
return Object.keys(this._actors).length == 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove an actor from the actor pool.
|
||||
*/
|
||||
@ -437,6 +485,24 @@ DebuggerServerConnection.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// Dyamically-loaded actors have to be created lazily.
|
||||
if (typeof actor == "function") {
|
||||
let instance;
|
||||
try {
|
||||
instance = new actor();
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
this.transport.send({
|
||||
error: "unknownError",
|
||||
message: ("error occurred while creating actor '" + actor.name +
|
||||
"': " + safeErrorString(e))
|
||||
});
|
||||
}
|
||||
actor.registeredPool.addActor(instance);
|
||||
actor.registeredPool.removeActor(actor);
|
||||
actor = instance;
|
||||
}
|
||||
|
||||
var ret = null;
|
||||
|
||||
// Dispatch the request to the actor.
|
||||
|
@ -27,7 +27,12 @@ function really_long() {
|
||||
|
||||
function test_socket_conn()
|
||||
{
|
||||
DebuggerServer.openListener(2929);
|
||||
do_check_eq(DebuggerServer._socketConnections, 0);
|
||||
do_check_true(DebuggerServer.openListener(2929));
|
||||
do_check_eq(DebuggerServer._socketConnections, 1);
|
||||
// Make sure opening the listener twice does nothing.
|
||||
do_check_true(DebuggerServer.openListener(2929));
|
||||
do_check_eq(DebuggerServer._socketConnections, 1);
|
||||
|
||||
let unicodeString = "(╯°□°)╯︵ ┻━┻";
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2929);
|
||||
@ -54,7 +59,12 @@ function test_socket_conn()
|
||||
|
||||
function test_socket_shutdown()
|
||||
{
|
||||
DebuggerServer.closeListener();
|
||||
do_check_eq(DebuggerServer._socketConnections, 1);
|
||||
do_check_true(DebuggerServer.closeListener());
|
||||
do_check_eq(DebuggerServer._socketConnections, 0);
|
||||
// Make sure closing the listener twice does nothing.
|
||||
do_check_false(DebuggerServer.closeListener());
|
||||
do_check_eq(DebuggerServer._socketConnections, 0);
|
||||
|
||||
let transport = debuggerSocketConnect("127.0.0.1", 2929);
|
||||
transport.hooks = {
|
||||
|
Loading…
Reference in New Issue
Block a user