/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include #include "CdpJson.h" #include "RuntimeTarget.h" namespace facebook::react::jsinspector_modern { InstanceAgent::InstanceAgent( FrontendChannel frontendChannel, InstanceTarget& target, SessionState& sessionState) : frontendChannel_(frontendChannel), target_(target), sessionState_(sessionState) { (void)target_; } bool InstanceAgent::handleRequest(const cdp::PreparsedRequest& req) { if (req.method == "Runtime.enable") { maybeSendExecutionContextCreatedNotification(); maybeSendPendingConsoleMessages(); // Fall through } if (runtimeAgent_ && runtimeAgent_->handleRequest(req)) { return true; } return false; } void InstanceAgent::setCurrentRuntime(RuntimeTarget* runtimeTarget) { auto previousRuntimeAgent = std::move(runtimeAgent_); if (runtimeTarget) { runtimeAgent_ = runtimeTarget->createAgent(frontendChannel_, sessionState_); } else { runtimeAgent_.reset(); } if (!sessionState_.isRuntimeDomainEnabled) { return; } if (previousRuntimeAgent != nullptr) { auto& previousContext = previousRuntimeAgent->getExecutionContextDescription(); folly::dynamic params = folly::dynamic::object("executionContextId", previousContext.id); if (previousContext.uniqueId.has_value()) { params["executionContextUniqueId"] = *previousContext.uniqueId; } frontendChannel_( cdp::jsonNotification("Runtime.executionContextDestroyed", params)); } maybeSendExecutionContextCreatedNotification(); maybeSendPendingConsoleMessages(); } void InstanceAgent::maybeSendExecutionContextCreatedNotification() { if (runtimeAgent_ != nullptr) { auto& newContext = runtimeAgent_->getExecutionContextDescription(); folly::dynamic params = folly::dynamic::object( "context", folly::dynamic::object("id", newContext.id)( "origin", newContext.origin)("name", newContext.name)); if (newContext.uniqueId.has_value()) { params["uniqueId"] = *newContext.uniqueId; } frontendChannel_( cdp::jsonNotification("Runtime.executionContextCreated", params)); } } void InstanceAgent::sendConsoleMessage(SimpleConsoleMessage message) { if (runtimeAgent_ && sessionState_.isRuntimeDomainEnabled) { sendConsoleMessageImmediately(std::move(message)); } else { sessionState_.pendingSimpleConsoleMessages.emplace_back(std::move(message)); } } static std::string consoleMessageTypeName(ConsoleAPIType type) { switch (type) { case ConsoleAPIType::kLog: return "log"; case ConsoleAPIType::kDebug: return "debug"; case ConsoleAPIType::kInfo: return "info"; case ConsoleAPIType::kError: return "error"; case ConsoleAPIType::kWarning: return "warning"; case ConsoleAPIType::kDir: return "dir"; case ConsoleAPIType::kDirXML: return "dirxml"; case ConsoleAPIType::kTable: return "table"; case ConsoleAPIType::kTrace: return "trace"; case ConsoleAPIType::kStartGroup: return "startGroup"; case ConsoleAPIType::kStartGroupCollapsed: return "startGroupCollapsed"; case ConsoleAPIType::kEndGroup: return "endGroup"; case ConsoleAPIType::kClear: return "clear"; case ConsoleAPIType::kAssert: return "assert"; case ConsoleAPIType::kTimeEnd: return "timeEnd"; case ConsoleAPIType::kCount: return "count"; default: assert(false && "unknown console API type"); return "error"; } } void InstanceAgent::sendConsoleMessageImmediately( SimpleConsoleMessage message) { assert(runtimeAgent_ != nullptr); folly::dynamic argsParam = folly::dynamic::array(); for (auto& arg : message.args) { argsParam.push_back(folly::dynamic::object("type", "string")("value", arg)); } frontendChannel_(cdp::jsonNotification( "Runtime.consoleAPICalled", folly::dynamic::object("type", consoleMessageTypeName(message.type))( "timestamp", message.timestamp)("args", std::move(argsParam))( "executionContextId", runtimeAgent_->getExecutionContextDescription().id)( // We use the @cdp Runtime.consoleAPICalled `context` parameter to // mark synthetic messages generated by the backend, i.e. not // originating in a real `console.*` API call. "context", runtimeAgent_->getExecutionContextDescription().name + "#InstanceAgent"))); } void InstanceAgent::maybeSendPendingConsoleMessages() { if (runtimeAgent_ != nullptr) { auto messages = std::move(sessionState_.pendingSimpleConsoleMessages); sessionState_.pendingSimpleConsoleMessages.clear(); for (auto& message : messages) { sendConsoleMessageImmediately(std::move(message)); } } } } // namespace facebook::react::jsinspector_modern