/* * Copyright (c) 2025, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include namespace DevTools { // https://firefox-source-docs.mozilla.org/devtools/backend/protocol.html#the-root-actor NonnullRefPtr RootActor::create(DevToolsServer& devtools, String name) { auto actor = adopt_ref(*new RootActor(devtools, move(name))); JsonObject traits; traits.set("sources"sv, false); traits.set("highlightable"sv, true); traits.set("customHighlighters"sv, true); traits.set("networkMonitor"sv, false); JsonObject message; message.set("applicationType"sv, "browser"sv); message.set("traits"sv, move(traits)); actor->send_message(move(message)); return actor; } RootActor::RootActor(DevToolsServer& devtools, String name) : Actor(devtools, move(name)) { } RootActor::~RootActor() = default; void RootActor::handle_message(Message const& message) { JsonObject response; if (message.type == "connect") { send_response(message, move(response)); return; } if (message.type == "getRoot"sv) { response.set("selected"sv, 0); for (auto const& actor : devtools().actor_registry()) { if (is(*actor.value)) response.set("deviceActor"sv, actor.key); else if (is(*actor.value)) response.set("preferenceActor"sv, actor.key); } send_response(message, move(response)); return; } if (message.type == "getProcess"sv) { auto id = get_required_parameter(message, "id"sv); if (!id.has_value()) return; for (auto const& actor : devtools().actor_registry()) { auto const* process_actor = as_if(*actor.value); if (!process_actor) continue; if (process_actor->description().id != *id) continue; response.set("processDescriptor"sv, process_actor->serialize_description()); break; } send_response(message, move(response)); return; } if (message.type == "getTab"sv) { auto browser_id = get_required_parameter(message, "browserId"sv); if (!browser_id.has_value()) return; for (auto const& actor : devtools().actor_registry()) { auto const* tab_actor = as_if(*actor.value); if (!tab_actor) continue; if (tab_actor->description().id != *browser_id) continue; response.set("tab"sv, tab_actor->serialize_description()); break; } send_response(message, move(response)); return; } if (message.type == "listAddons"sv) { response.set("addons"sv, JsonArray {}); send_response(message, move(response)); return; } if (message.type == "listProcesses"sv) { JsonArray processes; for (auto const& actor : devtools().actor_registry()) { if (auto const* process_actor = as_if(*actor.value)) processes.must_append(process_actor->serialize_description()); } response.set("processes"sv, move(processes)); send_response(message, move(response)); return; } if (message.type == "listServiceWorkerRegistrations"sv) { response.set("registrations"sv, JsonArray {}); send_response(message, move(response)); return; } if (message.type == "listTabs"sv) { m_has_sent_tab_list_changed_since_last_list_tabs_request = false; JsonArray tabs; for (auto& tab_description : devtools().delegate().tab_list()) { auto& actor = devtools().register_actor(move(tab_description)); tabs.must_append(actor.serialize_description()); } response.set("tabs"sv, move(tabs)); send_response(message, move(response)); return; } if (message.type == "listWorkers"sv) { response.set("workers"sv, JsonArray {}); send_response(message, move(response)); return; } send_unrecognized_packet_type_error(message); } void RootActor::send_tab_list_changed_message() { if (m_has_sent_tab_list_changed_since_last_list_tabs_request) return; JsonObject message; message.set("type"sv, "tabListChanged"sv); send_message(move(message)); m_has_sent_tab_list_changed_since_last_list_tabs_request = true; } }