react-native-windows 0.69.0-preview.2 → 0.69.0-preview.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Directory.Build.props +4 -0
- package/Folly/Folly.vcxproj +4 -5
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Network/RCTNetworkingWinShared.js +7 -0
- package/Libraries/Utilities/codegenNativeComponent.js +5 -6
- package/Libraries/Utilities/useColorScheme.js +9 -15
- package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +3 -1
- package/Microsoft.ReactNative/IReactContext.cpp +17 -0
- package/Microsoft.ReactNative/IReactContext.h +2 -0
- package/Microsoft.ReactNative/IReactContext.idl +27 -0
- package/Microsoft.ReactNative/JsiApi.cpp +9 -0
- package/Microsoft.ReactNative/JsiApi.h +1 -0
- package/Microsoft.ReactNative/JsiApi.idl +1 -0
- package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp +3 -5
- package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h +1 -1
- package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp +31 -9
- package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.h +48 -0
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +2 -2
- package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems.filters +1 -1
- package/Microsoft.ReactNative.Managed/packages.lock.json +57 -2
- package/PropertySheets/Generated/PackageVersion.g.props +1 -1
- package/PropertySheets/JSEngine.props +2 -2
- package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +9 -5
- package/Shared/CreateModules.h +17 -2
- package/Shared/InspectorPackagerConnection.cpp +6 -7
- package/Shared/InspectorPackagerConnection.h +1 -1
- package/Shared/JSI/ChakraRuntime.cpp +5 -0
- package/Shared/JSI/ChakraRuntime.h +1 -0
- package/Shared/JSI/NapiJsiV8RuntimeHolder.cpp +72 -2
- package/Shared/JSI/NapiJsiV8RuntimeHolder.h +2 -0
- package/Shared/Modules/BlobModule.cpp +376 -0
- package/Shared/Modules/BlobModule.h +153 -0
- package/Shared/Modules/CxxModuleUtilities.cpp +19 -0
- package/Shared/Modules/CxxModuleUtilities.h +23 -0
- package/Shared/Modules/FileReaderModule.cpp +156 -0
- package/Shared/Modules/FileReaderModule.h +54 -0
- package/Shared/Modules/HttpModule.cpp +72 -69
- package/Shared/Modules/HttpModule.h +8 -1
- package/Shared/Modules/IBlobPersistor.h +30 -0
- package/Shared/Modules/IHttpModuleProxy.h +30 -0
- package/Shared/Modules/IRequestBodyHandler.h +52 -0
- package/Shared/Modules/IResponseHandler.h +27 -0
- package/Shared/Modules/IUriHandler.h +37 -0
- package/Shared/Modules/IWebSocketModuleContentHandler.h +26 -0
- package/Shared/Modules/IWebSocketModuleProxy.h +22 -0
- package/Shared/Modules/NetworkingModule.cpp +1 -1
- package/Shared/Modules/WebSocketModule.cpp +92 -22
- package/Shared/Modules/WebSocketModule.h +27 -1
- package/Shared/Networking/IHttpResource.h +50 -2
- package/Shared/Networking/WinRTHttpResource.cpp +169 -51
- package/Shared/Networking/WinRTHttpResource.h +27 -8
- package/Shared/Networking/WinRTTypes.h +5 -2
- package/Shared/OInstance.cpp +22 -5
- package/Shared/OInstance.h +8 -4
- package/Shared/RuntimeOptions.cpp +6 -3
- package/Shared/RuntimeOptions.h +14 -3
- package/Shared/Shared.vcxitems +13 -0
- package/Shared/Shared.vcxitems.filters +40 -1
- package/fmt/fmt.vcxproj +4 -5
- package/package.json +14 -12
- package/template/cs-app-WinAppSDK/proj/NuGet.Config +3 -1
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/JSCRuntime.cpp +0 -1480
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/decorator.h +0 -753
- package/ReactCommon/TEMP_UntilReactCommonUpdate/jsi/jsi/jsi.h +0 -1331
|
@@ -86,8 +86,8 @@ struct InspectorProtocol {
|
|
|
86
86
|
for (const facebook::react::InspectorPage2 &page : pages) {
|
|
87
87
|
folly::dynamic pageDyn = folly::dynamic::object;
|
|
88
88
|
pageDyn["id"] = page.id;
|
|
89
|
-
pageDyn["title"] = std::string(page.title
|
|
90
|
-
pageDyn["vm"] = std::string(page.vm
|
|
89
|
+
pageDyn["title"] = std::string(page.title);
|
|
90
|
+
pageDyn["vm"] = std::string(page.vm);
|
|
91
91
|
|
|
92
92
|
pageDyn["isLastBundleDownloadSuccess"] = bundleStatus.m_isLastDownloadSucess;
|
|
93
93
|
pageDyn["bundleUpdateTimestamp"] = bundleStatus.m_updateTimestamp;
|
|
@@ -105,8 +105,8 @@ struct InspectorProtocol {
|
|
|
105
105
|
const facebook::react::InspectorPage2 page = pages->getPage(p);
|
|
106
106
|
folly::dynamic pageDyn = folly::dynamic::object;
|
|
107
107
|
pageDyn["id"] = page.id;
|
|
108
|
-
pageDyn["title"] = page.title
|
|
109
|
-
pageDyn["vm"] = page.vm
|
|
108
|
+
pageDyn["title"] = page.title;
|
|
109
|
+
pageDyn["vm"] = page.vm;
|
|
110
110
|
|
|
111
111
|
pageDyn["isLastBundleDownloadSuccess"] = bundleStatus.m_isLastDownloadSucess;
|
|
112
112
|
pageDyn["bundleUpdateTimestamp"] = bundleStatus.m_updateTimestamp;
|
|
@@ -155,11 +155,10 @@ void RemoteConnection::onDisconnect() {
|
|
|
155
155
|
RemoteConnection2::RemoteConnection2(int64_t pageId, const InspectorPackagerConnection &packagerConnection)
|
|
156
156
|
: m_packagerConnection(packagerConnection), m_pageId(pageId) {}
|
|
157
157
|
|
|
158
|
-
void RemoteConnection2::onMessage(std::
|
|
159
|
-
std::string msg(message->c_str());
|
|
158
|
+
void RemoteConnection2::onMessage(std::string message) {
|
|
160
159
|
folly::dynamic response = InspectorProtocol::constructResponseForPackager(
|
|
161
160
|
InspectorProtocol::EventType::WrappedEvent,
|
|
162
|
-
InspectorProtocol::constructVMResponsePayloadForPackager(m_pageId, std::move(
|
|
161
|
+
InspectorProtocol::constructVMResponsePayloadForPackager(m_pageId, std::move(message)));
|
|
163
162
|
std::string responsestr = folly::toJson(response);
|
|
164
163
|
m_packagerConnection.sendMessageToPackager(std::move(responsestr));
|
|
165
164
|
}
|
|
@@ -61,7 +61,7 @@ class RemoteConnection final : public facebook::react::IRemoteConnection {
|
|
|
61
61
|
class RemoteConnection2 final : public facebook::react::IRemoteConnection2 {
|
|
62
62
|
public:
|
|
63
63
|
RemoteConnection2(int64_t pageId, const InspectorPackagerConnection &packagerConnection);
|
|
64
|
-
void onMessage(std::
|
|
64
|
+
void onMessage(std::string message) override;
|
|
65
65
|
void onDisconnect() override;
|
|
66
66
|
|
|
67
67
|
private:
|
|
@@ -311,6 +311,11 @@ facebook::jsi::PropNameID ChakraRuntime::createPropNameIDFromString(const facebo
|
|
|
311
311
|
return MakePointer<facebook::jsi::PropNameID>(propertyId);
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
facebook::jsi::PropNameID ChakraRuntime::createPropNameIDFromSymbol(const facebook::jsi::Symbol &sym) {
|
|
315
|
+
const JsPropertyIdRef propSym = GetPropertyIdFromSymbol(GetJsRef(sym));
|
|
316
|
+
return MakePointer<facebook::jsi::PropNameID>(propSym);
|
|
317
|
+
}
|
|
318
|
+
|
|
314
319
|
std::string ChakraRuntime::utf8(const facebook::jsi::PropNameID &id) {
|
|
315
320
|
return Common::Unicode::Utf16ToUtf8(GetPropertyNameFromId(GetJsRef(id)));
|
|
316
321
|
}
|
|
@@ -63,6 +63,7 @@ class ChakraRuntime : public facebook::jsi::Runtime, public ChakraApi, ChakraApi
|
|
|
63
63
|
facebook::jsi::PropNameID createPropNameIDFromAscii(const char *str, size_t length) override;
|
|
64
64
|
facebook::jsi::PropNameID createPropNameIDFromUtf8(const uint8_t *utf8, size_t length) override;
|
|
65
65
|
facebook::jsi::PropNameID createPropNameIDFromString(const facebook::jsi::String &str) override;
|
|
66
|
+
facebook::jsi::PropNameID createPropNameIDFromSymbol(const facebook::jsi::Symbol &sym) override;
|
|
66
67
|
std::string utf8(const facebook::jsi::PropNameID &id) override;
|
|
67
68
|
bool compare(const facebook::jsi::PropNameID &lhs, const facebook::jsi::PropNameID &rhs) override;
|
|
68
69
|
|
|
@@ -77,17 +77,20 @@ NapiJsiV8RuntimeHolder::NapiJsiV8RuntimeHolder(
|
|
|
77
77
|
m_preparedScriptStore{std::move(preparedScriptStore)} {}
|
|
78
78
|
|
|
79
79
|
void NapiJsiV8RuntimeHolder::InitRuntime() noexcept {
|
|
80
|
-
napi_env env{};
|
|
81
80
|
napi_ext_env_settings settings{};
|
|
82
81
|
settings.this_size = sizeof(settings);
|
|
83
|
-
settings.flags.enable_gc_api = true;
|
|
84
82
|
if (m_debuggerPort > 0)
|
|
85
83
|
settings.inspector_port = m_debuggerPort;
|
|
86
84
|
|
|
87
85
|
settings.flags.enable_inspector = m_useDirectDebugger;
|
|
88
86
|
settings.flags.wait_for_debugger = m_debuggerBreakOnNextLine;
|
|
87
|
+
// TODO: args.debuggerRuntimeName = debuggerRuntimeName_;
|
|
89
88
|
settings.foreground_scheduler = &NapiJsiV8RuntimeHolder::ScheduleTaskCallback;
|
|
90
89
|
|
|
90
|
+
napi_ext_script_cache scriptCache = InitScriptCache(std::move(m_preparedScriptStore));
|
|
91
|
+
settings.script_cache = &scriptCache;
|
|
92
|
+
|
|
93
|
+
napi_env env{};
|
|
91
94
|
napi_ext_create_env(&settings, &env);
|
|
92
95
|
// Associate environment to holder.
|
|
93
96
|
napi_set_instance_data(env, this, nullptr /*finalize_cb*/, nullptr /*finalize_hint*/);
|
|
@@ -96,6 +99,73 @@ void NapiJsiV8RuntimeHolder::InitRuntime() noexcept {
|
|
|
96
99
|
m_ownThreadId = std::this_thread::get_id();
|
|
97
100
|
}
|
|
98
101
|
|
|
102
|
+
struct NodeApiJsiBuffer : facebook::jsi::Buffer {
|
|
103
|
+
static std::shared_ptr<const facebook::jsi::Buffer> CreateJsiBuffer(const napi_ext_buffer *buffer) {
|
|
104
|
+
if (buffer && buffer->data) {
|
|
105
|
+
return std::shared_ptr<const facebook::jsi::Buffer>(new NodeApiJsiBuffer(buffer));
|
|
106
|
+
} else {
|
|
107
|
+
return {};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
NodeApiJsiBuffer(const napi_ext_buffer *buffer) noexcept : buffer_(*buffer) {}
|
|
112
|
+
|
|
113
|
+
~NodeApiJsiBuffer() override {
|
|
114
|
+
if (buffer_.buffer_object.finalize_cb) {
|
|
115
|
+
buffer_.buffer_object.finalize_cb(nullptr, buffer_.buffer_object.data, buffer_.buffer_object.finalize_hint);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const uint8_t *data() const override {
|
|
120
|
+
return buffer_.data;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
size_t size() const override {
|
|
124
|
+
return buffer_.byte_size;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private:
|
|
128
|
+
napi_ext_buffer buffer_;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
napi_ext_script_cache NapiJsiV8RuntimeHolder::InitScriptCache(
|
|
132
|
+
unique_ptr<PreparedScriptStore> &&preparedScriptStore) noexcept {
|
|
133
|
+
napi_ext_script_cache scriptCache{};
|
|
134
|
+
scriptCache.cache_object = NativeObjectWrapper<unique_ptr<PreparedScriptStore>>::Wrap(std::move(preparedScriptStore));
|
|
135
|
+
scriptCache.load_cached_script = [](napi_env env,
|
|
136
|
+
napi_ext_script_cache *script_cache,
|
|
137
|
+
napi_ext_cached_script_metadata *script_metadata,
|
|
138
|
+
napi_ext_buffer *result) -> napi_status {
|
|
139
|
+
PreparedScriptStore *scriptStore = reinterpret_cast<PreparedScriptStore *>(script_cache->cache_object.data);
|
|
140
|
+
std::shared_ptr<const facebook::jsi::Buffer> buffer = scriptStore->tryGetPreparedScript(
|
|
141
|
+
ScriptSignature{script_metadata->source_url, script_metadata->source_hash},
|
|
142
|
+
JSRuntimeSignature{script_metadata->runtime_name, script_metadata->runtime_version},
|
|
143
|
+
script_metadata->tag);
|
|
144
|
+
if (buffer) {
|
|
145
|
+
result->buffer_object = NativeObjectWrapper<std::shared_ptr<const facebook::jsi::Buffer>>::Wrap(
|
|
146
|
+
std::shared_ptr<const facebook::jsi::Buffer>{buffer});
|
|
147
|
+
result->data = buffer->data();
|
|
148
|
+
result->byte_size = buffer->size();
|
|
149
|
+
} else {
|
|
150
|
+
*result = napi_ext_buffer{};
|
|
151
|
+
}
|
|
152
|
+
return napi_ok;
|
|
153
|
+
};
|
|
154
|
+
scriptCache.store_cached_script = [](napi_env env,
|
|
155
|
+
napi_ext_script_cache *script_cache,
|
|
156
|
+
napi_ext_cached_script_metadata *script_metadata,
|
|
157
|
+
const napi_ext_buffer *buffer) -> napi_status {
|
|
158
|
+
PreparedScriptStore *scriptStore = reinterpret_cast<PreparedScriptStore *>(script_cache->cache_object.data);
|
|
159
|
+
scriptStore->persistPreparedScript(
|
|
160
|
+
NodeApiJsiBuffer::CreateJsiBuffer(buffer),
|
|
161
|
+
ScriptSignature{script_metadata->source_url, script_metadata->source_hash},
|
|
162
|
+
JSRuntimeSignature{script_metadata->runtime_name, script_metadata->runtime_version},
|
|
163
|
+
script_metadata->tag);
|
|
164
|
+
return napi_ok;
|
|
165
|
+
};
|
|
166
|
+
return scriptCache;
|
|
167
|
+
}
|
|
168
|
+
|
|
99
169
|
#pragma region Microsoft::JSI::RuntimeHolderLazyInit
|
|
100
170
|
|
|
101
171
|
facebook::react::JSIEngineOverride NapiJsiV8RuntimeHolder::getRuntimeType() noexcept {
|
|
@@ -31,6 +31,8 @@ class NapiJsiV8RuntimeHolder : public Microsoft::JSI::RuntimeHolderLazyInit {
|
|
|
31
31
|
void *finalizeHint);
|
|
32
32
|
|
|
33
33
|
void InitRuntime() noexcept;
|
|
34
|
+
napi_ext_script_cache InitScriptCache(
|
|
35
|
+
std::unique_ptr<facebook::jsi::PreparedScriptStore> &&preparedScriptStore) noexcept;
|
|
34
36
|
|
|
35
37
|
std::shared_ptr<facebook::jsi::Runtime> m_runtime;
|
|
36
38
|
std::shared_ptr<facebook::react::MessageQueueThread> m_jsQueue;
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#include "BlobModule.h"
|
|
5
|
+
|
|
6
|
+
#include <Modules/CxxModuleUtilities.h>
|
|
7
|
+
#include <Modules/IHttpModuleProxy.h>
|
|
8
|
+
#include <Modules/IWebSocketModuleProxy.h>
|
|
9
|
+
#include <ReactPropertyBag.h>
|
|
10
|
+
#include <unicode.h>
|
|
11
|
+
|
|
12
|
+
// React Native
|
|
13
|
+
#include <cxxreact/JsArgumentHelpers.h>
|
|
14
|
+
|
|
15
|
+
// Windows API
|
|
16
|
+
#include <winrt/Windows.Foundation.h>
|
|
17
|
+
#include <winrt/Windows.Security.Cryptography.h>
|
|
18
|
+
|
|
19
|
+
// Standard Library
|
|
20
|
+
#include <chrono>
|
|
21
|
+
#include <filesystem>
|
|
22
|
+
#include <fstream>
|
|
23
|
+
|
|
24
|
+
using namespace facebook::xplat;
|
|
25
|
+
|
|
26
|
+
using folly::dynamic;
|
|
27
|
+
using std::scoped_lock;
|
|
28
|
+
using std::shared_ptr;
|
|
29
|
+
using std::string;
|
|
30
|
+
using std::vector;
|
|
31
|
+
using std::weak_ptr;
|
|
32
|
+
using winrt::Microsoft::ReactNative::IReactPropertyBag;
|
|
33
|
+
using winrt::Microsoft::ReactNative::ReactNonAbiValue;
|
|
34
|
+
using winrt::Microsoft::ReactNative::ReactPropertyBag;
|
|
35
|
+
using winrt::Microsoft::ReactNative::ReactPropertyId;
|
|
36
|
+
using winrt::Windows::Foundation::GuidHelper;
|
|
37
|
+
using winrt::Windows::Foundation::IInspectable;
|
|
38
|
+
using winrt::Windows::Foundation::Uri;
|
|
39
|
+
using winrt::Windows::Security::Cryptography::CryptographicBuffer;
|
|
40
|
+
|
|
41
|
+
namespace fs = std::filesystem;
|
|
42
|
+
|
|
43
|
+
namespace {
|
|
44
|
+
constexpr char moduleName[] = "BlobModule";
|
|
45
|
+
constexpr char blobKey[] = "blob";
|
|
46
|
+
constexpr char blobIdKey[] = "blobId";
|
|
47
|
+
constexpr char offsetKey[] = "offset";
|
|
48
|
+
constexpr char sizeKey[] = "size";
|
|
49
|
+
constexpr char typeKey[] = "type";
|
|
50
|
+
constexpr char dataKey[] = "data";
|
|
51
|
+
} // namespace
|
|
52
|
+
|
|
53
|
+
namespace Microsoft::React {
|
|
54
|
+
|
|
55
|
+
#pragma region BlobModule
|
|
56
|
+
|
|
57
|
+
BlobModule::BlobModule(winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept
|
|
58
|
+
: m_sharedState{std::make_shared<SharedState>()},
|
|
59
|
+
m_blobPersistor{std::make_shared<MemoryBlobPersistor>()},
|
|
60
|
+
m_contentHandler{std::make_shared<BlobWebSocketModuleContentHandler>(m_blobPersistor)},
|
|
61
|
+
m_requestBodyHandler{std::make_shared<BlobModuleRequestBodyHandler>(m_blobPersistor)},
|
|
62
|
+
m_responseHandler{std::make_shared<BlobModuleResponseHandler>(m_blobPersistor)},
|
|
63
|
+
m_inspectableProperties{inspectableProperties} {
|
|
64
|
+
auto propBag = ReactPropertyBag{m_inspectableProperties.try_as<IReactPropertyBag>()};
|
|
65
|
+
|
|
66
|
+
auto contentHandlerPropId =
|
|
67
|
+
ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleContentHandler>>>{L"BlobModule.ContentHandler"};
|
|
68
|
+
auto contentHandler = weak_ptr<IWebSocketModuleContentHandler>{m_contentHandler};
|
|
69
|
+
propBag.Set(contentHandlerPropId, std::move(contentHandler));
|
|
70
|
+
|
|
71
|
+
auto blobPersistorPropId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IBlobPersistor>>>{L"Blob.Persistor"};
|
|
72
|
+
auto blobPersistor = weak_ptr<IBlobPersistor>{m_blobPersistor};
|
|
73
|
+
propBag.Set(blobPersistorPropId, std::move(blobPersistor));
|
|
74
|
+
|
|
75
|
+
m_sharedState->Module = this;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
BlobModule::~BlobModule() noexcept /*override*/ {
|
|
79
|
+
m_sharedState->Module = nullptr;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#pragma region CxxModule
|
|
83
|
+
|
|
84
|
+
string BlobModule::getName() {
|
|
85
|
+
return moduleName;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
std::map<string, dynamic> BlobModule::getConstants() {
|
|
89
|
+
return {{"BLOB_URI_SCHEME", blobKey}, {"BLOB_URI_HOST", {}}};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
vector<module::CxxModule::Method> BlobModule::getMethods() {
|
|
93
|
+
return {
|
|
94
|
+
{"addNetworkingHandler",
|
|
95
|
+
[propBag = ReactPropertyBag{m_inspectableProperties.try_as<IReactPropertyBag>()},
|
|
96
|
+
requestBodyHandler = m_requestBodyHandler,
|
|
97
|
+
responseHandler = m_responseHandler](dynamic args) {
|
|
98
|
+
auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IHttpModuleProxy>>>{L"HttpModule.Proxy"};
|
|
99
|
+
|
|
100
|
+
if (auto prop = propBag.Get(propId)) {
|
|
101
|
+
if (auto httpHandler = prop.Value().lock()) {
|
|
102
|
+
httpHandler->AddRequestBodyHandler(requestBodyHandler);
|
|
103
|
+
httpHandler->AddResponseHandler(responseHandler);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// TODO: else emit error?
|
|
107
|
+
}},
|
|
108
|
+
|
|
109
|
+
{"addWebSocketHandler",
|
|
110
|
+
[contentHandler = m_contentHandler](dynamic args) {
|
|
111
|
+
auto id = jsArgAsInt(args, 0);
|
|
112
|
+
|
|
113
|
+
contentHandler->Register(id);
|
|
114
|
+
}},
|
|
115
|
+
|
|
116
|
+
{"removeWebSocketHandler",
|
|
117
|
+
[contentHandler = m_contentHandler](dynamic args) {
|
|
118
|
+
auto id = jsArgAsInt(args, 0);
|
|
119
|
+
|
|
120
|
+
contentHandler->Unregister(id);
|
|
121
|
+
}},
|
|
122
|
+
|
|
123
|
+
{"sendOverSocket",
|
|
124
|
+
[weakState = weak_ptr<SharedState>(m_sharedState),
|
|
125
|
+
persistor = m_blobPersistor,
|
|
126
|
+
propBag = ReactPropertyBag{m_inspectableProperties.try_as<IReactPropertyBag>()}](dynamic args) {
|
|
127
|
+
auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleProxy>>>{L"WebSocketModule.Proxy"};
|
|
128
|
+
shared_ptr<IWebSocketModuleProxy> wsProxy;
|
|
129
|
+
if (auto prop = propBag.Get(propId)) {
|
|
130
|
+
wsProxy = prop.Value().lock();
|
|
131
|
+
}
|
|
132
|
+
if (!wsProxy) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
auto blob = jsArgAsObject(args, 0);
|
|
137
|
+
auto blobId = blob[blobIdKey].getString();
|
|
138
|
+
auto offset = blob[offsetKey].getInt();
|
|
139
|
+
auto size = blob[sizeKey].getInt();
|
|
140
|
+
auto socketID = jsArgAsInt(args, 1);
|
|
141
|
+
|
|
142
|
+
winrt::array_view<uint8_t> data;
|
|
143
|
+
try {
|
|
144
|
+
data = persistor->ResolveMessage(std::move(blobId), offset, size);
|
|
145
|
+
} catch (const std::exception &e) {
|
|
146
|
+
if (auto sharedState = weakState.lock()) {
|
|
147
|
+
Modules::SendEvent(sharedState->Module->getInstance(), "blobFailed", e.what());
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
auto buffer = CryptographicBuffer::CreateFromByteArray(data);
|
|
153
|
+
auto winrtString = CryptographicBuffer::EncodeToBase64String(std::move(buffer));
|
|
154
|
+
auto base64String = Common::Unicode::Utf16ToUtf8(std::move(winrtString));
|
|
155
|
+
|
|
156
|
+
wsProxy->SendBinary(std::move(base64String), socketID);
|
|
157
|
+
}},
|
|
158
|
+
|
|
159
|
+
{"createFromParts",
|
|
160
|
+
// As of React Native 0.67, instance is set AFTER CxxModule::getMethods() is invoked.
|
|
161
|
+
// Use getInstance() directly once
|
|
162
|
+
// https://github.com/facebook/react-native/commit/1d45b20b6c6ba66df0485cdb9be36463d96cf182 becomes available.
|
|
163
|
+
[persistor = m_blobPersistor, weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) {
|
|
164
|
+
auto parts = jsArgAsArray(args, 0); // Array<Object>
|
|
165
|
+
auto blobId = jsArgAsString(args, 1);
|
|
166
|
+
vector<uint8_t> buffer{};
|
|
167
|
+
|
|
168
|
+
for (const auto &part : parts) {
|
|
169
|
+
auto type = part[typeKey].asString();
|
|
170
|
+
if (blobKey == type) {
|
|
171
|
+
auto blob = part[dataKey];
|
|
172
|
+
winrt::array_view<uint8_t> bufferPart;
|
|
173
|
+
try {
|
|
174
|
+
bufferPart = persistor->ResolveMessage(
|
|
175
|
+
blob[blobIdKey].asString(), blob[offsetKey].asInt(), blob[sizeKey].asInt());
|
|
176
|
+
} catch (const std::exception &e) {
|
|
177
|
+
if (auto sharedState = weakState.lock()) {
|
|
178
|
+
Modules::SendEvent(sharedState->Module->getInstance(), "blobFailed", e.what());
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
buffer.reserve(buffer.size() + bufferPart.size());
|
|
184
|
+
buffer.insert(buffer.end(), bufferPart.begin(), bufferPart.end());
|
|
185
|
+
} else if ("string" == type) {
|
|
186
|
+
auto data = part[dataKey].asString();
|
|
187
|
+
|
|
188
|
+
buffer.reserve(buffer.size() + data.size());
|
|
189
|
+
buffer.insert(buffer.end(), data.begin(), data.end());
|
|
190
|
+
} else {
|
|
191
|
+
if (auto state = weakState.lock()) {
|
|
192
|
+
auto message = "Invalid type for blob: " + type;
|
|
193
|
+
Modules::SendEvent(state->Module->getInstance(), "blobFailed", std::move(message));
|
|
194
|
+
}
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
persistor->StoreMessage(std::move(buffer), std::move(blobId));
|
|
200
|
+
}},
|
|
201
|
+
|
|
202
|
+
{"release",
|
|
203
|
+
[persistor = m_blobPersistor](dynamic args) // blobId: string
|
|
204
|
+
{
|
|
205
|
+
auto blobId = jsArgAsString(args, 0);
|
|
206
|
+
|
|
207
|
+
persistor->RemoveMessage(std::move(blobId));
|
|
208
|
+
}}};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
#pragma endregion CxxModule
|
|
212
|
+
|
|
213
|
+
#pragma endregion BlobModule
|
|
214
|
+
|
|
215
|
+
#pragma region MemoryBlobPersistor
|
|
216
|
+
|
|
217
|
+
#pragma region IBlobPersistor
|
|
218
|
+
|
|
219
|
+
winrt::array_view<uint8_t> MemoryBlobPersistor::ResolveMessage(string &&blobId, int64_t offset, int64_t size) {
|
|
220
|
+
if (size < 1)
|
|
221
|
+
return {};
|
|
222
|
+
|
|
223
|
+
scoped_lock lock{m_mutex};
|
|
224
|
+
|
|
225
|
+
auto dataItr = m_blobs.find(std::move(blobId));
|
|
226
|
+
// Not found.
|
|
227
|
+
if (dataItr == m_blobs.cend())
|
|
228
|
+
throw std::invalid_argument("Blob object not found");
|
|
229
|
+
|
|
230
|
+
auto &bytes = (*dataItr).second;
|
|
231
|
+
auto endBound = static_cast<size_t>(offset + size);
|
|
232
|
+
// Out of bounds.
|
|
233
|
+
if (endBound > bytes.size() || offset >= static_cast<int64_t>(bytes.size()) || offset < 0)
|
|
234
|
+
throw std::out_of_range("Offset or size out of range");
|
|
235
|
+
|
|
236
|
+
return winrt::array_view<uint8_t>(bytes.data() + offset, bytes.data() + endBound);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
void MemoryBlobPersistor::RemoveMessage(string &&blobId) noexcept {
|
|
240
|
+
scoped_lock lock{m_mutex};
|
|
241
|
+
|
|
242
|
+
m_blobs.erase(std::move(blobId));
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
void MemoryBlobPersistor::StoreMessage(vector<uint8_t> &&message, string &&blobId) noexcept {
|
|
246
|
+
scoped_lock lock{m_mutex};
|
|
247
|
+
|
|
248
|
+
m_blobs.insert_or_assign(std::move(blobId), std::move(message));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
string MemoryBlobPersistor::StoreMessage(vector<uint8_t> &&message) noexcept {
|
|
252
|
+
// substr(1, 36) strips curly braces from a GUID.
|
|
253
|
+
auto blobId = winrt::to_string(winrt::to_hstring(GuidHelper::CreateNewGuid())).substr(1, 36);
|
|
254
|
+
|
|
255
|
+
scoped_lock lock{m_mutex};
|
|
256
|
+
m_blobs.insert_or_assign(blobId, std::move(message));
|
|
257
|
+
|
|
258
|
+
return blobId;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
#pragma endregion IBlobPersistor
|
|
262
|
+
|
|
263
|
+
#pragma endregion MemoryBlobPersistor
|
|
264
|
+
|
|
265
|
+
#pragma region BlobWebSocketModuleContentHandler
|
|
266
|
+
|
|
267
|
+
BlobWebSocketModuleContentHandler::BlobWebSocketModuleContentHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
|
|
268
|
+
: m_blobPersistor{blobPersistor} {}
|
|
269
|
+
|
|
270
|
+
#pragma region IWebSocketModuleContentHandler
|
|
271
|
+
|
|
272
|
+
void BlobWebSocketModuleContentHandler::ProcessMessage(string &&message, dynamic ¶ms) /*override*/ {
|
|
273
|
+
params[dataKey] = std::move(message);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
void BlobWebSocketModuleContentHandler::ProcessMessage(vector<uint8_t> &&message, dynamic ¶ms) /*override*/ {
|
|
277
|
+
auto blob = dynamic::object();
|
|
278
|
+
blob(offsetKey, 0);
|
|
279
|
+
blob(sizeKey, message.size());
|
|
280
|
+
blob(blobIdKey, m_blobPersistor->StoreMessage(std::move(message)));
|
|
281
|
+
|
|
282
|
+
params[dataKey] = std::move(blob);
|
|
283
|
+
params[typeKey] = blobKey;
|
|
284
|
+
}
|
|
285
|
+
#pragma endregion IWebSocketModuleContentHandler
|
|
286
|
+
|
|
287
|
+
void BlobWebSocketModuleContentHandler::Register(int64_t socketID) noexcept {
|
|
288
|
+
scoped_lock lock{m_mutex};
|
|
289
|
+
m_socketIds.insert(socketID);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
void BlobWebSocketModuleContentHandler::Unregister(int64_t socketID) noexcept {
|
|
293
|
+
scoped_lock lock{m_mutex};
|
|
294
|
+
|
|
295
|
+
auto itr = m_socketIds.find(socketID);
|
|
296
|
+
if (itr != m_socketIds.end())
|
|
297
|
+
m_socketIds.erase(itr);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#pragma endregion BlobWebSocketModuleContentHandler
|
|
301
|
+
|
|
302
|
+
#pragma region BlobModuleRequestBodyHandler
|
|
303
|
+
|
|
304
|
+
BlobModuleRequestBodyHandler::BlobModuleRequestBodyHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
|
|
305
|
+
: m_blobPersistor{blobPersistor} {}
|
|
306
|
+
|
|
307
|
+
#pragma region IRequestBodyHandler
|
|
308
|
+
|
|
309
|
+
bool BlobModuleRequestBodyHandler::Supports(dynamic &data) /*override*/ {
|
|
310
|
+
auto itr = data.find(blobKey);
|
|
311
|
+
|
|
312
|
+
return itr != data.items().end() && !(*itr).second.empty();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
dynamic BlobModuleRequestBodyHandler::ToRequestBody(dynamic &data, string &contentType) /*override*/ {
|
|
316
|
+
auto type = contentType;
|
|
317
|
+
if (!data[typeKey].isNull() && !data[typeKey].asString().empty()) {
|
|
318
|
+
type = data[typeKey].asString();
|
|
319
|
+
}
|
|
320
|
+
if (type.empty()) {
|
|
321
|
+
type = "application/octet-stream";
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
auto blob = data[blobKey];
|
|
325
|
+
auto blobId = blob[blobIdKey].asString();
|
|
326
|
+
auto bytes = m_blobPersistor->ResolveMessage(std::move(blobId), blob[offsetKey].asInt(), blob[sizeKey].asInt());
|
|
327
|
+
|
|
328
|
+
auto result = dynamic::object();
|
|
329
|
+
result(typeKey, type);
|
|
330
|
+
result(sizeKey, bytes.size());
|
|
331
|
+
result("bytes", dynamic(bytes.cbegin(), bytes.cend()));
|
|
332
|
+
|
|
333
|
+
return result;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
#pragma endregion IRequestBodyHandler
|
|
337
|
+
|
|
338
|
+
#pragma endregion BlobModuleRequestBodyHandler
|
|
339
|
+
|
|
340
|
+
#pragma region BlobModuleResponseHandler
|
|
341
|
+
|
|
342
|
+
BlobModuleResponseHandler::BlobModuleResponseHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
|
|
343
|
+
: m_blobPersistor{blobPersistor} {}
|
|
344
|
+
|
|
345
|
+
#pragma region IResponseHandler
|
|
346
|
+
|
|
347
|
+
bool BlobModuleResponseHandler::Supports(string &responseType) /*override*/ {
|
|
348
|
+
return blobKey == responseType;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
dynamic BlobModuleResponseHandler::ToResponseData(vector<uint8_t> &&content) /*override*/ {
|
|
352
|
+
auto blob = dynamic::object();
|
|
353
|
+
blob(offsetKey, 0);
|
|
354
|
+
blob(sizeKey, content.size());
|
|
355
|
+
blob(blobIdKey, m_blobPersistor->StoreMessage(std::move(content)));
|
|
356
|
+
|
|
357
|
+
return blob;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
#pragma endregion IResponseHandler
|
|
361
|
+
|
|
362
|
+
#pragma endregion BlobModuleResponseHandler
|
|
363
|
+
|
|
364
|
+
/*extern*/ const char *GetBlobModuleName() noexcept {
|
|
365
|
+
return moduleName;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateBlobModule(
|
|
369
|
+
IInspectable const &inspectableProperties) noexcept {
|
|
370
|
+
if (auto properties = inspectableProperties.try_as<IReactPropertyBag>())
|
|
371
|
+
return std::make_unique<BlobModule>(properties);
|
|
372
|
+
|
|
373
|
+
return nullptr;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
} // namespace Microsoft::React
|