mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
C++ InspectorPackagerConnection (#41977)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/41977 Changelog: [Internal] Adds a new C++ implementation of `InspectorPackagerConnection`, intended to eventually replace `RCTInspectorPackagerConnection` on iOS and `InspectorPackagerConnection.java` on Android. The main *new* abstraction in the C++ version is the `InspectorPackagerConnectionDelegate` interface, which will allow each platform to plug in its own scheduler and WebSocket implementation This is almost entirely a direct translation of the Objective-C implementation to C++, so I've modelled it as a file copy in source control for ease of review. We may iterate further on the API at a later date, especially once the old implementations are gone. Reviewed By: huntie Differential Revision: D52134592 fbshipit-source-id: b4778b9c4fd424c4fa8d23bb9171629874e50e73
This commit is contained in:
committed by
Facebook GitHub Bot
parent
cfa02eec50
commit
db0d178b8f
@@ -16,5 +16,6 @@ add_library(jsinspector STATIC ${jsinspector_SRC})
|
||||
target_include_directories(jsinspector PUBLIC ${REACT_COMMON_DIR})
|
||||
|
||||
target_link_libraries(jsinspector
|
||||
folly_runtime
|
||||
glog
|
||||
)
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* 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 "InspectorPackagerConnection.h"
|
||||
#include "InspectorInterfaces.h"
|
||||
#include "InspectorPackagerConnectionImpl.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <folly/json.h>
|
||||
#include <glog/logging.h>
|
||||
#include <cerrno>
|
||||
#include <chrono>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
static constexpr const std::chrono::duration RECONNECT_DELAY =
|
||||
std::chrono::milliseconds{2000};
|
||||
static constexpr const char* INVALID = "<invalid>";
|
||||
|
||||
static folly::dynamic makePageIdPayload(std::string_view pageId) {
|
||||
return folly::dynamic::object("id", pageId);
|
||||
}
|
||||
|
||||
/*
|
||||
TODO(moti): Remove this comment, which is only here to help the diff tool
|
||||
understand the relationship between this file and
|
||||
RCTInspectorPackagerConnection.m.
|
||||
|
||||
@implementation RCTInspectorPackagerConnection
|
||||
|
||||
*/
|
||||
|
||||
// InspectorPackagerConnection::Impl method definitions
|
||||
|
||||
std::shared_ptr<InspectorPackagerConnection::Impl>
|
||||
InspectorPackagerConnection::Impl::create(
|
||||
std::string url,
|
||||
std::string app,
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate) {
|
||||
// No make_shared because the constructor is private
|
||||
return std::shared_ptr<InspectorPackagerConnection::Impl>(
|
||||
new InspectorPackagerConnection::Impl(url, app, std::move(delegate)));
|
||||
}
|
||||
|
||||
InspectorPackagerConnection::Impl::Impl(
|
||||
std::string url,
|
||||
std::string app,
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate)
|
||||
: url_(std::move(url)),
|
||||
app_(std::move(app)),
|
||||
delegate_(std::move(delegate)) {}
|
||||
|
||||
void InspectorPackagerConnection::Impl::handleProxyMessage(
|
||||
folly::const_dynamic_view message) {
|
||||
std::string event = message.descend("event").string_or(INVALID);
|
||||
if (event == "getPages") {
|
||||
sendEvent("getPages", pages());
|
||||
} else if (event == "wrappedEvent") {
|
||||
handleWrappedEvent(message.descend("payload"));
|
||||
} else if (event == "connect") {
|
||||
handleConnect(message.descend("payload"));
|
||||
} else if (event == "disconnect") {
|
||||
handleDisconnect(message.descend("payload"));
|
||||
} else {
|
||||
LOG(ERROR) << "Unknown event: " << event;
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::sendEventToAllConnections(
|
||||
std::string event) {
|
||||
for (auto& connection : inspectorConnections_) {
|
||||
connection.second->sendMessage(event);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::closeAllConnections() {
|
||||
for (auto& connection : inspectorConnections_) {
|
||||
connection.second->disconnect();
|
||||
}
|
||||
inspectorConnections_.clear();
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::handleConnect(
|
||||
folly::const_dynamic_view payload) {
|
||||
std::string pageId = payload.descend("pageId").string_or(INVALID);
|
||||
auto existingConnectionIt = inspectorConnections_.find(pageId);
|
||||
if (existingConnectionIt != inspectorConnections_.end()) {
|
||||
auto existingConnection = std::move(existingConnectionIt->second);
|
||||
inspectorConnections_.erase(existingConnectionIt);
|
||||
existingConnection->disconnect();
|
||||
LOG(WARNING) << "Already connected: " << pageId;
|
||||
return;
|
||||
}
|
||||
int pageIdInt;
|
||||
try {
|
||||
pageIdInt = std::stoi(pageId);
|
||||
} catch (...) {
|
||||
LOG(ERROR) << "Invalid page id: " << pageId;
|
||||
return;
|
||||
}
|
||||
auto remoteConnection =
|
||||
std::make_unique<InspectorPackagerConnection::RemoteConnectionImpl>(
|
||||
weak_from_this(), pageId);
|
||||
auto& inspector = getInspectorInstance();
|
||||
auto inspectorConnection =
|
||||
inspector.connect(pageIdInt, std::move(remoteConnection));
|
||||
inspectorConnections_.emplace(pageId, std::move(inspectorConnection));
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::handleDisconnect(
|
||||
folly::const_dynamic_view payload) {
|
||||
std::string pageId = payload.descend("pageId").string_or(INVALID);
|
||||
auto inspectorConnection = removeConnectionForPage(pageId);
|
||||
if (inspectorConnection) {
|
||||
inspectorConnection->disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ILocalConnection>
|
||||
InspectorPackagerConnection::Impl::removeConnectionForPage(std::string pageId) {
|
||||
auto it = inspectorConnections_.find(pageId);
|
||||
if (it != inspectorConnections_.end()) {
|
||||
auto connection = std::move(it->second);
|
||||
inspectorConnections_.erase(it);
|
||||
return connection;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::handleWrappedEvent(
|
||||
folly::const_dynamic_view payload) {
|
||||
std::string pageId = payload.descend("pageId").string_or(INVALID);
|
||||
std::string wrappedEvent = payload.descend("wrappedEvent").string_or(INVALID);
|
||||
auto connectionIt = inspectorConnections_.find(pageId);
|
||||
if (connectionIt == inspectorConnections_.end()) {
|
||||
LOG(WARNING) << "Not connected to page: " << pageId
|
||||
<< " , failed trying to handle event: " << wrappedEvent;
|
||||
return;
|
||||
}
|
||||
connectionIt->second->sendMessage(wrappedEvent);
|
||||
}
|
||||
|
||||
folly::dynamic InspectorPackagerConnection::Impl::pages() {
|
||||
auto& inspector = getInspectorInstance();
|
||||
auto pages = inspector.getPages();
|
||||
folly::dynamic array = folly::dynamic::array();
|
||||
|
||||
for (const auto& page : pages) {
|
||||
array.push_back(folly::dynamic::object("id", std::to_string(page.id))(
|
||||
"title", page.title)("app", app_)("vm", page.vm));
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::sendWrappedEvent(
|
||||
std::string pageId,
|
||||
std::string message) {
|
||||
sendEvent(
|
||||
"wrappedEvent",
|
||||
folly::dynamic::object("pageId", pageId)("wrappedEvent", message));
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::sendEvent(
|
||||
std::string event,
|
||||
folly::dynamic payload) {
|
||||
folly::dynamic message =
|
||||
folly::dynamic::object("event", event)("payload", payload);
|
||||
sendToPackager(message);
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::didFailWithError(
|
||||
std::optional<int> posixCode,
|
||||
std::string error) {
|
||||
if (webSocket_) {
|
||||
abort(posixCode, "WebSocket exception", error);
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::didReceiveMessage(
|
||||
std::string_view message) {
|
||||
folly::dynamic parsedJSON;
|
||||
try {
|
||||
parsedJSON = folly::parseJson(message);
|
||||
} catch (const folly::json::parse_error& e) {
|
||||
LOG(ERROR) << "Unrecognized inspector message, string was not valid JSON: "
|
||||
<< e.what();
|
||||
return;
|
||||
}
|
||||
handleProxyMessage(std::move(parsedJSON));
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::didClose() {
|
||||
webSocket_.reset();
|
||||
closeAllConnections();
|
||||
if (!closed_) {
|
||||
reconnect();
|
||||
}
|
||||
}
|
||||
|
||||
bool InspectorPackagerConnection::Impl::isConnected() const {
|
||||
return webSocket_ != nullptr;
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::connect() {
|
||||
if (closed_) {
|
||||
LOG(ERROR)
|
||||
<< "Illegal state: Can't connect after having previously been closed.";
|
||||
return;
|
||||
}
|
||||
webSocket_ = delegate_->connectWebSocket(url_, weak_from_this());
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::reconnect() {
|
||||
if (closed_) {
|
||||
LOG(ERROR)
|
||||
<< "Illegal state: Can't reconnect after having previously been closed.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!suppressConnectionErrors_) {
|
||||
LOG(WARNING) << "Couldn't connect to packager, will silently retry";
|
||||
suppressConnectionErrors_ = true;
|
||||
}
|
||||
|
||||
delegate_->scheduleCallback(
|
||||
[weakSelf = weak_from_this()] {
|
||||
auto strongSelf = weakSelf.lock();
|
||||
if (strongSelf && !strongSelf->closed_) {
|
||||
strongSelf->connect();
|
||||
}
|
||||
},
|
||||
RECONNECT_DELAY);
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::closeQuietly() {
|
||||
closed_ = true;
|
||||
disposeWebSocket();
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::sendToPackager(folly::dynamic message) {
|
||||
if (!webSocket_) {
|
||||
return;
|
||||
}
|
||||
|
||||
webSocket_->send(folly::toJson(message));
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::abort(
|
||||
std::optional<int> posixCode,
|
||||
const std::string& message,
|
||||
const std::string& cause) {
|
||||
// Don't log ECONNREFUSED at all; it's expected in cases where the server
|
||||
// isn't listening.
|
||||
if (posixCode != ECONNREFUSED) {
|
||||
LOG(INFO) << "Error occurred, shutting down websocket connection: "
|
||||
<< message << " " << cause;
|
||||
}
|
||||
closeAllConnections();
|
||||
disposeWebSocket();
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::Impl::disposeWebSocket() {
|
||||
webSocket_.reset();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@end
|
||||
|
||||
TODO(moti): Remove this comment, which is only here to help the diff tool
|
||||
understand the relationship between this file and
|
||||
RCTInspectorPackagerConnection.m.
|
||||
|
||||
@implementation RCTInspectorRemoteConnection
|
||||
|
||||
*/
|
||||
|
||||
// InspectorPackagerConnection::RemoteConnectionImpl method definitions
|
||||
|
||||
InspectorPackagerConnection::RemoteConnectionImpl::RemoteConnectionImpl(
|
||||
std::weak_ptr<InspectorPackagerConnection::Impl> owningPackagerConnection,
|
||||
std::string pageId)
|
||||
: owningPackagerConnection_(owningPackagerConnection),
|
||||
pageId_(std::move(pageId)) {}
|
||||
|
||||
void InspectorPackagerConnection::RemoteConnectionImpl::onMessage(
|
||||
std::string message) {
|
||||
auto owningPackagerConnectionStrong = owningPackagerConnection_.lock();
|
||||
if (!owningPackagerConnectionStrong) {
|
||||
return;
|
||||
}
|
||||
owningPackagerConnectionStrong->sendWrappedEvent(pageId_, message);
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::RemoteConnectionImpl::onDisconnect() {
|
||||
auto owningPackagerConnectionStrong = owningPackagerConnection_.lock();
|
||||
if (owningPackagerConnectionStrong) {
|
||||
owningPackagerConnectionStrong->sendEvent(
|
||||
"disconnect", makePageIdPayload(pageId_));
|
||||
}
|
||||
}
|
||||
|
||||
// InspectorPackagerConnection method definitions
|
||||
|
||||
InspectorPackagerConnection::InspectorPackagerConnection(
|
||||
std::string url,
|
||||
std::string app,
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate)
|
||||
: impl_(Impl::create(url, app, std::move(delegate))) {}
|
||||
|
||||
bool InspectorPackagerConnection::isConnected() const {
|
||||
return impl_->isConnected();
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::connect() {
|
||||
impl_->connect();
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::closeQuietly() {
|
||||
impl_->closeQuietly();
|
||||
}
|
||||
|
||||
void InspectorPackagerConnection::sendEventToAllConnections(std::string event) {
|
||||
impl_->sendEventToAllConnections(event);
|
||||
}
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 "WebSocketInterfaces.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
class InspectorPackagerConnectionDelegate;
|
||||
|
||||
/**
|
||||
* A platform-agnostic implementation of the "device" side of the React Native
|
||||
* inspector-proxy protocol. The protocol multiplexes one or more debugger
|
||||
* connections over a single socket.
|
||||
* InspectorPackagerConnection will automatically attempt to reconnect after a
|
||||
* delay if the connection fails or is lost.
|
||||
*/
|
||||
class InspectorPackagerConnection {
|
||||
public:
|
||||
/**
|
||||
* Creates a new connection instance. Connections start in the disconnected
|
||||
* state; connect() should be called to establish a connection.
|
||||
* \param url The WebSocket URL where the inspector-proxy server is listening.
|
||||
* \param app The name of the application being debugged.
|
||||
* \param delegate An interface to platform-specific methods for creating a
|
||||
* WebSocket, scheduling async work, etc.
|
||||
*/
|
||||
InspectorPackagerConnection(
|
||||
std::string url,
|
||||
std::string app,
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate);
|
||||
bool isConnected() const;
|
||||
void connect();
|
||||
void closeQuietly();
|
||||
void sendEventToAllConnections(std::string event);
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
class RemoteConnectionImpl;
|
||||
|
||||
std::shared_ptr<Impl> impl_;
|
||||
};
|
||||
|
||||
/**
|
||||
* An interface implemented by each supported platform to provide
|
||||
* platform-specific functionality required by InspectorPackagerConnection.
|
||||
*/
|
||||
class InspectorPackagerConnectionDelegate {
|
||||
public:
|
||||
virtual ~InspectorPackagerConnectionDelegate() = default;
|
||||
|
||||
/**
|
||||
* Creates a new WebSocket connection. The WebSocket must be in a connected
|
||||
* state when created, and automatically disconnect when destroyed.
|
||||
*/
|
||||
virtual std::unique_ptr<IWebSocket> connectWebSocket(
|
||||
const std::string& url,
|
||||
std::weak_ptr<IWebSocketDelegate> delegate) = 0;
|
||||
|
||||
/**
|
||||
* Schedules a function to run after a delay. If the function is called
|
||||
* asynchronously, the implementer of InspectorPackagerConnectionDelegate
|
||||
* is responsible for thread safety (e.g. scheduling the callback on the same
|
||||
* thread that called scheduleCallback, or otherwise ensuring
|
||||
* synchronization). The callback MAY be dropped and never called, e.g. if the
|
||||
* application is terminating.
|
||||
*/
|
||||
virtual void scheduleCallback(
|
||||
std::function<void(void)> callback,
|
||||
std::chrono::milliseconds delayMs) = 0;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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 "InspectorInterfaces.h"
|
||||
#include "InspectorPackagerConnection.h"
|
||||
|
||||
#include <folly/dynamic.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* Internals of InspectorPackagerConnection.
|
||||
*/
|
||||
class InspectorPackagerConnection::Impl
|
||||
: public IWebSocketDelegate,
|
||||
// Used to generate `weak_ptr`s we can pass around.
|
||||
public std::enable_shared_from_this<InspectorPackagerConnection::Impl> {
|
||||
public:
|
||||
/**
|
||||
* Implements InspectorPackagerConnection's constructor.
|
||||
*/
|
||||
static std::shared_ptr<Impl> create(
|
||||
std::string url,
|
||||
std::string app,
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate);
|
||||
|
||||
// InspectorPackagerConnection's public API
|
||||
bool isConnected() const;
|
||||
void connect();
|
||||
void closeQuietly();
|
||||
void sendEventToAllConnections(std::string event);
|
||||
std::unique_ptr<ILocalConnection> removeConnectionForPage(std::string pageId);
|
||||
|
||||
// Exposed for RemoteConnectionImpl's use
|
||||
void sendEvent(std::string event, folly::dynamic payload);
|
||||
// Exposed for RemoteConnectionImpl's use
|
||||
void sendWrappedEvent(std::string pageId, std::string message);
|
||||
|
||||
private:
|
||||
Impl(
|
||||
std::string url,
|
||||
std::string app,
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate);
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
void handleDisconnect(folly::const_dynamic_view payload);
|
||||
void handleConnect(folly::const_dynamic_view payload);
|
||||
void handleWrappedEvent(folly::const_dynamic_view wrappedEvent);
|
||||
void handleProxyMessage(folly::const_dynamic_view message);
|
||||
folly::dynamic pages();
|
||||
void reconnect();
|
||||
void closeAllConnections();
|
||||
void disposeWebSocket();
|
||||
void sendToPackager(folly::dynamic message);
|
||||
|
||||
void abort(
|
||||
std::optional<int> posixCode,
|
||||
const std::string& message,
|
||||
const std::string& cause);
|
||||
|
||||
// IWebSocketDelegate methods
|
||||
virtual void didFailWithError(std::optional<int> posixCode, std::string error)
|
||||
override;
|
||||
virtual void didReceiveMessage(std::string_view message) override;
|
||||
virtual void didClose() override;
|
||||
|
||||
std::string url_;
|
||||
std::string app_;
|
||||
std::unique_ptr<InspectorPackagerConnectionDelegate> delegate_;
|
||||
|
||||
std::unordered_map<std::string, std::unique_ptr<ILocalConnection>>
|
||||
inspectorConnections_;
|
||||
std::unique_ptr<IWebSocket> webSocket_;
|
||||
bool closed_{false};
|
||||
bool suppressConnectionErrors_{false};
|
||||
};
|
||||
|
||||
class InspectorPackagerConnection::RemoteConnectionImpl
|
||||
: public IRemoteConnection {
|
||||
public:
|
||||
RemoteConnectionImpl(
|
||||
std::weak_ptr<InspectorPackagerConnection::Impl> owningPackagerConnection,
|
||||
std::string pageId);
|
||||
|
||||
// IRemoteConnection methods
|
||||
void onMessage(std::string message) override;
|
||||
void onDisconnect() override;
|
||||
|
||||
private:
|
||||
std::weak_ptr<InspectorPackagerConnection::Impl> owningPackagerConnection_;
|
||||
std::string pageId_;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
@@ -16,6 +16,9 @@ else
|
||||
source[:tag] = "v#{version}"
|
||||
end
|
||||
|
||||
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -DFOLLY_CFG_NO_COROUTINES=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -DFOLLY_HAVE_CLOCK_GETTIME=1 -Wno-comma -Wno-shorten-64-to-32'
|
||||
folly_version = '2023.08.07.00'
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "React-jsinspector"
|
||||
s.version = version
|
||||
@@ -27,9 +30,12 @@ Pod::Spec.new do |s|
|
||||
s.source = source
|
||||
s.source_files = "*.{cpp,h}"
|
||||
s.header_dir = 'jsinspector'
|
||||
s.pod_target_xcconfig = { "CLANG_CXX_LANGUAGE_STANDARD" => "c++20" }
|
||||
|
||||
s.compiler_flags = folly_compiler_flags
|
||||
s.pod_target_xcconfig = {
|
||||
"HEADER_SEARCH_PATHS" => "\"$(PODS_TARGET_SRCROOT)/..\" \"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/DoubleConversion\" \"$(PODS_ROOT)/fmt/include\"",
|
||||
"CLANG_CXX_LANGUAGE_STANDARD" => "c++20"
|
||||
}
|
||||
s.dependency "glog"
|
||||
|
||||
add_dependency(s, "React-nativeconfig")
|
||||
s.dependency "RCT-Folly", folly_version
|
||||
s.dependency "React-nativeconfig"
|
||||
end
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace facebook::react::jsinspector_modern {
|
||||
|
||||
/**
|
||||
* Simplified interface to a WebSocket connection.
|
||||
* The socket MUST be initially open when constructed.
|
||||
*/
|
||||
class IWebSocket {
|
||||
public:
|
||||
/**
|
||||
* If still connected when destroyed, the socket MUST automatically send an
|
||||
* "end of session" message and disconnect.
|
||||
*/
|
||||
virtual ~IWebSocket() = default;
|
||||
|
||||
/**
|
||||
* Sends a message over the socket. This function may be called on any thread
|
||||
* without synchronization.
|
||||
* \param message Message to send, in UTF-8 encoding.
|
||||
*/
|
||||
virtual void send(std::string_view message) = 0;
|
||||
};
|
||||
|
||||
class IWebSocketDelegate {
|
||||
public:
|
||||
virtual ~IWebSocketDelegate() = default;
|
||||
|
||||
/**
|
||||
* Called when the socket has encountered an error.
|
||||
* \param posixCode POSIX errno value if available, otherwise nullopt.
|
||||
* \param error Error description.
|
||||
*/
|
||||
virtual void didFailWithError(
|
||||
std::optional<int> posixCode,
|
||||
std::string error) = 0;
|
||||
|
||||
/**
|
||||
* Called when a message has been received from the socket.
|
||||
* \param message Message received, in UTF-8 encoding.
|
||||
*/
|
||||
virtual void didReceiveMessage(std::string_view message) = 0;
|
||||
|
||||
/**
|
||||
* Called when the socket has been closed.
|
||||
*/
|
||||
virtual void didClose() = 0;
|
||||
};
|
||||
|
||||
} // namespace facebook::react::jsinspector_modern
|
||||
Reference in New Issue
Block a user