ladybird/Libraries/LibDevTools/DevToolsServer.cpp

159 lines
4.3 KiB
C++
Raw Normal View History

/*
* 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/ParentAccessibilityActor.h>
#include <LibDevTools/Actors/PreferenceActor.h>
#include <LibDevTools/Actors/ProcessActor.h>
#include <LibDevTools/Actors/TabActor.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 = [weak_self = make_weak_ptr<DevToolsServer>()] {
if (!weak_self)
return;
if (auto result = weak_self->on_new_client(); result.is_error())
warnln("Failed to accept DevTools client: {}", result.error());
};
}
DevToolsServer::~DevToolsServer()
{
m_is_shutting_down = true;
m_server->on_ready_to_accept = {};
if (m_connection) {
m_connection->on_connection_closed = {};
m_connection->on_message_received = {};
}
}
2026-05-22 11:05:51 -03:00
Optional<u16> DevToolsServer::local_port() const
{
return m_server->local_port();
}
void DevToolsServer::refresh_tab_list()
{
if (!m_root_actor)
return;
m_actor_registry.remove_all_matching([](auto const&, auto const& actor) {
return is<TabActor>(*actor);
});
m_root_actor->send_tab_list_changed_message();
}
void DevToolsServer::unregister_actor(String const& name)
{
if (m_is_shutting_down)
return;
Core::deferred_invoke([weak_self = make_weak_ptr<DevToolsServer>(), name] {
if (weak_self)
weak_self->m_actor_registry.remove(name);
});
}
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 = [weak_self = make_weak_ptr<DevToolsServer>()] {
if (weak_self)
weak_self->close_connection();
};
m_connection->on_message_received = [weak_self = make_weak_ptr<DevToolsServer>()](auto message) {
if (weak_self)
weak_self->on_message_received(move(message));
};
m_root_actor = register_actor<RootActor>();
register_actor<DeviceActor>();
register_actor<PreferenceActor>();
register_actor<ProcessActor>(ProcessDescription { .is_parent = true });
register_actor<ParentAccessibilityActor>();
return {};
}
void DevToolsServer::on_message_received(JsonObject message)
{
auto to = message.get_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_string("type"sv);
if (!type.has_value()) {
actor->value->send_missing_parameter_error({}, "type"sv);
return;
}
actor->value->message_received(*type, move(message));
}
void DevToolsServer::close_connection()
{
dbgln_if(DEVTOOLS_DEBUG, "Lost connection to the DevTools client");
if (m_is_shutting_down)
return;
Core::deferred_invoke([weak_self = make_weak_ptr<DevToolsServer>()] {
if (!weak_self)
return;
weak_self->m_connection = nullptr;
weak_self->m_actor_registry.clear();
weak_self->m_root_actor = nullptr;
});
}
}