mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-11-09 09:41:02 +00:00
This is to prepare for an upcoming change where we will need to track replies to messages by ID. We will be able to add parameters to this structure without having to edit every single actor subclass header file.
120 lines
3.2 KiB
C++
120 lines
3.2 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/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 = [this]() {
|
|
if (auto result = on_new_client(); result.is_error())
|
|
warnln("Failed to accept DevTools client: {}", result.error());
|
|
};
|
|
}
|
|
|
|
DevToolsServer::~DevToolsServer() = default;
|
|
|
|
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();
|
|
}
|
|
|
|
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 message) {
|
|
on_message_received(move(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 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");
|
|
|
|
Core::deferred_invoke([this]() {
|
|
m_connection = nullptr;
|
|
m_actor_registry.clear();
|
|
m_root_actor = nullptr;
|
|
});
|
|
}
|
|
|
|
}
|