Add native delta client for Metro

Summary:
Adds C++ delta client that keeps modules in memory, and can be used as a RAM bundle.

For now, this client expects a `folly::dynamic` object as payload for patches, i.e. the JSON response retrieved from Metro needs to be parsed with `folly::parseJson` by the caller.

In the future, we will replace JSON with a streaming friendly binary format.

Reviewed By: fromcelticpark

Differential Revision: D7845136

fbshipit-source-id: f003f98a2607c8354c427a7e60e01e19e20295b1
This commit is contained in:
David Aurelio 2018-05-03 08:38:01 -07:00 committed by Facebook Github Bot
parent e8662a2123
commit 4d931d529e
6 changed files with 121 additions and 1 deletions

View File

@ -82,7 +82,7 @@ JSModulesUnbundle::Module JniJSModulesUnbundle::getModule(uint32_t moduleId) con
buffer = static_cast<const char *>(AAsset_getBuffer(asset.get()));
}
if (buffer == nullptr) {
throw ModuleNotFound("Module not found: " + sourceUrl);
throw ModuleNotFound(moduleId);
}
return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))};
}

View File

@ -17,6 +17,7 @@ LOCAL_SRC_FILES := \
JSCSamplingProfiler.cpp \
JSCTracing.cpp \
JSCUtils.cpp \
JSDeltaBundleClient.cpp \
JSExecutor.cpp \
JSIndexedRAMBundle.cpp \
MethodCall.cpp \

View File

@ -92,6 +92,7 @@ CXXREACT_PUBLIC_HEADERS = [
"JSCExecutor.h",
"JSCNativeModules.h",
"JSCUtils.h",
"JSDeltaBundleClient.h",
"JSIndexedRAMBundle.h",
"JSModulesUnbundle.h",
"MessageQueueThread.h",

View File

@ -0,0 +1,72 @@
#include "JSDeltaBundleClient.h"
#include <sstream>
#include <folly/Memory.h>
namespace facebook {
namespace react {
namespace {
std::string startupCode(const folly::dynamic *pre, const folly::dynamic *post) {
std::ostringstream startupCode;
for (auto section : {pre, post}) {
if (section != nullptr) {
for (folly::dynamic pair : *section) {
startupCode << pair[1].getString() << '\n';
}
}
}
return startupCode.str();
}
} // namespace
void JSDeltaBundleClient::patch(const folly::dynamic& delta) {
auto const reset = delta.get_ptr("reset");
if (reset != nullptr && reset->asBool()) {
clear();
}
auto const pre = delta.get_ptr("pre");
auto const post = delta.get_ptr("post");
if ((pre != nullptr && pre->size() > 0) || (post != nullptr && post->size() > 0)) {
startupCode_ = startupCode(pre, post);
}
const folly::dynamic *modules = delta.get_ptr("delta");
if (modules != nullptr) {
for (const folly::dynamic pair : *modules) {
auto id = pair[0].getInt();
auto module = pair[1];
if (module.isNull()) {
modules_.erase(id);
} else {
modules_.emplace(id, module.getString());
}
}
}
}
JSModulesUnbundle::Module JSDeltaBundleClient::getModule(uint32_t moduleId) const {
auto search = modules_.find(moduleId);
if (search != modules_.end()) {
return {folly::to<std::string>(search->first, ".js"), search->second};
}
throw JSModulesUnbundle::ModuleNotFound(moduleId);
}
std::unique_ptr<const JSBigString> JSDeltaBundleClient::getStartupCode() const {
return folly::make_unique<JSBigStdString>(startupCode_);
}
void JSDeltaBundleClient::clear() {
modules_.clear();
startupCode_.clear();
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,42 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <cstdint>
#include <memory>
#include <string>
#include <unordered_map>
#include <cxxreact/JSBigString.h>
#include <cxxreact/JSModulesUnbundle.h>
#include <folly/dynamic.h>
namespace facebook {
namespace react {
class JSDeltaBundleClient {
public:
void patch(const folly::dynamic& delta);
JSModulesUnbundle::Module getModule(uint32_t moduleId) const;
std::unique_ptr<const JSBigString> getStartupCode() const;
void clear();
private:
std::unordered_map<uint32_t, std::string> modules_;
std::string startupCode_;
};
class JSDeltaBundleClientRAMBundle : public JSModulesUnbundle {
public:
JSDeltaBundleClientRAMBundle(
std::shared_ptr<const JSDeltaBundleClient> client) : client_(client) {}
Module getModule(uint32_t moduleId) const override {
return client_->getModule(moduleId);
}
private:
const std::shared_ptr<const JSDeltaBundleClient> client_;
};
} // namespace react
} // namespace facebook

View File

@ -6,6 +6,7 @@
#include <string>
#include <stdexcept>
#include <folly/Conv.h>
#include <jschelpers/noncopyable.h>
namespace facebook {
@ -21,7 +22,10 @@ class JSModulesUnbundle : noncopyable {
*/
public:
class ModuleNotFound : public std::out_of_range {
public:
using std::out_of_range::out_of_range;
ModuleNotFound(uint32_t moduleId) : std::out_of_range::out_of_range(
folly::to<std::string>("Module not found: ", moduleId)) {}
};
struct Module {
std::string name;