blob: dee3828ab672a9a2f76d405d06248e8c7cfba86b [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "fuchsia_web/webinstance_host/fuchsia_web_debug_proxy.h"
#include <lib/fidl/cpp/binding.h>
#include "base/check.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/logging.h"
namespace {
// Proxies notifications from a DevToolsPerContextListener channel connected
// to a web container, to the specified set of DevToolsListeners.
class PerContextListenerProxy final
: public fuchsia::web::DevToolsPerContextListener {
public:
PerContextListenerProxy(
fidl::InterfaceRequest<fuchsia::web::DevToolsPerContextListener> request,
const fidl::InterfacePtrSet<fuchsia::web::DevToolsListener>& clients)
: binding_(this, std::move(request)) {
// Notify clients of the newly-available per-Context DevTools.
for (const auto& client : clients.ptrs()) {
fidl::InterfaceHandle<fuchsia::web::DevToolsPerContextListener> handle;
(*client)->OnContextDevToolsAvailable(handle.NewRequest());
auto ptr = std::make_unique<
fidl::InterfacePtr<fuchsia::web::DevToolsPerContextListener>>(
handle.Bind());
// If the client disconnects then remove it. If no clients remain then
// delete this proxy.
ptr->set_error_handler([this, client = ptr.get()](zx_status_t status) {
ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status);
clients_.erase(client);
if (clients_.empty())
delete this;
});
clients_.insert(std::move(ptr));
}
// Delete this proxy if the instance goes-away.
binding_.set_error_handler([this](zx_status_t status) {
ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status);
delete this;
});
}
~PerContextListenerProxy() override = default;
// fuchsia::web::DevToolsPerContextListener implementation.
void OnHttpPortOpen(uint16_t port) override {
for (const auto& client : clients_) {
(*client)->OnHttpPortOpen(port);
}
}
private:
fidl::Binding<fuchsia::web::DevToolsPerContextListener> binding_;
// Connections to clients to which to propagate updates.
base::flat_set<std::unique_ptr<fidl::InterfacePtr<
fuchsia::web::DevToolsPerContextListener>>,
base::UniquePtrComparator>
clients_;
};
} // namespace
FuchsiaWebDebugProxy::FuchsiaWebDebugProxy() = default;
FuchsiaWebDebugProxy::~FuchsiaWebDebugProxy() = default;
void FuchsiaWebDebugProxy::EnableDevTools(
fidl::InterfaceHandle<fuchsia::web::DevToolsListener> listener,
EnableDevToolsCallback callback) {
// Add the listener to the active set, but do not inform it of any debuggable
// instances that already exist, since callers are expected to only start
// creating new instances after the callback has returned.
devtools_listeners_.AddInterfacePtr(listener.Bind());
// If there were statically-configured fuchsia.web.Debug instances configured
// then they should be connected-to here, and |callback()| invoked only
// when each static instance' |EnableDevTools()| call had completed, or
// failed.
callback();
}
void FuchsiaWebDebugProxy::RegisterInstance(
fidl::InterfaceHandle<fuchsia::web::Debug> debug) {
DCHECK(has_clients());
// Create a new DevToolsListener binding, and connect it to the instance.
fidl::InterfaceHandle<fuchsia::web::DevToolsListener> handle;
instance_bindings_.AddBinding(this, handle.NewRequest());
debug.Bind()->EnableDevTools(std::move(handle), {});
}
void FuchsiaWebDebugProxy::OnContextDevToolsAvailable(
fidl::InterfaceRequest<fuchsia::web::DevToolsPerContextListener> request) {
// Create a proxy to propagate notifications for this new per-Context
// listener out to each of the clients.
new PerContextListenerProxy(std::move(request), devtools_listeners_);
}