/* * 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. */ #ifdef HERMES_ENABLE_DEBUGGER #include "HermesRuntimeAgentDelegate.h" #include #include #include #include using namespace facebook::hermes; namespace facebook::react::jsinspector_modern { class HermesRuntimeAgentDelegate::Impl final : public RuntimeAgentDelegate { using HermesState = hermes::cdp::State; struct HermesStateWrapper : public ExportedState { explicit HermesStateWrapper(HermesState state) : state_(std::move(state)) {} static HermesState unwrapDestructively(ExportedState* wrapper) { if (!wrapper) { return {}; } if (auto* typedWrapper = dynamic_cast(wrapper)) { return std::move(typedWrapper->state_); } return {}; } private: HermesState state_; }; public: Impl( FrontendChannel frontendChannel, SessionState& sessionState, std::unique_ptr previouslyExportedState, const ExecutionContextDescription& executionContextDescription, HermesRuntime& runtime, HermesRuntimeTargetDelegate& runtimeTargetDelegate, const RuntimeExecutor& runtimeExecutor) : hermes_(hermes::cdp::CDPAgent::create( executionContextDescription.id, runtimeTargetDelegate.getCDPDebugAPI(), // RuntimeTask takes a HermesRuntime whereas our RuntimeExecutor // takes a jsi::Runtime. [runtimeExecutor, &runtime](facebook::hermes::debugger::RuntimeTask fn) { runtimeExecutor( [&runtime, fn = std::move(fn)](auto&) { fn(runtime); }); }, frontendChannel, HermesStateWrapper::unwrapDestructively( previouslyExportedState.get()))) { if (sessionState.isRuntimeDomainEnabled) { hermes_->enableRuntimeDomain(); } if (sessionState.isDebuggerDomainEnabled) { hermes_->enableDebuggerDomain(); } } bool handleRequest(const cdp::PreparsedRequest& req) override { // TODO: Change to string::starts_with when we're on C++20. if (req.method.rfind("Log.", 0) == 0) { // Since we know Hermes doesn't do anything useful with Log messages, // but our containing HostAgent will, bail out early. // TODO: We need a way to negotiate this more dynamically with Hermes // through the API. return false; } // Forward everything else to Hermes's CDPAgent. hermes_->handleCommand(req.toJson()); // Let the call know that this request is handled (i.e. it is Hermes's // responsibility to respond with either success or an error). return true; } std::unique_ptr getExportedState() override { return std::make_unique(hermes_->getState()); } private: std::unique_ptr hermes_; }; HermesRuntimeAgentDelegate::HermesRuntimeAgentDelegate( FrontendChannel frontendChannel, SessionState& sessionState, std::unique_ptr previouslyExportedState, const ExecutionContextDescription& executionContextDescription, HermesRuntime& runtime, HermesRuntimeTargetDelegate& runtimeTargetDelegate, RuntimeExecutor runtimeExecutor) : impl_(std::make_unique( std::move(frontendChannel), sessionState, std::move(previouslyExportedState), executionContextDescription, runtime, runtimeTargetDelegate, std::move(runtimeExecutor))) {} bool HermesRuntimeAgentDelegate::handleRequest( const cdp::PreparsedRequest& req) { return impl_->handleRequest(req); } std::unique_ptr HermesRuntimeAgentDelegate::getExportedState() { return impl_->getExportedState(); } } // namespace facebook::react::jsinspector_modern #endif // HERMES_ENABLE_DEBUGGER