Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 "DevLoadingViewModule.h"

namespace facebook::react {

const int32_t DEFAULT_TEXT_COLOR = 0xFFFFFFFF;
const int32_t DEFAULT_BACKGROUND_COLOR = 0xFF2584E8;

DevLoadingViewModule::DevLoadingViewModule(
std::shared_ptr<CallInvoker> jsInvoker,
std::weak_ptr<IDevUIDelegate> devUIDelegate)
: NativeDevLoadingViewCxxSpec(jsInvoker),
devUIDelegate_(std::move(devUIDelegate)) {}

DevLoadingViewModule::~DevLoadingViewModule() {
if (auto devUIDelegate = devUIDelegate_.lock()) {
devUIDelegate->hideLoadingView();
}
}

void DevLoadingViewModule::showMessage(
jsi::Runtime& /*rt*/,
const std::string& message,
std::optional<int32_t> textColor,
std::optional<int32_t> backgroundColor) {
if (auto devUIDelegate = devUIDelegate_.lock()) {
devUIDelegate->showLoadingView(
message,
SharedColor{textColor.value_or(DEFAULT_TEXT_COLOR)},
SharedColor{backgroundColor.value_or(DEFAULT_BACKGROUND_COLOR)});
}
}

void DevLoadingViewModule::hide(jsi::Runtime& /*rt*/) {
if (auto devUIDelegate = devUIDelegate_.lock()) {
devUIDelegate->hideLoadingView();
}
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* 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 "IDevUIDelegate.h"

#include <FBReactNativeSpec/FBReactNativeSpecJSI.h>
#include <jsi/jsi.h>
#include <optional>

namespace facebook::react {

class DevLoadingViewModule
: public NativeDevLoadingViewCxxSpec<DevLoadingViewModule> {
public:
DevLoadingViewModule(
std::shared_ptr<CallInvoker> jsInvoker,
std::weak_ptr<IDevUIDelegate> devUIDelegate);

~DevLoadingViewModule() override;

void showMessage(
jsi::Runtime& rt,
const std::string& message,
std::optional<int32_t> textColor,
std::optional<int32_t> backgroundColor);

void hide(jsi::Runtime& rt);

private:
std::weak_ptr<IDevUIDelegate> devUIDelegate_;
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* 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 "DevServerHelper.h"

#include <fmt/format.h>
#include <glog/logging.h>
#include <jsinspector-modern/InspectorFlags.h>
#include <openssl/sha.h>
#include <react/devsupport/inspector/Inspector.h>
#include <react/devsupport/inspector/InspectorPackagerConnectionDelegate.h>
#include <iomanip>
#include <regex>

namespace {

constexpr std::string_view DEFAULT_PLATFORM = "android";

std::string SHA256(const std::string& input) {
std::array<unsigned char, SHA256_DIGEST_LENGTH> hash{};
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, input.c_str(), input.size());
SHA256_Final(hash.data(), &sha256);
std::stringstream ss;
for (unsigned char i : hash) {
ss << std::hex << std::setw(2) << std::setfill('0') << (int)i;
}
return ss.str();
}

std::string urlEscape(const std::string& str) {
std::regex pattern("[^a-zA-Z0-9._~-]");
return std::regex_replace(str, pattern, "");
}

} // namespace

namespace facebook::react {

DevServerHelper::DevServerHelper(
std::string appId,
std::string deviceName,
const HttpClientFactory& httpClientFactory,
JavaScriptModuleCallback javaScriptModuleCallback) noexcept
: appId_(std::move(appId)),
deviceName_(std::move(deviceName)),
httpClient_(httpClientFactory()),
javaScriptModuleCallback_(std::move(javaScriptModuleCallback)) {
deviceId_ = SHA256(fmt::format("{}-{}", deviceName_, appId_));
}

std::future<std::string> DevServerHelper::downloadBundleResourceSync(
const std::string& jsBundleUrl,
DownloadProgressCallback&& downloadProgressCallback) {
auto promise = std::make_shared<std::promise<std::string>>();
http::NetworkCallbacks callbacks{
.onBody =
[jsBundleUrl, promise, downloadProgressCallback](
std::unique_ptr<folly::IOBuf> ioBuf) {
std::string responseStr = ioBuf->moveToFbString().toStdString();
promise->set_value(responseStr);
},
.onResponseComplete =
[jsBundleUrl, promise, downloadProgressCallback](
const std::string& error, bool timeoutError) {
if (!error.empty() || timeoutError) {
if (downloadProgressCallback) {
downloadProgressCallback(DownloadProgressStatus::FAILED);
}
std::string errorMessage =
"Failed to download JS bundle from Url: " + jsBundleUrl +
". Error: " + (error.empty() ? "Timeout" : error);
LOG(WARNING) << errorMessage;
try {
throw std::runtime_error(errorMessage);
} catch (...) {
try {
promise->set_exception(std::current_exception());
} catch (...) {
}
}
} else if (downloadProgressCallback) {
downloadProgressCallback(DownloadProgressStatus::FINISHED);
}
}};
httpClient_->sendRequest(std::move(callbacks), "GET", jsBundleUrl);
if (downloadProgressCallback) {
downloadProgressCallback(DownloadProgressStatus::STARTED);
}
return promise->get_future();
}

std::string DevServerHelper::getInspectorUrl() const {
bool isProfilingBuild =
jsinspector_modern::InspectorFlags::getInstance().getIsProfilingBuild();

return fmt::format(
"ws://{}:{}/inspector/device?name={}&app={}&device={}&profiling={}",
DEFAULT_DEV_SERVER_HOST,
DEFAULT_DEV_SERVER_PORT,
urlEscape(deviceName_),
appId_,
deviceId_,
isProfilingBuild);
}

std::string DevServerHelper::getBundleUrl() const {
if (sourcePath_.empty()) {
return "";
}

bool dev = true;
bool lazy = dev;
bool minify = false;
bool splitBundle = false;
bool modulesOnly = splitBundle;
bool runModule = !splitBundle;
return fmt::format(
"http://{}:{}/{}.bundle?platform={}&dev={}&lazy={}&minify={}&app={}&modulesOnly={}&runModule={}&inlineSourceMap=false&excludeSource=true&sourcePaths=url-server",
DEFAULT_DEV_SERVER_HOST,
DEFAULT_DEV_SERVER_PORT,
sourcePath_,
DEFAULT_PLATFORM,
dev,
lazy,
minify,
appId_,
modulesOnly,
runModule);
};

std::string DevServerHelper::getPackagerConnectionUrl() const {
return fmt::format(
"ws://{}:{}/message", DEFAULT_DEV_SERVER_HOST, DEFAULT_DEV_SERVER_PORT);
}

void DevServerHelper::openDebugger() const {
auto requestUrl = fmt::format(
"http://{}:{}/open-debugger?device={}",
DEFAULT_DEV_SERVER_HOST,
DEFAULT_DEV_SERVER_PORT,
deviceId_);
httpClient_->sendRequest({}, "POST", requestUrl);
}

void DevServerHelper::setupHMRClient() const {
folly::dynamic params = folly::dynamic::array(
DEFAULT_PLATFORM,
sourcePath_,
DEFAULT_DEV_SERVER_HOST,
DEFAULT_DEV_SERVER_PORT,
true /*enable*/);
javaScriptModuleCallback_("HMRClient", "setup", std::move(params));
}

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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 <folly/dynamic.h>
#include <react/http/IHttpClient.h>
#include <react/nativemodule/JavaScriptModule.h>
#include <future>
#include <memory>
#include <string>

namespace facebook::react {

namespace {

constexpr std::string_view DEFAULT_DEV_SERVER_HOST = "localhost";
constexpr uint32_t DEFAULT_DEV_SERVER_PORT = 8081;

} // namespace

class DevServerHelper {
public:
enum class DownloadProgressStatus : short { STARTED, FAILED, FINISHED };
using DownloadProgressCallback = std::function<void(DownloadProgressStatus)>;

DevServerHelper(
std::string appId,
std::string deviceName,
const HttpClientFactory& httpClientFactory,
JavaScriptModuleCallback javaScriptModuleCallback) noexcept;
~DevServerHelper() noexcept = default;

std::future<std::string> downloadBundleResourceSync(
const std::string& jsBundleUrl,
DownloadProgressCallback&& downloadProgressCallback = nullptr);

std::string getInspectorUrl() const;

std::string getBundleUrl() const;

std::string getPackagerConnectionUrl() const;

void openDebugger() const;

void setSourcePath(const std::string& sourcePath) {
sourcePath_ = sourcePath;
}

void setupHMRClient() const;

private:
std::string appId_;
std::string deviceName_;
std::unique_ptr<IHttpClient> httpClient_;
JavaScriptModuleCallback javaScriptModuleCallback_;
std::string deviceId_;
std::string sourcePath_;
};

} // namespace facebook::react
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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 "DevSettingsModule.h"

#include <glog/logging.h>

namespace facebook::react {

void DevSettingsModule::reload(jsi::Runtime& /*rt*/) {
LOG(INFO) << "DevSettingsModule::reload";
if (liveReloadCallback_) {
liveReloadCallback_();
}
}

void DevSettingsModule::reloadWithReason(
jsi::Runtime& /*rt*/,
const std::string& reason) {
LOG(INFO) << "DevSettingsModule::reloadWithReason: " << reason;
if (liveReloadCallback_) {
liveReloadCallback_();
}
}

void DevSettingsModule::onFastRefresh(jsi::Runtime& /*rt*/) {
LOG(INFO) << "DevSettingsModule::onFastRefresh";
}

void DevSettingsModule::setHotLoadingEnabled(
jsi::Runtime& /*rt*/,
bool isHotLoadingEnabled) {
LOG(INFO) << "DevSettingsModule::setHotLoadingEnabled: "
<< (int)isHotLoadingEnabled;
}

void DevSettingsModule::setIsDebuggingRemotely(
jsi::Runtime& /*rt*/,
bool /*isDebuggingRemotelyEnabled*/) {}

void DevSettingsModule::setProfilingEnabled(
jsi::Runtime& /*rt*/,
bool /*isProfilingEnabled*/) {}

void DevSettingsModule::toggleElementInspector(jsi::Runtime& rt) {}

void DevSettingsModule::addMenuItem(
jsi::Runtime& /*rt*/,
const std::string& /*title*/) {}

void DevSettingsModule::setIsShakeToShowDevMenuEnabled(
jsi::Runtime& /*rt*/,
bool /*enabled*/) {}

void DevSettingsModule::openDebugger(jsi::Runtime& /*rt*/) {
if (auto devServerHelper = devServerHelper_.lock()) {
devServerHelper->openDebugger();
}
}

void DevSettingsModule::addListener(
jsi::Runtime& /*rt*/,
const std::string& /*eventName*/) {
// noop
}

void DevSettingsModule::removeListeners(
jsi::Runtime& /*rt*/,
double /*count*/) {
// noop
}

} // namespace facebook::react
Loading
Loading