From a1bf7bae1075314673b41cba8d3ea885a9051d2f Mon Sep 17 00:00:00 2001 From: Eric Seidel Date: Tue, 11 Nov 2014 10:29:21 -0800 Subject: [PATCH] Make it possible to have multiple InspectorBackends This will make it possible to connect a c++ inspector backend in addition to the JS one. We lose the feature of running multiple inspector servers in this patch, but we weren't using that feature and could easily add it back if we plan to use it. This patch has a *ton* of boilerplate code due to crbug.com/431911, hopefully that will be fixed soon and we can delete all the Impl nonsense. R=abarth@chromium.org Review URL: https://codereview.chromium.org/710043004 --- framework/inspector/inspector.sky | 1 - services/inspector/BUILD.gn | 4 - services/inspector/inspector.mojom | 5 +- services/inspector/inspector_frontend_impl.cc | 97 -------- services/inspector/inspector_frontend_impl.h | 56 ----- services/inspector/server.cc | 232 +++++++++++++++++- viewer/BUILD.gn | 7 +- viewer/services/inspector_impl.cc | 14 ++ 8 files changed, 244 insertions(+), 172 deletions(-) delete mode 100644 services/inspector/inspector_frontend_impl.cc delete mode 100644 services/inspector/inspector_frontend_impl.h diff --git a/framework/inspector/inspector.sky b/framework/inspector/inspector.sky index c4c8ec686..6e73f78f1 100644 --- a/framework/inspector/inspector.sky +++ b/framework/inspector/inspector.sky @@ -93,5 +93,4 @@ window.frontendConnection = new connection.Connection( inspector.InspectorFrontend.proxyClass); window.frontend = frontendConnection.remote; -frontend.listen(9898); diff --git a/services/inspector/BUILD.gn b/services/inspector/BUILD.gn index e2b11f2a8..eb52f0b00 100644 --- a/services/inspector/BUILD.gn +++ b/services/inspector/BUILD.gn @@ -5,8 +5,6 @@ import("//mojo/public/tools/bindings/mojom.gni") group("inspector") { - testonly = true - deps = [ ":sky_inspector_server", ] @@ -14,8 +12,6 @@ group("inspector") { shared_library("sky_inspector_server") { sources = [ - "inspector_frontend_impl.cc", - "inspector_frontend_impl.h", "server.cc", ] diff --git a/services/inspector/inspector.mojom b/services/inspector/inspector.mojom index 70a750317..4d65b4397 100644 --- a/services/inspector/inspector.mojom +++ b/services/inspector/inspector.mojom @@ -4,9 +4,12 @@ module sky; +interface InspectorServer { + Listen(int32 port) => (); +}; + [Client=InspectorBackend] interface InspectorFrontend { - Listen(int32 port); SendMessage(string message); }; diff --git a/services/inspector/inspector_frontend_impl.cc b/services/inspector/inspector_frontend_impl.cc deleted file mode 100644 index d88abd12d..000000000 --- a/services/inspector/inspector_frontend_impl.cc +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "sky/services/inspector/inspector_frontend_impl.h" - -#include "base/lazy_instance.h" -#include "net/server/http_server.h" -#include "net/socket/tcp_server_socket.h" - -namespace sky { -namespace inspector { -namespace { -const int kNotConnected = -1; -static base::LazyInstance> g_servers = - LAZY_INSTANCE_INITIALIZER; -} - -InspectorFrontendImpl::InspectorFrontendImpl() - : connection_id_(kNotConnected) { -} - -InspectorFrontendImpl::~InspectorFrontendImpl() { - StopListening(); -} - -void InspectorFrontendImpl::OnConnect(int connection_id) { -} - -void InspectorFrontendImpl::OnHttpRequest( - int connection_id, const net::HttpServerRequestInfo& info) { - web_server_->Send500(connection_id, "websockets protocol only"); -} - -void InspectorFrontendImpl::OnWebSocketRequest( - int connection_id, const net::HttpServerRequestInfo& info) { - if (connection_id_ != kNotConnected) { - web_server_->Close(connection_id); - return; - } - web_server_->AcceptWebSocket(connection_id, info); - connection_id_ = connection_id; - client()->OnConnect(); -} - -void InspectorFrontendImpl::OnWebSocketMessage( - int connection_id, const std::string& data) { - DCHECK_EQ(connection_id, connection_id_); - client()->OnMessage(data); -} - -void InspectorFrontendImpl::OnClose(int connection_id) { - if (connection_id != connection_id_) - return; - connection_id_ = kNotConnected; - client()->OnDisconnect(); -} - -void InspectorFrontendImpl::Listen(int32_t port) { - Register(port); - scoped_ptr server_socket( - new net::TCPServerSocket(NULL, net::NetLog::Source())); - server_socket->ListenWithAddressAndPort("0.0.0.0", port, 1); - web_server_.reset(new net::HttpServer(server_socket.Pass(), this)); -} - -void InspectorFrontendImpl::StopListening() { - if (!web_server_) - return; - web_server_.reset(); - Unregister(); -} - -void InspectorFrontendImpl::Register(int port) { - auto& servers = g_servers.Get(); - auto iter = servers.find(port); - if (iter != servers.end()) - iter->second->StopListening(); - DCHECK(servers.find(port) == servers.end()); - servers[port] = this; - port_ = port; -} - -void InspectorFrontendImpl::Unregister() { - DCHECK(g_servers.Get().find(port_)->second == this); - g_servers.Get().erase(port_); - port_ = kNotConnected; -} - -void InspectorFrontendImpl::SendMessage(const mojo::String& message) { - if (connection_id_ == kNotConnected) - return; - web_server_->SendOverWebSocket(connection_id_, message); -} - -} // namespace inspector -} // namespace sky diff --git a/services/inspector/inspector_frontend_impl.h b/services/inspector/inspector_frontend_impl.h deleted file mode 100644 index 652176035..000000000 --- a/services/inspector/inspector_frontend_impl.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef SKY_SERVICES_INSPECTOR_INSPECTOR_FRONTEND_IMPL_H_ -#define SKY_SERVICES_INSPECTOR_INSPECTOR_FRONTEND_IMPL_H_ - -#include "mojo/public/cpp/application/interface_factory_impl.h" -#include "mojo/public/cpp/bindings/interface_impl.h" -#include "net/server/http_server.h" -#include "net/socket/tcp_server_socket.h" -#include "sky/services/inspector/inspector.mojom.h" - -namespace sky { -namespace inspector { - -class InspectorFrontendImpl : public mojo::InterfaceImpl, - public net::HttpServer::Delegate { - public: - InspectorFrontendImpl(); - virtual ~InspectorFrontendImpl(); - - private: - // From net::HttpServer::Delegate - virtual void OnConnect(int connection_id) override; - virtual void OnHttpRequest( - int connection_id, const net::HttpServerRequestInfo& info) override; - virtual void OnWebSocketRequest( - int connection_id, const net::HttpServerRequestInfo& info) override; - virtual void OnWebSocketMessage( - int connection_id, const std::string& data) override; - virtual void OnClose(int connection_id) override; - - // From InspectorFrontend - virtual void Listen(int32_t port) override; - virtual void SendMessage(const mojo::String&) override; - - void StopListening(); - - void Register(int port); - void Unregister(); - - int port_; - int connection_id_; - scoped_ptr web_server_; - - MOJO_DISALLOW_COPY_AND_ASSIGN(InspectorFrontendImpl); -}; - -typedef mojo::InterfaceFactoryImpl< - InspectorFrontendImpl> InspectorFrontendFactory; - -} // namespace tester -} // namespace sky - -#endif // SKY_SERVICES_INSPECTOR_INSPECTOR_FRONTEND_IMPL_H_ diff --git a/services/inspector/server.cc b/services/inspector/server.cc index d052cc257..0963dd18b 100644 --- a/services/inspector/server.cc +++ b/services/inspector/server.cc @@ -6,32 +6,244 @@ #include "mojo/public/c/system/main.h" #include "mojo/public/cpp/application/application_delegate.h" #include "mojo/public/cpp/application/application_impl.h" -#include "sky/services/inspector/inspector_frontend_impl.h" +#include "mojo/public/cpp/application/interface_factory_impl.h" +#include "mojo/public/cpp/bindings/interface_impl.h" +#include "net/server/http_server.h" +#include "net/socket/tcp_server_socket.h" +#include "sky/services/inspector/inspector.mojom.h" + namespace sky { namespace inspector { -class Server : public mojo::ApplicationDelegate { +// TODO(eseidel): None of this Impl nonsense is necessary: crbug.com/431963 +class InspectorServerImpl : public mojo::InterfaceImpl { +public: + class Delegate { + public: + virtual void Register(InspectorServerImpl* impl) = 0; + virtual void Unregister(InspectorServerImpl* impl) = 0; + virtual void Listen(int32_t port) = 0; + }; + InspectorServerImpl(Delegate* delegate) : delegate_(delegate) { + delegate_->Register(this); + } + virtual ~InspectorServerImpl() { + delegate_->Unregister(this); + } + + // InspectorServer: + void Listen(int32_t port, const mojo::Callback& callback) override { + delegate_->Listen(port); + callback.Run(); + } + + void OnShutdown() { + delete this; + } + +private: + // InterfaceImpl: + void OnConnectionError() override { + delete this; // crbug.com/431911 + } + + Delegate* delegate_; +}; + +class InspectorFrontendImpl : public mojo::InterfaceImpl { public: - Server() {} - virtual ~Server() {} + class Delegate { + public: + virtual void Register(InspectorFrontendImpl*) = 0; + virtual void Unregister(InspectorFrontendImpl*) = 0; + virtual void SendMessage(const mojo::String&) = 0; + }; + + InspectorFrontendImpl(Delegate* delegate); + virtual ~InspectorFrontendImpl(); + + void OnShutdown(); private: - // Overridden from mojo::ApplicationDelegate: - virtual void Initialize(mojo::ApplicationImpl* app) override { - } + // InspectorFrontend: + void SendMessage(const mojo::String& message) override; + + // InterfaceImpl: + void OnConnectionError() override; + + Delegate* delegate_; + + MOJO_DISALLOW_COPY_AND_ASSIGN(InspectorFrontendImpl); +}; + +InspectorFrontendImpl::InspectorFrontendImpl(Delegate* delegate) + : delegate_(delegate) { + delegate_->Register(this); +} + +InspectorFrontendImpl::~InspectorFrontendImpl() { + delegate_->Unregister(this); +} + +void InspectorFrontendImpl::OnShutdown() { + client()->OnDisconnect(); + delete this; +} + +void InspectorFrontendImpl::OnConnectionError() { + delete this; // crbug.com/431911 +} - virtual bool ConfigureIncomingConnection( +void InspectorFrontendImpl::SendMessage(const mojo::String& message) { + delegate_->SendMessage(message); +} + + +namespace { +const int kNotConnected = -1; +} + +class Server : public mojo::ApplicationDelegate, + public InspectorFrontendImpl::Delegate, + public InspectorServerImpl::Delegate, + public mojo::InterfaceFactory, + public mojo::InterfaceFactory, + public net::HttpServer::Delegate { + public: + Server() : connection_id_(kNotConnected) {} + virtual ~Server(); + + private: + // mojo::ApplicationDelegate: + void Initialize(mojo::ApplicationImpl* app) override { + } + bool ConfigureIncomingConnection( mojo::ApplicationConnection* connection) override { - connection->AddService(&frontend_factory_); + connection->AddService(this); + connection->AddService(this); return true; } - InspectorFrontendFactory frontend_factory_; + // InterfaceFactory: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest request) override { + // Weak instead of strong, per crbug.com/431911 + WeakBindToRequest(new InspectorFrontendImpl(this), &request); + } + + // InterfaceFactory: + void Create(mojo::ApplicationConnection* connection, + mojo::InterfaceRequest request) override { + // Weak instead of strong, per crbug.com/431911 + WeakBindToRequest(new InspectorServerImpl(this), &request); + } + + // InspectorServerImpl::Delegate: + void Register(InspectorServerImpl*) override; + void Unregister(InspectorServerImpl*) override; + void Listen(int32_t port) override; + + // InspectorFrontendImpl::Delegate: + void Register(InspectorFrontendImpl*) override; + void Unregister(InspectorFrontendImpl*) override; + void SendMessage(const mojo::String& message) override; + + // net::HttpServer::Delegate: + void OnConnect(int connection_id) override; + void OnHttpRequest( + int connection_id, const net::HttpServerRequestInfo& info) override; + void OnWebSocketRequest( + int connection_id, const net::HttpServerRequestInfo& info) override; + void OnWebSocketMessage( + int connection_id, const std::string& data) override; + void OnClose(int connection_id) override; + + void CloseAllAgentConnections(); + + int connection_id_; + scoped_ptr web_server_; + ObserverList agents_; + ObserverList clients_; DISALLOW_COPY_AND_ASSIGN(Server); }; +Server::~Server() +{ + FOR_EACH_OBSERVER(InspectorServerImpl, clients_, OnShutdown()); + CloseAllAgentConnections(); +} + +void Server::CloseAllAgentConnections() { + FOR_EACH_OBSERVER(InspectorFrontendImpl, agents_, OnShutdown()); +} + +void Server::OnConnect(int connection_id) { +} + +void Server::OnHttpRequest( + int connection_id, const net::HttpServerRequestInfo& info) { + web_server_->Send500(connection_id, "websockets protocol only"); +} + +void Server::OnWebSocketRequest( + int connection_id, const net::HttpServerRequestInfo& info) { + if (connection_id_ != kNotConnected) { + web_server_->Close(connection_id); + return; + } + web_server_->AcceptWebSocket(connection_id, info); + connection_id_ = connection_id; + FOR_EACH_OBSERVER(InspectorFrontendImpl, agents_, client()->OnConnect()); +} + +void Server::OnWebSocketMessage( + int connection_id, const std::string& data) { + DCHECK_EQ(connection_id, connection_id_); + FOR_EACH_OBSERVER(InspectorFrontendImpl, agents_, client()->OnMessage(data)); +} + +void Server::OnClose(int connection_id) { + if (connection_id != connection_id_) + return; + connection_id_ = kNotConnected; + FOR_EACH_OBSERVER(InspectorFrontendImpl, agents_, client()->OnDisconnect()); +} + +void Server::Register(InspectorServerImpl* client) { + clients_.AddObserver(client); +} + +void Server::Unregister(InspectorServerImpl* client) { + clients_.RemoveObserver(client); +} + +void Server::Register(InspectorFrontendImpl* agent) { + agents_.AddObserver(agent); +} + +void Server::Unregister(InspectorFrontendImpl* agent) { + agents_.RemoveObserver(agent); +} + +void Server::Listen(int32_t port) { + CloseAllAgentConnections(); // Assume caller represents a new app. + + // TODO(eseidel): Early-out here if we're already bound to the right port. + web_server_.reset(); + scoped_ptr server_socket( + new net::TCPServerSocket(NULL, net::NetLog::Source())); + server_socket->ListenWithAddressAndPort("0.0.0.0", port, 1); + web_server_.reset(new net::HttpServer(server_socket.Pass(), this)); +} + +void Server::SendMessage(const mojo::String& message) { + if (connection_id_ == kNotConnected) + return; + web_server_->SendOverWebSocket(connection_id_, message); +} + } // namespace inspector } // namespace sky diff --git a/viewer/BUILD.gn b/viewer/BUILD.gn index 4018a3103..3b834d511 100644 --- a/viewer/BUILD.gn +++ b/viewer/BUILD.gn @@ -42,16 +42,18 @@ shared_library("viewer") { include_dirs = [ ".." ] deps = [ + ":bindings", + ":sky_modules", "//base:i18n", "//cc", "//cc/surfaces", "//gin", "//mojo/application", - "//mojo/edk/js", "//mojo/cc", "//mojo/common", "//mojo/converters/geometry", "//mojo/converters/surfaces", + "//mojo/edk/js", "//mojo/public/c/system:for_shared_library", "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", @@ -67,12 +69,11 @@ shared_library("viewer") { "//net", "//skia", "//sky/engine/public:blink", + "//sky/services/inspector:bindings", "//sky/viewer/cc", "//third_party/icu", "//ui/native_theme", "//url", - ":bindings", - ":sky_modules", ] } diff --git a/viewer/services/inspector_impl.cc b/viewer/services/inspector_impl.cc index a5343fa96..4c8d086f3 100644 --- a/viewer/services/inspector_impl.cc +++ b/viewer/services/inspector_impl.cc @@ -4,10 +4,12 @@ #include "sky/viewer/services/inspector_impl.h" +#include "base/bind.h" #include "sky/engine/public/web/WebDocument.h" #include "sky/engine/public/web/WebElement.h" #include "sky/engine/public/web/WebFrame.h" #include "sky/engine/public/web/WebView.h" +#include "sky/services/inspector/inspector.mojom.h" #include "sky/viewer/document_view.h" namespace sky { @@ -19,9 +21,21 @@ InspectorServiceImpl::InspectorServiceImpl(DocumentView* view) InspectorServiceImpl::~InspectorServiceImpl() { } +void Ignored() {} + void InspectorServiceImpl::Inject() { if (!view_) return; + + mojo::ServiceProviderPtr inpector_service_provider; + view_->shell()->ConnectToApplication("mojo:sky_inspector_server", + GetProxy(&inpector_service_provider)); + InspectorServerPtr inspector; + ConnectToService(inpector_service_provider.get(), &inspector); + inspector->Listen(9898, base::Bind(&Ignored)); + // Listen drops existing agents/backends, wait before registering new ones. + inspector.WaitForIncomingMethodCall(); + view_->web_view()->injectModule("/sky/framework/inspector/inspector.sky"); } -- GitLab