diff --git a/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.cpp b/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.cpp index 05676162f68f..21cd74ca1489 100644 --- a/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.cpp +++ b/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.cpp @@ -9,22 +9,40 @@ #include #include -#include namespace facebook::react { PackagerConnection::PackagerConnection( - const WebSocketClientFactory& webSocketClientFactory, - const std::string& packagerConnectionUrl, + WebSocketClientFactory webSocketClientFactory, + std::string packagerConnectionUrl, LiveReloadCallback&& liveReloadCallback, ShowDevMenuCallback&& showDevMenuCallback) - : liveReloadCallback_(std::move(liveReloadCallback)), + : webSocketClientFactory_(std::move(webSocketClientFactory)), + packagerConnectionUrl_(std::move(packagerConnectionUrl)), + liveReloadCallback_(std::move(liveReloadCallback)), showDevMenuCallback_(std::move(showDevMenuCallback)) { - websocket_ = webSocketClientFactory(); + attemptConnection(); +} + +PackagerConnection::~PackagerConnection() noexcept { + reconnectThread_.quit(); + if (websocket_) { + websocket_->setOnClosedCallback(nullptr); + websocket_->setOnMessageCallback(nullptr); + websocket_->close("PackagerConnection destroyed"); + } +} + +void PackagerConnection::attemptConnection() { + if (websocket_) { + websocket_->setOnClosedCallback(nullptr); + websocket_->close("reconnecting"); + } + websocket_ = webSocketClientFactory_(); websocket_->setOnMessageCallback([this](const std::string& message) { LOG(INFO) << "Received message from packager: " << message; - auto json = nlohmann::json::parse(message); - if (json.is_null() || json["version"] != 2) { + auto json = nlohmann::json::parse(message, nullptr, false); + if (json.is_discarded() || json.is_null() || json["version"] != 2) { return; } auto method = json["method"]; @@ -34,11 +52,38 @@ PackagerConnection::PackagerConnection( showDevMenuCallback_(); } }); - websocket_->connect(packagerConnectionUrl); + websocket_->setOnClosedCallback([this](const std::string& reason) { + LOG(INFO) << "PackagerConnection closed: " << reason; + scheduleReconnect(); + }); + websocket_->connect( + packagerConnectionUrl_, + [this](bool success, const std::string& /*error*/) { + if (success) { + if (!isInitialConnection_) { + LOG(INFO) + << "PackagerConnection connected to Metro - triggering live reload"; + liveReloadCallback_(); + } else { + LOG(INFO) << "PackagerConnection connected to Metro"; + } + isInitialConnection_ = false; + } else { + scheduleReconnect(); + } + }); } -PackagerConnection::~PackagerConnection() noexcept { - websocket_->close("PackagerConnection destroyed"); +void PackagerConnection::scheduleReconnect() { + if (reconnectPending_.exchange(true)) { + return; + } + reconnectThread_.runAsync( + [this]() { + reconnectPending_ = false; + attemptConnection(); + }, + std::chrono::milliseconds(5000)); } } // namespace facebook::react diff --git a/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.h b/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.h index eee5149fd438..7e1596c0f2ba 100644 --- a/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.h +++ b/packages/react-native/ReactCxxPlatform/react/devsupport/PackagerConnection.h @@ -8,6 +8,8 @@ #pragma once #include +#include +#include #include #include #include @@ -20,8 +22,8 @@ class PackagerConnection { public: PackagerConnection( - const WebSocketClientFactory &webSocketClientFactory, - const std::string &packagerConnectionUrl, + WebSocketClientFactory webSocketClientFactory, + std::string packagerConnectionUrl, LiveReloadCallback &&liveReloadCallback, ShowDevMenuCallback &&showDevMenuCallback); ~PackagerConnection() noexcept; @@ -31,9 +33,17 @@ class PackagerConnection { PackagerConnection &operator=(PackagerConnection &&other) = delete; private: + void attemptConnection(); + void scheduleReconnect(); + + const WebSocketClientFactory webSocketClientFactory_; + const std::string packagerConnectionUrl_; const LiveReloadCallback liveReloadCallback_; const ShowDevMenuCallback showDevMenuCallback_; std::unique_ptr websocket_; + std::atomic isInitialConnection_{true}; + std::atomic reconnectPending_{false}; + TaskDispatchThread reconnectThread_{"PackagerReconnect"}; }; } // namespace facebook::react