Files
ladybird/Libraries/LibDevTools/Actor.cpp
Timothy Flynn 24a5e4e7d5 LibDevTools: Move message data into a structure
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.
2025-03-13 16:56:28 -04:00

115 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibDevTools/Actor.h>
#include <LibDevTools/Connection.h>
#include <LibDevTools/DevToolsServer.h>
namespace DevTools {
Actor::Actor(DevToolsServer& devtools, String name)
: m_devtools(devtools)
, m_name(move(name))
{
}
Actor::~Actor() = default;
void Actor::message_received(StringView type, JsonObject message)
{
handle_message({ type, move(message) });
}
void Actor::send_message(JsonObject message, Optional<BlockToken> block_token)
{
if (m_block_responses && !block_token.has_value()) {
m_blocked_responses.append(move(message));
return;
}
message.set("from"sv, name());
if (auto& connection = devtools().connection())
connection->send_message(move(message));
}
// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets
void Actor::send_missing_parameter_error(StringView parameter)
{
JsonObject error;
error.set("error"sv, "missingParameter"sv);
error.set("message"sv, MUST(String::formatted("Missing parameter: '{}'", parameter)));
send_message(move(error));
}
// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#error-packets
void Actor::send_unrecognized_packet_type_error(Message const& message)
{
JsonObject error;
error.set("error"sv, "unrecognizedPacketType"sv);
error.set("message"sv, MUST(String::formatted("Unrecognized packet type: '{}'", message.type)));
send_message(move(error));
}
// https://github.com/mozilla/gecko-dev/blob/master/devtools/server/actors/object.js
// This error is not documented, but is used by Firefox nonetheless.
void Actor::send_unknown_actor_error(StringView actor)
{
JsonObject error;
error.set("error"sv, "unknownActor"sv);
error.set("message"sv, MUST(String::formatted("Unknown actor: '{}'", actor)));
send_message(move(error));
}
Actor::BlockToken Actor::block_responses()
{
// https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#the-request-reply-pattern
// The actor processes packets in the order they are received, and the client can trust that the ith reply
// corresponds to the ith request.
// The above requirement gets tricky for actors which require an async implementation. For example, the "getWalker"
// message sent to the InspectorActor results in the server fetching the DOM tree as JSON from the WebContent process.
// We cannot reply to the message until that is received. However, we will likely receive more messages from the
// client in that time. We cannot reply to those messages until we've replied to the "getWalker" message. Thus, we
// use this token to queue responses from the actor until that reply can be sent.
return { {}, *this };
}
Actor::BlockToken::BlockToken(Badge<Actor>, Actor& actor)
: m_actor(actor)
{
// If we end up in a situtation where an actor has multiple async handlers at once, we will need to come up with a
// more sophisticated blocking mechanism.
VERIFY(!actor.m_block_responses);
actor.m_block_responses = true;
}
Actor::BlockToken::BlockToken(BlockToken&& other)
: m_actor(move(other.m_actor))
{
}
Actor::BlockToken& Actor::BlockToken::operator=(BlockToken&& other)
{
m_actor = move(other.m_actor);
return *this;
}
Actor::BlockToken::~BlockToken()
{
auto actor = m_actor.strong_ref();
if (!actor)
return;
auto blocked_responses = move(actor->m_blocked_responses);
actor->m_block_responses = false;
for (auto& message : blocked_responses)
actor->send_message(move(message));
}
}