mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-26 06:18:59 +00:00
To aid with debugging web page issues in Ladybird without needing to implement a fully fledged inspector, we can implement the Firefox DevTools protocol and use their DevTools. The protocol is described here: https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html This commit contains just enough to connect to Ladybird from a DevTools client.
107 lines
2.9 KiB
C++
107 lines
2.9 KiB
C++
/*
|
|
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Debug.h>
|
|
#include <AK/JsonObject.h>
|
|
#include <AK/JsonValue.h>
|
|
#include <LibCore/EventLoop.h>
|
|
#include <LibCore/Socket.h>
|
|
#include <LibCore/TCPServer.h>
|
|
#include <LibDevTools/Actors/DeviceActor.h>
|
|
#include <LibDevTools/Actors/PreferenceActor.h>
|
|
#include <LibDevTools/Actors/ProcessActor.h>
|
|
#include <LibDevTools/Connection.h>
|
|
#include <LibDevTools/DevToolsServer.h>
|
|
|
|
namespace DevTools {
|
|
|
|
static u64 s_server_count = 0;
|
|
|
|
ErrorOr<NonnullOwnPtr<DevToolsServer>> DevToolsServer::create(DevToolsDelegate& delegate, u16 port)
|
|
{
|
|
auto address = IPv4Address::from_string("0.0.0.0"sv).release_value();
|
|
|
|
auto server = TRY(Core::TCPServer::try_create());
|
|
TRY(server->listen(address, port, Core::TCPServer::AllowAddressReuse::Yes));
|
|
|
|
return adopt_own(*new DevToolsServer(delegate, move(server)));
|
|
}
|
|
|
|
DevToolsServer::DevToolsServer(DevToolsDelegate& delegate, NonnullRefPtr<Core::TCPServer> server)
|
|
: m_server(move(server))
|
|
, m_delegate(delegate)
|
|
, m_server_id(s_server_count++)
|
|
{
|
|
m_server->on_ready_to_accept = [this]() {
|
|
if (auto result = on_new_client(); result.is_error())
|
|
warnln("Failed to accept DevTools client: {}", result.error());
|
|
};
|
|
}
|
|
|
|
DevToolsServer::~DevToolsServer() = default;
|
|
|
|
ErrorOr<void> DevToolsServer::on_new_client()
|
|
{
|
|
if (m_connection)
|
|
return Error::from_string_literal("Only one active DevTools connection is currently allowed");
|
|
|
|
auto client = TRY(m_server->accept());
|
|
auto buffered_socket = TRY(Core::BufferedTCPSocket::create(move(client)));
|
|
|
|
m_connection = Connection::create(move(buffered_socket));
|
|
|
|
m_connection->on_connection_closed = [this]() {
|
|
close_connection();
|
|
};
|
|
|
|
m_connection->on_message_received = [this](auto const& message) {
|
|
on_message_received(message);
|
|
};
|
|
|
|
m_root_actor = register_actor<RootActor>();
|
|
|
|
register_actor<DeviceActor>();
|
|
register_actor<PreferenceActor>();
|
|
register_actor<ProcessActor>(ProcessDescription { .is_parent = true });
|
|
|
|
return {};
|
|
}
|
|
|
|
void DevToolsServer::on_message_received(JsonObject const& message)
|
|
{
|
|
auto to = message.get_byte_string("to"sv);
|
|
if (!to.has_value()) {
|
|
m_root_actor->send_missing_parameter_error("to"sv);
|
|
return;
|
|
}
|
|
|
|
auto actor = m_actor_registry.find(*to);
|
|
if (actor == m_actor_registry.end()) {
|
|
m_root_actor->send_unknown_actor_error(*to);
|
|
return;
|
|
}
|
|
|
|
auto type = message.get_byte_string("type"sv);
|
|
if (!type.has_value()) {
|
|
actor->value->send_missing_parameter_error("type"sv);
|
|
return;
|
|
}
|
|
|
|
actor->value->handle_message(*type, message);
|
|
}
|
|
|
|
void DevToolsServer::close_connection()
|
|
{
|
|
dbgln_if(DEVTOOLS_DEBUG, "Lost connection to the DevTools client");
|
|
|
|
Core::deferred_invoke([this]() {
|
|
m_connection = nullptr;
|
|
m_actor_registry.clear();
|
|
m_root_actor = nullptr;
|
|
});
|
|
}
|
|
|
|
}
|