mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 898485 - [app manager] Implement an abstract connection manager. r=past
This commit is contained in:
parent
d9dfec89f5
commit
c446e895d6
@ -52,6 +52,7 @@ var BuiltinProvider = {
|
||||
"devtools/server": "resource://gre/modules/devtools/server",
|
||||
"devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
|
||||
"devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
|
||||
"devtools/client": "resource://gre/modules/devtools/client",
|
||||
|
||||
// Allow access to xpcshell test items from the loader.
|
||||
"xpcshell-test": "resource://test"
|
||||
@ -87,7 +88,7 @@ var SrcdirProvider = {
|
||||
let serverURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "server"));
|
||||
let webconsoleURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "webconsole"));
|
||||
let cssLogicURI = this.fileURI(OS.Path.join(toolkitURI, "styleinspector", "css-logic"));
|
||||
|
||||
let clientURI = this.fileURI(OS.Path.join(srcdir, "toolkit", "devtools", "client"));
|
||||
let mainURI = this.fileURI(OS.Path.join(srcdir, "browser", "devtools", "main.js"));
|
||||
this.loader = new loader.Loader({
|
||||
modules: {
|
||||
@ -97,6 +98,7 @@ var SrcdirProvider = {
|
||||
"": "resource://gre/modules/commonjs/",
|
||||
"devtools/server": serverURI,
|
||||
"devtools/toolkit/webconsole": webconsoleURI,
|
||||
"devtools/client": clientURI,
|
||||
"devtools": devtoolsURI,
|
||||
"devtools/styleinspector/css-logic": cssLogicURI,
|
||||
"main": mainURI
|
||||
|
@ -13,3 +13,4 @@ include $(topsrcdir)/config/rules.mk
|
||||
|
||||
libs::
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/*.jsm $(FINAL_TARGET)/modules/devtools
|
||||
$(INSTALL) $(IFLAGS1) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/client
|
||||
|
252
toolkit/devtools/client/connection-manager.js
Normal file
252
toolkit/devtools/client/connection-manager.js
Normal file
@ -0,0 +1,252 @@
|
||||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* 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";
|
||||
|
||||
const {Cu} = require("chrome");
|
||||
const {setTimeout, clearTimeout} = require('sdk/timers');
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
|
||||
/**
|
||||
* Connection Manager.
|
||||
*
|
||||
* To use this module:
|
||||
* const {ConnectionManager} = require("devtools/client/connection-manager");
|
||||
*
|
||||
* # ConnectionManager
|
||||
*
|
||||
* Methods:
|
||||
* ⬩ Connection createConnection(host, port)
|
||||
* ⬩ void destroyConnection(connection)
|
||||
*
|
||||
* Properties:
|
||||
* ⬩ Array connections
|
||||
*
|
||||
* # Connection
|
||||
*
|
||||
* A connection is a wrapper around a debugger client. It has a simple
|
||||
* API to instantiate a connection to a debugger server. Once disconnected,
|
||||
* no need to re-create a Connection object. Calling `connect()` again
|
||||
* will re-create a debugger client.
|
||||
*
|
||||
* Methods:
|
||||
* ⬩ connect() Connect to host:port. Expect a "connecting" event. If
|
||||
* host is not specified, a local pipe is used
|
||||
* ⬩ disconnect() Disconnect if connected. Expect a "disconnecting" event
|
||||
*
|
||||
* Properties:
|
||||
* ⬩ host IP address or hostname
|
||||
* ⬩ port Port
|
||||
* ⬩ logs Current logs. "newlog" event notifies new available logs
|
||||
* ⬩ store Reference to a local data store (see below)
|
||||
* ⬩ status Connection status:
|
||||
* Connection.Status.CONNECTED
|
||||
* Connection.Status.DISCONNECTED
|
||||
* Connection.Status.CONNECTING
|
||||
* Connection.Status.DISCONNECTING
|
||||
* Connection.Status.DESTROYED
|
||||
*
|
||||
* Events (as in event-emitter.js):
|
||||
* ⬩ Connection.Events.CONNECTING Trying to connect to host:port
|
||||
* ⬩ Connection.Events.CONNECTED Connection is successful
|
||||
* ⬩ Connection.Events.DISCONNECTING Trying to disconnect from server
|
||||
* ⬩ Connection.Events.DISCONNECTED Disconnected (at client request, or because of a timeout or connection error)
|
||||
* ⬩ Connection.Events.STATUS_CHANGED The connection status (connection.status) has changed
|
||||
* ⬩ Connection.Events.TIMEOUT Connection timeout
|
||||
* ⬩ Connection.Events.HOST_CHANGED Host has changed
|
||||
* ⬩ Connection.Events.PORT_CHANGED Port has changed
|
||||
* ⬩ Connection.Events.NEW_LOG A new log line is available
|
||||
*
|
||||
*/
|
||||
|
||||
let ConnectionManager = {
|
||||
_connections: new Set(),
|
||||
createConnection: function(host, port) {
|
||||
let c = new Connection(host, port);
|
||||
c.once("destroy", (event) => this.destroyConnection(c));
|
||||
this._connections.add(c);
|
||||
this.emit("new", c);
|
||||
return c;
|
||||
},
|
||||
destroyConnection: function(connection) {
|
||||
if (this._connections.has(connection)) {
|
||||
this._connections.delete(connection);
|
||||
if (connection.status != Connection.Status.DESTROYED) {
|
||||
connection.destroy();
|
||||
}
|
||||
}
|
||||
},
|
||||
get connections() {
|
||||
return [c for (c of this._connections)];
|
||||
},
|
||||
}
|
||||
|
||||
EventEmitter.decorate(ConnectionManager);
|
||||
|
||||
let lastID = -1;
|
||||
|
||||
function Connection(host, port) {
|
||||
EventEmitter.decorate(this);
|
||||
this.uid = ++lastID;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this._setStatus(Connection.Status.DISCONNECTED);
|
||||
this._onDisconnected = this._onDisconnected.bind(this);
|
||||
this._onConnected = this._onConnected.bind(this);
|
||||
this._onTimeout = this._onTimeout.bind(this);
|
||||
}
|
||||
|
||||
Connection.Status = {
|
||||
CONNECTED: "connected",
|
||||
DISCONNECTED: "disconnected",
|
||||
CONNECTING: "connecting",
|
||||
DISCONNECTING: "disconnecting",
|
||||
DESTROYED: "destroyed",
|
||||
}
|
||||
|
||||
Connection.Events = {
|
||||
CONNECTED: Connection.Status.CONNECTED,
|
||||
DISCONNECTED: Connection.Status.DISCONNECTED,
|
||||
CONNECTING: Connection.Status.CONNECTING,
|
||||
DISCONNECTING: Connection.Status.DISCONNECTING,
|
||||
DESTROYED: Connection.Status.DESTROYED,
|
||||
TIMEOUT: "timeout",
|
||||
STATUS_CHANGED: "status-changed",
|
||||
HOST_CHANGED: "host-changed",
|
||||
PORT_CHANGED: "port-changed",
|
||||
NEW_LOG: "new_log"
|
||||
}
|
||||
|
||||
Connection.prototype = {
|
||||
logs: "",
|
||||
log: function(str) {
|
||||
this.logs += "\n" + str;
|
||||
this.emit(Connection.Events.NEW_LOG, str);
|
||||
},
|
||||
|
||||
get client() {
|
||||
return this._client
|
||||
},
|
||||
|
||||
get host() {
|
||||
return this._host
|
||||
},
|
||||
|
||||
set host(value) {
|
||||
if (this._host && this._host == value)
|
||||
return;
|
||||
this._host = value;
|
||||
this.emit(Connection.Events.HOST_CHANGED);
|
||||
},
|
||||
|
||||
get port() {
|
||||
return this._port
|
||||
},
|
||||
|
||||
set port(value) {
|
||||
if (this._port && this._port == value)
|
||||
return;
|
||||
this._port = value;
|
||||
this.emit(Connection.Events.PORT_CHANGED);
|
||||
},
|
||||
|
||||
disconnect: function(force) {
|
||||
if (this.status == Connection.Status.DESTROYED) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(this._timeoutID);
|
||||
if (this.status == Connection.Status.CONNECTED ||
|
||||
this.status == Connection.Status.CONNECTING) {
|
||||
this.log("disconnecting");
|
||||
this._setStatus(Connection.Status.DISCONNECTING);
|
||||
this._client.close();
|
||||
}
|
||||
},
|
||||
|
||||
connect: function() {
|
||||
if (this.status == Connection.Status.DESTROYED) {
|
||||
return;
|
||||
}
|
||||
if (!this._client) {
|
||||
this.log("connecting to " + this.host + ":" + this.port);
|
||||
this._setStatus(Connection.Status.CONNECTING);
|
||||
let delay = Services.prefs.getIntPref("devtools.debugger.remote-timeout");
|
||||
this._timeoutID = setTimeout(this._onTimeout, delay);
|
||||
|
||||
let transport;
|
||||
if (!this._host) {
|
||||
transport = DebuggerServer.connectPipe();
|
||||
} else {
|
||||
transport = debuggerSocketConnect(this._host, this._port);
|
||||
}
|
||||
this._client = new DebuggerClient(transport);
|
||||
this._client.addOneTimeListener("closed", this._onDisconnected);
|
||||
this._client.connect(this._onConnected);
|
||||
} else {
|
||||
let msg = "Can't connect. Client is not fully disconnected";
|
||||
this.log(msg);
|
||||
throw new Error(msg);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.log("killing connection");
|
||||
clearTimeout(this._timeoutID);
|
||||
if (this._client) {
|
||||
this._client.close();
|
||||
this._client = null;
|
||||
}
|
||||
this._setStatus(Connection.Status.DESTROYED);
|
||||
},
|
||||
|
||||
get status() {
|
||||
return this._status
|
||||
},
|
||||
|
||||
_setStatus: function(value) {
|
||||
if (this._status && this._status == value)
|
||||
return;
|
||||
this._status = value;
|
||||
this.emit(value);
|
||||
this.emit(Connection.Events.STATUS_CHANGED, value);
|
||||
},
|
||||
|
||||
_onDisconnected: function() {
|
||||
clearTimeout(this._timeoutID);
|
||||
switch (this.status) {
|
||||
case Connection.Status.CONNECTED:
|
||||
this.log("disconnected (unexpected)");
|
||||
break;
|
||||
case Connection.Status.CONNECTING:
|
||||
this.log("Connection error");
|
||||
break;
|
||||
default:
|
||||
this.log("disconnected");
|
||||
}
|
||||
this._client = null;
|
||||
this._setStatus(Connection.Status.DISCONNECTED);
|
||||
},
|
||||
|
||||
_onConnected: function() {
|
||||
this.log("connected");
|
||||
clearTimeout(this._timeoutID);
|
||||
this._setStatus(Connection.Status.CONNECTED);
|
||||
},
|
||||
|
||||
_onTimeout: function() {
|
||||
this.log("connection timeout");
|
||||
this.emit(Connection.Events.TIMEOUT, str);
|
||||
this.disconnect();
|
||||
},
|
||||
}
|
||||
|
||||
exports.ConnectionManager = ConnectionManager;
|
||||
exports.Connection = Connection;
|
||||
|
@ -36,6 +36,7 @@ MOCHITEST_CHROME_FILES = \
|
||||
test_styles-modify.html \
|
||||
test_unsafeDereference.html \
|
||||
nonchrome_unsafeDereference.html \
|
||||
test_connection-manager.html \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
@ -0,0 +1,98 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Bug 898485 - [app manager] Implement an abstract connection manager
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mozilla Bug</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script>
|
||||
|
||||
window.onload = function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
|
||||
Cu.import("resource://gre/modules/devtools/Loader.jsm");
|
||||
|
||||
DebuggerServer.init(function () { return true; });
|
||||
DebuggerServer.addBrowserActors();
|
||||
|
||||
var {ConnectionManager, Connection} = devtools.require("devtools/client/connection-manager");
|
||||
|
||||
var orgCount = ConnectionManager.connections.length;
|
||||
|
||||
ConnectionManager.once("new", (event, c) => {
|
||||
is(ConnectionManager.connections[orgCount], c, "new event fired, with correct connection");
|
||||
});
|
||||
|
||||
var c1 = ConnectionManager.createConnection();
|
||||
var c2 = ConnectionManager.createConnection();
|
||||
|
||||
is(ConnectionManager.connections[orgCount], c1, "Connection 1 registered");
|
||||
is(ConnectionManager.connections[orgCount + 1], c2, "Connection 2 registered");
|
||||
|
||||
c1.once(Connection.Events.DESTROYED, function() {
|
||||
is(ConnectionManager.connections.length, orgCount + 1, "Connection 1 destroyed");
|
||||
|
||||
var c = c2;
|
||||
|
||||
var eventsRef = "connecting connected disconnecting disconnected host-changed disconnected destroyed";
|
||||
var events = [];
|
||||
|
||||
var s = Connection.Status;
|
||||
|
||||
is(c.status, s.DISCONNECTED, "disconnected");
|
||||
|
||||
c.once(Connection.Events.CONNECTING, function(e) { events.push(e); is(c.status, s.CONNECTING, "connecting"); });
|
||||
c.once(Connection.Events.CONNECTED, function(e) { events.push(e); is(c.status, s.CONNECTED, "connected"); c.disconnect()});
|
||||
c.once(Connection.Events.DISCONNECTING, function(e) { events.push(e); is(c.status, s.DISCONNECTING, "disconnecting"); });
|
||||
c.once(Connection.Events.DISCONNECTED, function(e) { events.push(e); is(c.status, s.DISCONNECTED, "disconnected"); testError()});
|
||||
c.once(Connection.Events.DESTROYED, function(e) { events.push(e); is(c.status, s.DESTROYED, "destroyed"); finish()});
|
||||
|
||||
c.connect();
|
||||
|
||||
function testStore() {
|
||||
c.store.on("set", function(e,path) {
|
||||
if (path.join(".") == "device.width") {
|
||||
is(c.store.object.device.width, window.screen.width, "Store is fed with valid data");
|
||||
c.disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testError() {
|
||||
c.once(Connection.Events.DISCONNECTED, function(e) {
|
||||
events.push(e);
|
||||
ConnectionManager.destroyConnection(c);
|
||||
});
|
||||
c.once(Connection.Events.HOST_CHANGED, function(e) {
|
||||
events.push(e);
|
||||
c.connect();
|
||||
});
|
||||
c.port = 1;
|
||||
c.host = "localhost";
|
||||
}
|
||||
|
||||
function finish() {
|
||||
is(events.join(" "), eventsRef, "Events received in the right order");
|
||||
DebuggerServer.destroy();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
ConnectionManager.destroyConnection(c1);
|
||||
|
||||
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user