jiuyiUniapp/service/node_modules/react-native/ReactCommon/jsinspector-modern/HostTarget.h

277 lines
9.6 KiB
C
Raw Normal View History

2025-02-13 09:59:20 +08:00
/*
* 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.
*/
#pragma once
#include "ExecutionContextManager.h"
#include "HostCommand.h"
#include "InspectorInterfaces.h"
#include "InstanceTarget.h"
#include "NetworkIOAgent.h"
#include "ScopedExecutor.h"
#include "WeakList.h"
#include <optional>
#include <string>
#ifndef JSINSPECTOR_EXPORT
#ifdef _MSC_VER
#ifdef CREATE_SHARED_LIBRARY
#define JSINSPECTOR_EXPORT __declspec(dllexport)
#else
#define JSINSPECTOR_EXPORT
#endif // CREATE_SHARED_LIBRARY
#else // _MSC_VER
#define JSINSPECTOR_EXPORT __attribute__((visibility("default")))
#endif // _MSC_VER
#endif // !defined(JSINSPECTOR_EXPORT)
namespace facebook::react::jsinspector_modern {
class HostTargetSession;
class HostAgent;
class HostCommandSender;
class HostTarget;
struct HostTargetMetadata {
std::optional<std::string> appDisplayName;
std::optional<std::string> appIdentifier;
std::optional<std::string> deviceName;
std::optional<std::string> integrationName;
std::optional<std::string> platform;
std::optional<std::string> reactNativeVersion;
};
/**
* Receives events from a HostTarget. This is a shared interface that each
* React Native platform needs to implement in order to integrate with the
* debugging stack.
*/
class HostTargetDelegate : public LoadNetworkResourceDelegate {
public:
HostTargetDelegate() = default;
HostTargetDelegate(const HostTargetDelegate&) = delete;
HostTargetDelegate(HostTargetDelegate&&) = delete;
HostTargetDelegate& operator=(const HostTargetDelegate&) = delete;
HostTargetDelegate& operator=(HostTargetDelegate&&) = delete;
// TODO(moti): This is 1:1 the shape of the corresponding CDP message -
// consider reusing typed/generated CDP interfaces when we have those.
struct PageReloadRequest {
// It isn't clear what the ignoreCache parameter of @cdp Page.reload should
// mean in React Native. We parse it, but don't do anything with it yet.
std::optional<bool> ignoreCache;
// TODO: Implement scriptToEvaluateOnLoad parameter of @cdp Page.reload.
std::optional<std::string> scriptToEvaluateOnLoad;
/**
* Equality operator, useful for unit tests
*/
inline bool operator==(const PageReloadRequest& rhs) const {
return ignoreCache == rhs.ignoreCache &&
scriptToEvaluateOnLoad == rhs.scriptToEvaluateOnLoad;
}
};
struct OverlaySetPausedInDebuggerMessageRequest {
/**
* The message to display in the overlay. If nullopt, hide the overlay.
*/
std::optional<std::string> message;
/**
* Equality operator, useful for unit tests
*/
inline bool operator==(
const OverlaySetPausedInDebuggerMessageRequest& rhs) const {
return message == rhs.message;
}
};
virtual ~HostTargetDelegate() override;
/**
* Returns a metadata object describing the host. This is called on an
* initial response to @cdp ReactNativeApplication.enable.
*/
virtual HostTargetMetadata getMetadata() = 0;
/**
* Called when the debugger requests a reload of the page. This is called on
* the thread on which messages are dispatched to the session (that is, where
* ILocalConnection::sendMessage was called).
*/
virtual void onReload(const PageReloadRequest& request) = 0;
/**
* Called when the debugger requests that the "paused in debugger" overlay be
* shown or hidden. If the message is nullopt, hide the overlay, otherwise
* show it with the given message. This is called on the inspector thread.
*
* If this method is called with a non-null message, it's guaranteed to
* eventually be called again with a null message. In all other respects,
* the timing and payload of these messages are fully controlled by the
* client.
*/
virtual void onSetPausedInDebuggerMessage(
const OverlaySetPausedInDebuggerMessageRequest& request) = 0;
/**
* Called by NetworkIOAgent on handling a `Network.loadNetworkResource` CDP
* request. Platform implementations should override this to perform a
* network request of the given URL, and use listener's callbacks on receipt
* of headers, data chunks, and errors.
*/
void loadNetworkResource(
const LoadNetworkResourceRequest& /*params*/,
ScopedExecutor<NetworkRequestListener> /*executor*/) override {
throw NotImplementedException(
"LoadNetworkResourceDelegate.loadNetworkResource is not implemented by this host target delegate.");
}
};
/**
* The limited interface that HostTarget exposes to its associated
* sessions/agents.
*/
class HostTargetController final {
public:
explicit HostTargetController(HostTarget& target);
HostTargetDelegate& getDelegate();
bool hasInstance() const;
/**
* Increments the target's pause overlay counter. The counter represents the
* exact number of Agents that have (concurrently) requested the pause
* overlay to be shown. It's the caller's responsibility to only call this
* when the pause overlay's requested state transitions from hidden to
* visible.
*/
void incrementPauseOverlayCounter();
/**
* Decrements the target's pause overlay counter. The counter represents the
* exact number of Agents that have (concurrently) requested the pause
* overlay to be shown. It's the caller's responsibility to only call this
* when the pause overlay's requested state transitions from hidden to
* visible.
* \returns false if the counter has reached 0, otherwise true.
*/
bool decrementPauseOverlayCounter();
private:
HostTarget& target_;
size_t pauseOverlayCounter_{0};
};
/**
* The top-level Target in a React Native app. This is equivalent to the
* "Host" in React Native's architecture - the entity that manages the
* lifecycle of a React Instance.
*/
class JSINSPECTOR_EXPORT HostTarget
: public EnableExecutorFromThis<HostTarget> {
public:
/**
* Constructs a new HostTarget.
* \param delegate The HostTargetDelegate that will
* receive events from this HostTarget. The caller is responsible for ensuring
* that the HostTargetDelegate outlives this object.
* \param executor An executor that may be used to call methods on this
* HostTarget while it exists. \c create additionally guarantees that the
* executor will not be called after the HostTarget is destroyed.
* \note Copies of the provided executor may be destroyed on arbitrary
* threads, including after the HostTarget is destroyed. Callers must ensure
* that such destructor calls are safe - e.g. if using a lambda as the
* executor, all captured values must be safe to destroy from any thread.
*/
static std::shared_ptr<HostTarget> create(
HostTargetDelegate& delegate,
VoidExecutor executor);
HostTarget(const HostTarget&) = delete;
HostTarget(HostTarget&&) = delete;
HostTarget& operator=(const HostTarget&) = delete;
HostTarget& operator=(HostTarget&&) = delete;
~HostTarget();
/**
* Creates a new Session connected to this HostTarget, wrapped in an
* interface which is compatible with \c IInspector::addPage.
* The caller is responsible for destroying the connection before HostTarget
* is destroyed, on the same thread where HostTarget's constructor and
* destructor execute.
*/
std::unique_ptr<ILocalConnection> connect(
std::unique_ptr<IRemoteConnection> connectionToFrontend);
/**
* Registers an instance with this HostTarget.
* \param delegate The InstanceTargetDelegate that will receive events from
* this InstanceTarget. The caller is responsible for ensuring that the
* InstanceTargetDelegate outlives this object.
* \return An InstanceTarget reference representing the newly created
* instance. This reference is only valid until unregisterInstance is called
* (or the HostTarget is destroyed). \pre There isn't currently an instance
* registered with this HostTarget.
*/
InstanceTarget& registerInstance(InstanceTargetDelegate& delegate);
/**
* Unregisters an instance from this HostTarget.
* \param instance The InstanceTarget reference previously returned by
* registerInstance.
*/
void unregisterInstance(InstanceTarget& instance);
/**
* Sends an imperative command to the HostTarget. May be called from any
* thread.
*/
void sendCommand(HostCommand command);
private:
/**
* Constructs a new HostTarget.
* The caller must call setExecutor immediately afterwards.
* \param delegate The HostTargetDelegate that will
* receive events from this HostTarget. The caller is responsible for ensuring
* that the HostTargetDelegate outlives this object.
*/
HostTarget(HostTargetDelegate& delegate);
HostTargetDelegate& delegate_;
WeakList<HostTargetSession> sessions_;
HostTargetController controller_{*this};
// executionContextManager_ is a shared_ptr to guarantee its validity while
// the InstanceTarget is alive (just in case the InstanceTarget ends up
// briefly outliving the HostTarget, which it generally shouldn't).
std::shared_ptr<ExecutionContextManager> executionContextManager_;
std::shared_ptr<InstanceTarget> currentInstance_{nullptr};
std::unique_ptr<HostCommandSender> commandSender_;
inline HostTargetDelegate& getDelegate() {
return delegate_;
}
inline bool hasInstance() const {
return currentInstance_ != nullptr;
}
// Necessary to allow HostAgent to access HostTarget's internals in a
// controlled way (i.e. only HostTargetController gets friend access, while
// HostAgent itself doesn't).
friend class HostTargetController;
};
folly::dynamic hostMetadataToDynamic(const HostTargetMetadata& metadata);
} // namespace facebook::react::jsinspector_modern