react-native-windows 0.0.0-canary.672 → 0.0.0-canary.673

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.
@@ -24,6 +24,15 @@
24
24
  "Microsoft.SourceLink.Common": "1.0.0"
25
25
  }
26
26
  },
27
+ "NETStandard.Library": {
28
+ "type": "Direct",
29
+ "requested": "[2.0.3, )",
30
+ "resolved": "2.0.3",
31
+ "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
32
+ "dependencies": {
33
+ "Microsoft.NETCore.Platforms": "1.1.0"
34
+ }
35
+ },
27
36
  "Microsoft.Build.Tasks.Git": {
28
37
  "type": "Transitive",
29
38
  "resolved": "1.0.0",
@@ -53,21 +62,13 @@
53
62
  "Microsoft.NETCore.Platforms": {
54
63
  "type": "Transitive",
55
64
  "resolved": "2.1.0",
56
- "contentHash": "GmkKfoyerqmsHMn7OZj0AKpcBabD+GaafqphvX2Mw406IwiJRy1pKcKqdCfKJfYmkRyJ6+e+RaUylgdJoDa1jQ=="
65
+ "contentHash": "ok+RPAtESz/9MUXeIEz6Lv5XAGQsaNmEYXMsgVALj4D7kqC8gveKWXWXbufLySR2fWrwZf8smyN5RmHu0e4BHA=="
57
66
  },
58
67
  "Microsoft.SourceLink.Common": {
59
68
  "type": "Transitive",
60
69
  "resolved": "1.0.0",
61
70
  "contentHash": "G8DuQY8/DK5NN+3jm5wcMcd9QYD90UV7MiLmdljSJixi3U/vNaeBKmmXUqI4DJCOeWizIUEh4ALhSt58mR+5eg=="
62
71
  },
63
- "NETStandard.Library": {
64
- "type": "Transitive",
65
- "resolved": "2.0.3",
66
- "contentHash": "548M6mnBSJWxsIlkQHfbzoYxpiYFXZZSL00p4GHYv8PkiqFBnnT68mW5mGEsA/ch9fDO9GkPgkFQpWiXZN7mAQ==",
67
- "dependencies": {
68
- "Microsoft.NETCore.Platforms": "1.1.0"
69
- }
70
- },
71
72
  "runtime.win10-arm.Microsoft.Net.Native.Compiler": {
72
73
  "type": "Transitive",
73
74
  "resolved": "2.2.7-rel-27913-00",
@@ -10,11 +10,11 @@
10
10
  -->
11
11
  <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
12
12
  <PropertyGroup>
13
- <ReactNativeWindowsVersion>0.0.0-canary.672</ReactNativeWindowsVersion>
13
+ <ReactNativeWindowsVersion>0.0.0-canary.673</ReactNativeWindowsVersion>
14
14
  <ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
15
15
  <ReactNativeWindowsMinor>0</ReactNativeWindowsMinor>
16
16
  <ReactNativeWindowsPatch>0</ReactNativeWindowsPatch>
17
17
  <ReactNativeWindowsCanary>true</ReactNativeWindowsCanary>
18
- <ReactNativeWindowsCommitId>11b038f411acd9f1eb37a371830132f06eae3267</ReactNativeWindowsCommitId>
18
+ <ReactNativeWindowsCommitId>1a52d0a11b43fda3a8a72dac3b6e03349a77c01d</ReactNativeWindowsCommitId>
19
19
  </PropertyGroup>
20
20
  </Project>
@@ -3,7 +3,7 @@
3
3
 
4
4
  #pragma once
5
5
 
6
- #include <Modules/IBlobPersistor.h>
6
+ #include "IBlobPersistor.h"
7
7
 
8
8
  // Standard Library
9
9
  #include <functional>
@@ -4,210 +4,139 @@
4
4
  #include "BlobModule.h"
5
5
 
6
6
  #include <Modules/CxxModuleUtilities.h>
7
- #include <Modules/IHttpModuleProxy.h>
8
- #include <Modules/IWebSocketModuleProxy.h>
9
- #include <ReactPropertyBag.h>
10
- #include <unicode.h>
11
7
 
12
8
  // React Native
13
9
  #include <cxxreact/JsArgumentHelpers.h>
14
10
 
15
- // Boost Libraries
16
- #include <boost/uuid/uuid_io.hpp>
17
-
18
- // Windows API
19
- #include <winrt/Windows.Foundation.h>
20
- #include <winrt/Windows.Security.Cryptography.h>
21
-
22
- // Standard Library
23
- #include <chrono>
24
- #include <filesystem>
25
- #include <fstream>
26
-
27
11
  using namespace facebook::xplat;
28
12
 
29
13
  using folly::dynamic;
30
- using std::scoped_lock;
31
- using std::shared_ptr;
14
+ using Microsoft::React::Networking::IBlobResource;
32
15
  using std::string;
33
16
  using std::vector;
34
- using std::weak_ptr;
35
- using winrt::Microsoft::ReactNative::IReactPropertyBag;
36
- using winrt::Microsoft::ReactNative::ReactNonAbiValue;
37
- using winrt::Microsoft::ReactNative::ReactPropertyBag;
38
- using winrt::Microsoft::ReactNative::ReactPropertyId;
39
17
  using winrt::Windows::Foundation::IInspectable;
40
- using winrt::Windows::Foundation::Uri;
41
- using winrt::Windows::Security::Cryptography::CryptographicBuffer;
42
18
 
43
- namespace fs = std::filesystem;
44
19
  namespace msrn = winrt::Microsoft::ReactNative;
45
20
 
46
21
  namespace {
47
- constexpr char moduleName[] = "BlobModule";
48
- constexpr char blobKey[] = "blob";
49
- constexpr char blobIdKey[] = "blobId";
50
- constexpr char offsetKey[] = "offset";
51
- constexpr char sizeKey[] = "size";
52
- constexpr char typeKey[] = "type";
53
- constexpr char dataKey[] = "data";
22
+ constexpr char s_moduleName[] = "BlobModule";
23
+
24
+ const auto &blobKeys = IBlobResource::FieldNames();
54
25
  } // namespace
55
26
 
56
27
  namespace Microsoft::React {
57
28
 
58
- #pragma region BlobModule
29
+ #pragma region BlobTurboModule
59
30
 
60
- BlobModule::BlobModule(winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept
61
- : m_sharedState{std::make_shared<SharedState>()},
62
- m_blobPersistor{std::make_shared<MemoryBlobPersistor>()},
63
- m_contentHandler{std::make_shared<BlobWebSocketModuleContentHandler>(m_blobPersistor)},
64
- m_requestBodyHandler{std::make_shared<BlobModuleRequestBodyHandler>(m_blobPersistor)},
65
- m_responseHandler{std::make_shared<BlobModuleResponseHandler>(m_blobPersistor)},
66
- m_inspectableProperties{inspectableProperties} {
67
- auto propBag = ReactPropertyBag{m_inspectableProperties.try_as<IReactPropertyBag>()};
68
-
69
- auto contentHandlerPropId =
70
- ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleContentHandler>>>{L"BlobModule.ContentHandler"};
71
- auto contentHandler = weak_ptr<IWebSocketModuleContentHandler>{m_contentHandler};
72
- propBag.Set(contentHandlerPropId, std::move(contentHandler));
73
-
74
- auto blobPersistorPropId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IBlobPersistor>>>{L"Blob.Persistor"};
75
- auto blobPersistor = weak_ptr<IBlobPersistor>{m_blobPersistor};
76
- propBag.Set(blobPersistorPropId, std::move(blobPersistor));
77
-
78
- m_sharedState->Module = this;
31
+ void BlobTurboModule::Initialize(msrn::ReactContext const &reactContext) noexcept {
32
+ m_resource = IBlobResource::Make(reactContext.Properties().Handle());
33
+ m_resource->Callbacks().OnError = [&reactContext](string &&errorText) {
34
+ Modules::SendEvent(reactContext, L"blobFailed", {errorText});
35
+ };
36
+ }
37
+
38
+ ReactNativeSpecs::BlobModuleSpec_Constants BlobTurboModule::GetConstants() noexcept {
39
+ ReactNativeSpecs::BlobModuleSpec_Constants result;
40
+ result.BLOB_URI_SCHEME = blobKeys.Blob;
41
+ result.BLOB_URI_HOST = {};
42
+
43
+ return result;
44
+ }
45
+
46
+ void BlobTurboModule::AddNetworkingHandler() noexcept {
47
+ m_resource->AddNetworkingHandler();
79
48
  }
80
49
 
81
- BlobModule::~BlobModule() noexcept /*override*/ {
82
- m_sharedState->Module = nullptr;
50
+ void BlobTurboModule::AddWebSocketHandler(double id) noexcept {
51
+ m_resource->AddWebSocketHandler(static_cast<int64_t>(id));
83
52
  }
84
53
 
54
+ void BlobTurboModule::RemoveWebSocketHandler(double id) noexcept {
55
+ m_resource->RemoveWebSocketHandler(static_cast<int64_t>(id));
56
+ }
57
+
58
+ void BlobTurboModule::SendOverSocket(msrn::JSValue &&blob, double socketID) noexcept {
59
+ m_resource->SendOverSocket(
60
+ blob[blobKeys.BlobId].AsString(),
61
+ blob[blobKeys.Offset].AsInt64(),
62
+ blob[blobKeys.Size].AsInt64(),
63
+ static_cast<int64_t>(socketID));
64
+ }
65
+
66
+ void BlobTurboModule::CreateFromParts(vector<msrn::JSValue> &&parts, string &&withId) noexcept {
67
+ m_resource->CreateFromParts(std::move(parts), std::move(withId));
68
+ }
69
+
70
+ void BlobTurboModule::Release(string &&blobId) noexcept {
71
+ m_resource->Release(std::move(blobId));
72
+ }
73
+
74
+ #pragma endregion BlobTurboModule
75
+
76
+ #pragma region BlobModule
77
+
78
+ BlobModule::BlobModule(winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept
79
+ : m_resource{IBlobResource::Make(inspectableProperties)} {}
80
+
85
81
  #pragma region CxxModule
86
82
 
87
83
  string BlobModule::getName() {
88
- return moduleName;
84
+ return s_moduleName;
89
85
  }
90
86
 
91
87
  std::map<string, dynamic> BlobModule::getConstants() {
92
- return {{"BLOB_URI_SCHEME", blobKey}, {"BLOB_URI_HOST", {}}};
88
+ return {{"BLOB_URI_SCHEME", blobKeys.Blob}, {"BLOB_URI_HOST", {}}};
93
89
  }
94
90
 
95
91
  vector<module::CxxModule::Method> BlobModule::getMethods() {
92
+ // See CxxNativeModule::lazyInit()
93
+ m_resource->Callbacks().OnError = [weakInstance = getInstance()](string &&errorText) {
94
+ Modules::SendEvent(weakInstance, "blobFailed", std::move(errorText));
95
+ };
96
+
96
97
  return {
97
- {"addNetworkingHandler",
98
- [propBag = ReactPropertyBag{m_inspectableProperties.try_as<IReactPropertyBag>()},
99
- requestBodyHandler = m_requestBodyHandler,
100
- responseHandler = m_responseHandler](dynamic args) {
101
- auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IHttpModuleProxy>>>{L"HttpModule.Proxy"};
102
-
103
- if (auto prop = propBag.Get(propId)) {
104
- if (auto httpHandler = prop.Value().lock()) {
105
- httpHandler->AddRequestBodyHandler(requestBodyHandler);
106
- httpHandler->AddResponseHandler(responseHandler);
107
- }
108
- }
109
- // TODO: else emit error?
110
- }},
98
+ {"addNetworkingHandler", [resource = m_resource](dynamic /*args*/) { resource->AddNetworkingHandler(); }},
111
99
 
112
100
  {"addWebSocketHandler",
113
- [contentHandler = m_contentHandler](dynamic args) {
101
+ [resource = m_resource](dynamic args) {
114
102
  auto id = jsArgAsInt(args, 0);
115
103
 
116
- contentHandler->Register(id);
104
+ resource->AddWebSocketHandler(id);
117
105
  }},
118
106
 
119
107
  {"removeWebSocketHandler",
120
- [contentHandler = m_contentHandler](dynamic args) {
108
+ [resource = m_resource](dynamic args) {
121
109
  auto id = jsArgAsInt(args, 0);
122
110
 
123
- contentHandler->Unregister(id);
111
+ resource->RemoveWebSocketHandler(id);
124
112
  }},
125
113
 
126
114
  {"sendOverSocket",
127
- [weakState = weak_ptr<SharedState>(m_sharedState),
128
- persistor = m_blobPersistor,
129
- propBag = ReactPropertyBag{m_inspectableProperties.try_as<IReactPropertyBag>()}](dynamic args) {
130
- auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleProxy>>>{L"WebSocketModule.Proxy"};
131
- shared_ptr<IWebSocketModuleProxy> wsProxy;
132
- if (auto prop = propBag.Get(propId)) {
133
- wsProxy = prop.Value().lock();
134
- }
135
- if (!wsProxy) {
136
- return;
137
- }
138
-
115
+ [resource = m_resource](dynamic args) {
139
116
  auto blob = jsArgAsObject(args, 0);
140
- auto blobId = blob[blobIdKey].getString();
141
- auto offset = blob[offsetKey].getInt();
142
- auto size = blob[sizeKey].getInt();
143
- auto socketID = jsArgAsInt(args, 1);
144
-
145
- winrt::array_view<uint8_t const> data;
146
- try {
147
- data = persistor->ResolveMessage(std::move(blobId), offset, size);
148
- } catch (const std::exception &e) {
149
- if (auto sharedState = weakState.lock()) {
150
- Modules::SendEvent(sharedState->Module->getInstance(), "blobFailed", e.what());
151
- }
152
- return;
153
- }
154
-
155
- auto buffer = CryptographicBuffer::CreateFromByteArray(data);
156
- auto winrtString = CryptographicBuffer::EncodeToBase64String(std::move(buffer));
157
- auto base64String = Common::Unicode::Utf16ToUtf8(std::move(winrtString));
158
-
159
- wsProxy->SendBinary(std::move(base64String), socketID);
117
+ auto blobId = blob[blobKeys.BlobId].getString();
118
+ auto offset = blob[blobKeys.Offset].getInt();
119
+ auto size = blob[blobKeys.Size].getInt();
120
+ auto socketId = jsArgAsInt(args, 1);
121
+
122
+ resource->SendOverSocket(std::move(blobId), offset, size, socketId);
160
123
  }},
161
124
 
162
125
  {"createFromParts",
163
- // As of React Native 0.67, instance is set AFTER CxxModule::getMethods() is invoked.
164
- // Use getInstance() directly once
165
- // https://github.com/facebook/react-native/commit/1d45b20b6c6ba66df0485cdb9be36463d96cf182 becomes available.
166
- [persistor = m_blobPersistor, weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) {
167
- auto parts = jsArgAsArray(args, 0); // Array<Object>
126
+ [resource = m_resource](dynamic args) {
127
+ auto dynamicParts = jsArgAsArray(args, 0); // Array<Object>
128
+ auto parts = Modules::ToJSValue(dynamicParts);
168
129
  auto blobId = jsArgAsString(args, 1);
169
- vector<uint8_t> buffer{};
170
-
171
- for (const auto &part : parts) {
172
- auto type = part[typeKey].asString();
173
- if (blobKey == type) {
174
- auto blob = part[dataKey];
175
- winrt::array_view<uint8_t const> bufferPart;
176
- try {
177
- bufferPart = persistor->ResolveMessage(
178
- blob[blobIdKey].asString(), blob[offsetKey].asInt(), blob[sizeKey].asInt());
179
- } catch (const std::exception &e) {
180
- if (auto sharedState = weakState.lock()) {
181
- Modules::SendEvent(sharedState->Module->getInstance(), "blobFailed", e.what());
182
- }
183
- return;
184
- }
185
-
186
- buffer.reserve(buffer.size() + bufferPart.size());
187
- buffer.insert(buffer.end(), bufferPart.begin(), bufferPart.end());
188
- } else if ("string" == type) {
189
- auto data = part[dataKey].asString();
190
-
191
- buffer.reserve(buffer.size() + data.size());
192
- buffer.insert(buffer.end(), data.begin(), data.end());
193
- } else {
194
- if (auto state = weakState.lock()) {
195
- auto message = "Invalid type for blob: " + type;
196
- Modules::SendEvent(state->Module->getInstance(), "blobFailed", std::move(message));
197
- }
198
- return;
199
- }
200
- }
201
-
202
- persistor->StoreMessage(std::move(buffer), std::move(blobId));
130
+
131
+ resource->CreateFromParts(parts.MoveArray(), std::move(blobId));
203
132
  }},
204
133
 
205
134
  {"release",
206
- [persistor = m_blobPersistor](dynamic args) // blobId: string
135
+ [resource = m_resource](dynamic args) // blobId: string
207
136
  {
208
137
  auto blobId = jsArgAsString(args, 0);
209
138
 
210
- persistor->RemoveMessage(std::move(blobId));
139
+ resource->Release(std::move(blobId));
211
140
  }}};
212
141
  }
213
142
 
@@ -215,173 +144,13 @@ vector<module::CxxModule::Method> BlobModule::getMethods() {
215
144
 
216
145
  #pragma endregion BlobModule
217
146
 
218
- #pragma region MemoryBlobPersistor
219
-
220
- #pragma region IBlobPersistor
221
-
222
- winrt::array_view<uint8_t const> MemoryBlobPersistor::ResolveMessage(string &&blobId, int64_t offset, int64_t size) {
223
- if (size < 1)
224
- return {};
225
-
226
- scoped_lock lock{m_mutex};
227
-
228
- auto dataItr = m_blobs.find(std::move(blobId));
229
- // Not found.
230
- if (dataItr == m_blobs.cend())
231
- throw std::invalid_argument("Blob object not found");
232
-
233
- auto &bytes = (*dataItr).second;
234
- auto endBound = static_cast<size_t>(offset + size);
235
- // Out of bounds.
236
- if (endBound > bytes.size() || offset >= static_cast<int64_t>(bytes.size()) || offset < 0)
237
- throw std::out_of_range("Offset or size out of range");
238
-
239
- return winrt::array_view<uint8_t const>(bytes.data() + offset, bytes.data() + endBound);
240
- }
241
-
242
- void MemoryBlobPersistor::RemoveMessage(string &&blobId) noexcept {
243
- scoped_lock lock{m_mutex};
244
-
245
- m_blobs.erase(std::move(blobId));
246
- }
247
-
248
- void MemoryBlobPersistor::StoreMessage(vector<uint8_t> &&message, string &&blobId) noexcept {
249
- scoped_lock lock{m_mutex};
250
-
251
- m_blobs.insert_or_assign(std::move(blobId), std::move(message));
252
- }
253
-
254
- string MemoryBlobPersistor::StoreMessage(vector<uint8_t> &&message) noexcept {
255
- auto blobId = boost::uuids::to_string(m_guidGenerator());
256
-
257
- scoped_lock lock{m_mutex};
258
- m_blobs.insert_or_assign(blobId, std::move(message));
259
-
260
- return blobId;
261
- }
262
-
263
- #pragma endregion IBlobPersistor
264
-
265
- #pragma endregion MemoryBlobPersistor
266
-
267
- #pragma region BlobWebSocketModuleContentHandler
268
-
269
- BlobWebSocketModuleContentHandler::BlobWebSocketModuleContentHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
270
- : m_blobPersistor{blobPersistor} {}
271
-
272
- #pragma region IWebSocketModuleContentHandler
273
-
274
- void BlobWebSocketModuleContentHandler::ProcessMessage(string &&message, dynamic &params) /*override*/ {
275
- params[dataKey] = std::move(message);
276
- }
277
-
278
- void BlobWebSocketModuleContentHandler::ProcessMessage(vector<uint8_t> &&message, dynamic &params) /*override*/ {
279
- auto blob = dynamic::object();
280
- blob(offsetKey, 0);
281
- blob(sizeKey, message.size());
282
- blob(blobIdKey, m_blobPersistor->StoreMessage(std::move(message)));
283
-
284
- params[dataKey] = std::move(blob);
285
- params[typeKey] = blobKey;
286
- }
287
-
288
- void BlobWebSocketModuleContentHandler::ProcessMessage(
289
- string &&message,
290
- msrn::JSValueObject &params) noexcept /*override*/
291
- {
292
- params[dataKey] = std::move(message);
293
- }
294
-
295
- void BlobWebSocketModuleContentHandler::ProcessMessage(
296
- vector<uint8_t> &&message,
297
- msrn::JSValueObject &params) noexcept /*override*/
298
- {
299
- auto blob = msrn::JSValueObject{
300
- {offsetKey, 0}, {sizeKey, message.size()}, {blobIdKey, m_blobPersistor->StoreMessage(std::move(message))}};
301
-
302
- params[dataKey] = std::move(blob);
303
- params[typeKey] = blobKey;
304
- }
305
-
306
- #pragma endregion IWebSocketModuleContentHandler
307
-
308
- void BlobWebSocketModuleContentHandler::Register(int64_t socketID) noexcept {
309
- scoped_lock lock{m_mutex};
310
- m_socketIds.insert(socketID);
311
- }
312
-
313
- void BlobWebSocketModuleContentHandler::Unregister(int64_t socketID) noexcept {
314
- scoped_lock lock{m_mutex};
315
-
316
- auto itr = m_socketIds.find(socketID);
317
- if (itr != m_socketIds.end())
318
- m_socketIds.erase(itr);
319
- }
320
-
321
- #pragma endregion BlobWebSocketModuleContentHandler
322
-
323
- #pragma region BlobModuleRequestBodyHandler
324
-
325
- BlobModuleRequestBodyHandler::BlobModuleRequestBodyHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
326
- : m_blobPersistor{blobPersistor} {}
327
-
328
- #pragma region IRequestBodyHandler
329
-
330
- bool BlobModuleRequestBodyHandler::Supports(msrn::JSValueObject &data) /*override*/ {
331
- auto itr = data.find(blobKey);
332
-
333
- return itr != data.cend() && !(*itr).second.AsString().empty();
334
- }
335
-
336
- msrn::JSValueObject BlobModuleRequestBodyHandler::ToRequestBody(
337
- msrn::JSValueObject &data,
338
- string &contentType) /*override*/ {
339
- auto type = contentType;
340
- auto itr = data.find(typeKey);
341
- if (itr != data.cend() && !(*itr).second.AsString().empty()) {
342
- type = (*itr).second.AsString();
343
- }
344
- if (type.empty()) {
345
- type = "application/octet-stream";
346
- }
347
-
348
- auto &blob = data[blobKey].AsObject();
349
- auto blobId = blob[blobIdKey].AsString();
350
- auto bytes = m_blobPersistor->ResolveMessage(std::move(blobId), blob[offsetKey].AsInt64(), blob[sizeKey].AsInt64());
351
-
352
- return {{typeKey, type}, {sizeKey, bytes.size()}, {"bytes", msrn::JSValueArray(bytes.cbegin(), bytes.cend())}};
353
- }
354
-
355
- #pragma endregion IRequestBodyHandler
356
-
357
- #pragma endregion BlobModuleRequestBodyHandler
358
-
359
- #pragma region BlobModuleResponseHandler
360
-
361
- BlobModuleResponseHandler::BlobModuleResponseHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
362
- : m_blobPersistor{blobPersistor} {}
363
-
364
- #pragma region IResponseHandler
365
-
366
- bool BlobModuleResponseHandler::Supports(string &responseType) /*override*/ {
367
- return blobKey == responseType;
368
- }
369
-
370
- msrn::JSValueObject BlobModuleResponseHandler::ToResponseData(vector<uint8_t> &&content) /*override*/ {
371
- return {{offsetKey, 0}, {sizeKey, content.size()}, {blobIdKey, m_blobPersistor->StoreMessage(std::move(content))}};
372
- }
373
-
374
- #pragma endregion IResponseHandler
375
-
376
- #pragma endregion BlobModuleResponseHandler
377
-
378
147
  /*extern*/ const char *GetBlobModuleName() noexcept {
379
- return moduleName;
148
+ return s_moduleName;
380
149
  }
381
150
 
382
151
  /*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateBlobModule(
383
152
  IInspectable const &inspectableProperties) noexcept {
384
- if (auto properties = inspectableProperties.try_as<IReactPropertyBag>())
153
+ if (auto properties = inspectableProperties.try_as<msrn::IReactPropertyBag>())
385
154
  return std::make_unique<BlobModule>(properties);
386
155
 
387
156
  return nullptr;
@@ -3,114 +3,56 @@
3
3
 
4
4
  #pragma once
5
5
 
6
- #include <Modules/IBlobPersistor.h>
7
- #include <Modules/IRequestBodyHandler.h>
8
- #include <Modules/IResponseHandler.h>
9
- #include <Modules/IWebSocketModuleContentHandler.h>
6
+ #include <NativeBlobModuleSpec.g.h>
7
+
8
+ #include <Networking/IBlobResource.h>
10
9
 
11
10
  // React Native
12
11
  #include <cxxreact/CxxModule.h>
13
12
 
14
- // Boost Libraries
15
- #include <boost/uuid/uuid_generators.hpp>
16
-
17
13
  // Windows API
18
14
  #include <winrt/base.h>
19
15
 
20
16
  // Standard Library
21
- #include <mutex>
22
17
  #include <string>
23
- #include <unordered_map>
24
- #include <unordered_set>
25
18
  #include <vector>
26
19
 
27
20
  namespace Microsoft::React {
28
21
 
29
- class MemoryBlobPersistor final : public IBlobPersistor {
30
- std::unordered_map<std::string, std::vector<uint8_t>> m_blobs;
31
- std::mutex m_mutex;
32
- boost::uuids::random_generator m_guidGenerator;
33
-
34
- public:
35
- #pragma region IBlobPersistor
36
-
37
- winrt::array_view<uint8_t const> ResolveMessage(std::string &&blobId, int64_t offset, int64_t size) override;
22
+ REACT_MODULE(BlobTurboModule, L"BlobModule")
23
+ struct BlobTurboModule {
24
+ using ModuleSpec = ReactNativeSpecs::BlobModuleSpec;
38
25
 
39
- void RemoveMessage(std::string &&blobId) noexcept override;
26
+ REACT_INIT(Initialize)
27
+ void Initialize(winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept;
40
28
 
41
- void StoreMessage(std::vector<uint8_t> &&message, std::string &&blobId) noexcept override;
29
+ REACT_GET_CONSTANTS(GetConstants)
30
+ ReactNativeSpecs::BlobModuleSpec_Constants GetConstants() noexcept;
42
31
 
43
- std::string StoreMessage(std::vector<uint8_t> &&message) noexcept override;
44
-
45
- #pragma endregion IBlobPersistor
46
- };
47
-
48
- class BlobWebSocketModuleContentHandler final : public IWebSocketModuleContentHandler {
49
- std::unordered_set<int64_t> m_socketIds;
50
- std::mutex m_mutex;
51
- std::shared_ptr<IBlobPersistor> m_blobPersistor;
52
-
53
- public:
54
- BlobWebSocketModuleContentHandler(std::shared_ptr<IBlobPersistor> blobPersistor) noexcept;
32
+ REACT_METHOD(AddNetworkingHandler, L"addNetworkingHandler")
33
+ void AddNetworkingHandler() noexcept;
55
34
 
56
- #pragma region IWebSocketModuleContentHandler
35
+ REACT_METHOD(AddWebSocketHandler, L"addWebSocketHandler")
36
+ void AddWebSocketHandler(double id) noexcept;
57
37
 
58
- void ProcessMessage(std::string &&message, folly::dynamic &params) override;
38
+ REACT_METHOD(RemoveWebSocketHandler, L"removeWebSocketHandler")
39
+ void RemoveWebSocketHandler(double id) noexcept;
59
40
 
60
- void ProcessMessage(std::vector<uint8_t> &&message, folly::dynamic &params) override;
61
-
62
- void ProcessMessage(std::string &&message, winrt::Microsoft::ReactNative::JSValueObject &params) noexcept override;
63
-
64
- void ProcessMessage(std::vector<uint8_t> &&message, winrt::Microsoft::ReactNative::JSValueObject &params) noexcept
65
- override;
66
-
67
- #pragma endregion IWebSocketModuleContentHandler
68
-
69
- void Register(int64_t socketID) noexcept;
70
-
71
- void Unregister(int64_t socketID) noexcept;
72
- };
73
-
74
- class BlobModuleRequestBodyHandler final : public IRequestBodyHandler {
75
- std::shared_ptr<IBlobPersistor> m_blobPersistor;
76
-
77
- public:
78
- BlobModuleRequestBodyHandler(std::shared_ptr<IBlobPersistor> blobPersistor) noexcept;
41
+ REACT_METHOD(SendOverSocket, L"sendOverSocket")
42
+ void SendOverSocket(winrt::Microsoft::ReactNative::JSValue &&blob, double socketID) noexcept;
79
43
 
80
- #pragma region IRequestBodyHandler
44
+ REACT_METHOD(CreateFromParts, L"createFromParts")
45
+ void CreateFromParts(std::vector<winrt::Microsoft::ReactNative::JSValue> &&parts, std::string &&withId) noexcept;
81
46
 
82
- bool Supports(winrt::Microsoft::ReactNative::JSValueObject &data) override;
47
+ REACT_METHOD(Release, L"release")
48
+ void Release(std::string &&blobId) noexcept;
83
49
 
84
- winrt::Microsoft::ReactNative::JSValueObject ToRequestBody(
85
- winrt::Microsoft::ReactNative::JSValueObject &data,
86
- std::string &contentType) override;
87
-
88
- #pragma endregion IRequestBodyHandler
89
- };
90
-
91
- class BlobModuleResponseHandler final : public IResponseHandler {
92
- std::shared_ptr<IBlobPersistor> m_blobPersistor;
93
-
94
- public:
95
- BlobModuleResponseHandler(std::shared_ptr<IBlobPersistor> blobPersistor) noexcept;
96
-
97
- #pragma region IResponseHandler
98
-
99
- bool Supports(std::string &responseType) override;
100
-
101
- winrt::Microsoft::ReactNative::JSValueObject ToResponseData(std::vector<uint8_t> &&content) override;
102
-
103
- #pragma endregion IResponseHandler
50
+ private:
51
+ std::shared_ptr<Networking::IBlobResource> m_resource;
104
52
  };
105
53
 
106
54
  class BlobModule : public facebook::xplat::module::CxxModule {
107
- std::shared_ptr<MemoryBlobPersistor> m_blobPersistor;
108
- std::shared_ptr<BlobWebSocketModuleContentHandler> m_contentHandler;
109
- std::shared_ptr<BlobModuleRequestBodyHandler> m_requestBodyHandler;
110
- std::shared_ptr<BlobModuleResponseHandler> m_responseHandler;
111
-
112
- // Property bag high level reference.
113
- winrt::Windows::Foundation::IInspectable m_inspectableProperties;
55
+ std::shared_ptr<Networking::IBlobResource> m_resource;
114
56
 
115
57
  public:
116
58
  enum class MethodId {
@@ -125,15 +67,6 @@ class BlobModule : public facebook::xplat::module::CxxModule {
125
67
 
126
68
  BlobModule(winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept;
127
69
 
128
- ~BlobModule() noexcept override;
129
-
130
- struct SharedState {
131
- /// <summary>
132
- /// Keeps a raw reference to the module object to lazily retrieve the React Instance as needed.
133
- /// </summary>
134
- CxxModule *Module{nullptr};
135
- };
136
-
137
70
  #pragma region CxxModule
138
71
 
139
72
  /// <summary>
@@ -153,12 +86,6 @@ class BlobModule : public facebook::xplat::module::CxxModule {
153
86
  std::vector<Method> getMethods() override;
154
87
 
155
88
  #pragma endregion CxxModule
156
-
157
- private:
158
- /// <summary>
159
- /// Keeps members that can be accessed threads other than this module's owner accessible.
160
- /// </summary>
161
- std::shared_ptr<SharedState> m_sharedState;
162
89
  };
163
90
 
164
91
  } // namespace Microsoft::React
@@ -3,9 +3,6 @@
3
3
 
4
4
  #pragma once
5
5
 
6
- // React Native
7
- #include <folly/dynamic.h>
8
-
9
6
  // React Native Windows
10
7
  #include <JSValue.h>
11
8
 
@@ -21,10 +18,6 @@ namespace Microsoft::React {
21
18
  struct IWebSocketModuleContentHandler {
22
19
  virtual ~IWebSocketModuleContentHandler() noexcept {}
23
20
 
24
- virtual void ProcessMessage(std::string &&message, folly::dynamic &params) = 0;
25
-
26
- virtual void ProcessMessage(std::vector<uint8_t> &&message, folly::dynamic &params) = 0;
27
-
28
21
  virtual void ProcessMessage(std::string &&message, winrt::Microsoft::ReactNative::JSValueObject &params) noexcept = 0;
29
22
 
30
23
  virtual void ProcessMessage(
@@ -112,7 +112,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
112
112
  if (!strongInstance)
113
113
  return;
114
114
 
115
- dynamic args = dynamic::object("id", id)("type", isBinary ? "binary" : "text");
115
+ auto args = msrn::JSValueObject{{"id", id}, {"type", isBinary ? "binary" : "text"}};
116
116
  shared_ptr<Microsoft::React::IWebSocketModuleContentHandler> contentHandler;
117
117
  auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<Microsoft::React::IWebSocketModuleContentHandler>>>{
118
118
  L"BlobModule.ContentHandler"};
@@ -134,7 +134,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
134
134
  args["data"] = message;
135
135
  }
136
136
 
137
- SendEvent(weakInstance, "websocketMessage", std::move(args));
137
+ SendEvent(weakInstance, "websocketMessage", Microsoft::React::Modules::ToDynamic(std::move(args)));
138
138
  });
139
139
  ws->SetOnClose([id, weakInstance](IWebSocketResource::CloseCode code, const string &reason) {
140
140
  auto strongInstance = weakInstance.lock();
@@ -0,0 +1,323 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #include "DefaultBlobResource.h"
5
+
6
+ #include <Modules/IHttpModuleProxy.h>
7
+ #include <Modules/IWebSocketModuleProxy.h>
8
+
9
+ // Boost Libraries
10
+ #include <boost/uuid/uuid_io.hpp>
11
+
12
+ // Windows API
13
+ #include <winrt/Windows.Security.Cryptography.h>
14
+
15
+ using std::scoped_lock;
16
+ using std::shared_ptr;
17
+ using std::string;
18
+ using std::vector;
19
+ using std::weak_ptr;
20
+ using winrt::array_view;
21
+ using winrt::Windows::Security::Cryptography::CryptographicBuffer;
22
+
23
+ namespace msrn = winrt::Microsoft::ReactNative;
24
+
25
+ namespace {
26
+
27
+ constexpr Microsoft::React::Networking::IBlobResource::BlobFieldNames
28
+ blobKeys{"blob", "blobId", "offset", "size", "type", "data"};
29
+
30
+ } // namespace
31
+
32
+ namespace Microsoft::React::Networking {
33
+
34
+ #pragma region DefaultBlobResource
35
+
36
+ DefaultBlobResource::DefaultBlobResource(
37
+ shared_ptr<MemoryBlobPersistor> blobPersistor,
38
+ shared_ptr<BlobWebSocketModuleContentHandler> contentHandler,
39
+ shared_ptr<BlobModuleRequestBodyHandler> requestBodyHandler,
40
+ shared_ptr<BlobModuleResponseHandler> responseHandler,
41
+ msrn::ReactPropertyBag propertyBag)
42
+ : m_blobPersistor{blobPersistor},
43
+ m_contentHandler{contentHandler},
44
+ m_requestBodyHandler{requestBodyHandler},
45
+ m_responseHandler{responseHandler},
46
+ m_propertyBag{propertyBag} {}
47
+
48
+ #pragma region IBlobResource
49
+
50
+ /*static*/ const IBlobResource::BlobFieldNames &IBlobResource::FieldNames() noexcept {
51
+ return blobKeys;
52
+ }
53
+
54
+ /*static*/ shared_ptr<IBlobResource> IBlobResource::Make(
55
+ winrt::Windows::Foundation::IInspectable const &inspectableProperties) {
56
+ using namespace msrn;
57
+
58
+ auto propBag = ReactPropertyBag{inspectableProperties.try_as<IReactPropertyBag>()};
59
+
60
+ auto blobPersistor = std::make_shared<MemoryBlobPersistor>();
61
+ auto contentHandler = std::make_shared<BlobWebSocketModuleContentHandler>(blobPersistor);
62
+ auto requestBodyHanlder = std::make_shared<BlobModuleRequestBodyHandler>(blobPersistor);
63
+ auto responseHandler = std::make_shared<BlobModuleResponseHandler>(blobPersistor);
64
+
65
+ auto contentHandlerPropId =
66
+ ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleContentHandler>>>{L"BlobModule.ContentHandler"};
67
+ propBag.Set(contentHandlerPropId, weak_ptr<IWebSocketModuleContentHandler>{contentHandler});
68
+
69
+ auto blobPersistorPropId = ReactPropertyId<ReactNonAbiValue<weak_ptr<IBlobPersistor>>>{L"Blob.Persistor"};
70
+ ;
71
+ propBag.Set(blobPersistorPropId, weak_ptr<IBlobPersistor>{blobPersistor});
72
+
73
+ auto result = std::make_shared<DefaultBlobResource>(
74
+ blobPersistor, contentHandler, requestBodyHanlder, responseHandler, propBag);
75
+
76
+ return result;
77
+ }
78
+
79
+ void DefaultBlobResource::SendOverSocket(string &&blobId, int64_t offset, int64_t size, int64_t socketId) noexcept
80
+ /*override*/ {
81
+ auto propId =
82
+ msrn::ReactPropertyId<msrn::ReactNonAbiValue<weak_ptr<IWebSocketModuleProxy>>>{L"WebSocketModule.Proxy"};
83
+ shared_ptr<IWebSocketModuleProxy> wsProxy;
84
+ if (auto prop = m_propertyBag.Get(propId)) {
85
+ wsProxy = prop.Value().lock();
86
+ }
87
+ if (!wsProxy) {
88
+ return;
89
+ }
90
+
91
+ array_view<uint8_t const> data;
92
+ try {
93
+ data = m_blobPersistor->ResolveMessage(std::move(blobId), offset, size);
94
+ } catch (const std::exception &e) {
95
+ return m_callbacks.OnError(e.what());
96
+ }
97
+
98
+ auto buffer = CryptographicBuffer::CreateFromByteArray(data);
99
+ auto base64Hstring = CryptographicBuffer::EncodeToBase64String(std::move(buffer));
100
+ auto base64String = winrt::to_string(base64Hstring);
101
+
102
+ wsProxy->SendBinary(std::move(base64String), socketId);
103
+ }
104
+
105
+ void DefaultBlobResource::CreateFromParts(msrn::JSValueArray &&parts, string &&blobId) noexcept /*override*/ {
106
+ vector<uint8_t> buffer{};
107
+
108
+ for (const auto &partItem : parts) {
109
+ auto &part = partItem.AsObject();
110
+ auto type = part.at(blobKeys.Type).AsString();
111
+ if (blobKeys.Blob == type) {
112
+ auto &blob = part.at(blobKeys.Data).AsObject();
113
+ array_view<uint8_t const> bufferPart;
114
+ try {
115
+ bufferPart = m_blobPersistor->ResolveMessage(
116
+ blob.at(blobKeys.BlobId).AsString(), blob.at(blobKeys.Offset).AsInt64(), blob.at(blobKeys.Size).AsInt64());
117
+ } catch (const std::exception &e) {
118
+ return m_callbacks.OnError(e.what());
119
+ }
120
+
121
+ buffer.reserve(buffer.size() + bufferPart.size());
122
+ buffer.insert(buffer.end(), bufferPart.begin(), bufferPart.end());
123
+ } else if ("string" == type) {
124
+ auto data = part.at(blobKeys.Data).AsString();
125
+
126
+ buffer.reserve(buffer.size() + data.size());
127
+ buffer.insert(buffer.end(), data.begin(), data.end());
128
+ } else {
129
+ return m_callbacks.OnError("Invalid type for blob: " + type);
130
+ }
131
+ }
132
+
133
+ m_blobPersistor->StoreMessage(std::move(buffer), std::move(blobId));
134
+ }
135
+
136
+ void DefaultBlobResource::Release(string &&blobId) noexcept /*override*/ {
137
+ m_blobPersistor->RemoveMessage(std::move(blobId));
138
+ }
139
+
140
+ void DefaultBlobResource::AddNetworkingHandler() noexcept /*override*/ {
141
+ auto propId = msrn::ReactPropertyId<msrn::ReactNonAbiValue<weak_ptr<IHttpModuleProxy>>>{L"HttpModule.Proxy"};
142
+
143
+ if (auto prop = m_propertyBag.Get(propId)) {
144
+ if (auto httpHandler = prop.Value().lock()) {
145
+ httpHandler->AddRequestBodyHandler(m_requestBodyHandler);
146
+ httpHandler->AddResponseHandler(m_responseHandler);
147
+ }
148
+ }
149
+ // TODO: else emit error?
150
+ }
151
+
152
+ void DefaultBlobResource::AddWebSocketHandler(int64_t id) noexcept /*override*/ {
153
+ m_contentHandler->Register(id);
154
+ }
155
+
156
+ void DefaultBlobResource::RemoveWebSocketHandler(int64_t id) noexcept /*override*/ {
157
+ m_contentHandler->Unregister(id);
158
+ }
159
+
160
+ IBlobResource::BlobCallbacks &DefaultBlobResource::Callbacks() noexcept /*override*/ {
161
+ return m_callbacks;
162
+ }
163
+
164
+ #pragma endregion IBlobResource
165
+
166
+ #pragma endregion DefaultBlobResource
167
+
168
+ #pragma region MemoryBlobPersistor
169
+
170
+ #pragma region IBlobPersistor
171
+
172
+ array_view<uint8_t const> MemoryBlobPersistor::ResolveMessage(string &&blobId, int64_t offset, int64_t size) {
173
+ if (size < 1)
174
+ return {};
175
+
176
+ scoped_lock lock{m_mutex};
177
+
178
+ auto dataItr = m_blobs.find(std::move(blobId));
179
+ // Not found.
180
+ if (dataItr == m_blobs.cend())
181
+ throw std::invalid_argument("Blob object not found");
182
+
183
+ auto &bytes = (*dataItr).second;
184
+ auto endBound = static_cast<size_t>(offset + size);
185
+ // Out of bounds.
186
+ if (endBound > bytes.size() || offset >= static_cast<int64_t>(bytes.size()) || offset < 0)
187
+ throw std::out_of_range("Offset or size out of range");
188
+
189
+ return array_view<uint8_t const>(bytes.data() + offset, bytes.data() + endBound);
190
+ }
191
+
192
+ void MemoryBlobPersistor::RemoveMessage(string &&blobId) noexcept {
193
+ scoped_lock lock{m_mutex};
194
+
195
+ m_blobs.erase(std::move(blobId));
196
+ }
197
+
198
+ void MemoryBlobPersistor::StoreMessage(vector<uint8_t> &&message, string &&blobId) noexcept {
199
+ scoped_lock lock{m_mutex};
200
+
201
+ m_blobs.insert_or_assign(std::move(blobId), std::move(message));
202
+ }
203
+
204
+ string MemoryBlobPersistor::StoreMessage(vector<uint8_t> &&message) noexcept {
205
+ auto blobId = boost::uuids::to_string(m_guidGenerator());
206
+
207
+ scoped_lock lock{m_mutex};
208
+ m_blobs.insert_or_assign(blobId, std::move(message));
209
+
210
+ return blobId;
211
+ }
212
+
213
+ #pragma endregion IBlobPersistor
214
+
215
+ #pragma endregion MemoryBlobPersistor
216
+
217
+ #pragma region BlobWebSocketModuleContentHandler
218
+
219
+ BlobWebSocketModuleContentHandler::BlobWebSocketModuleContentHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
220
+ : m_blobPersistor{blobPersistor} {}
221
+
222
+ #pragma region IWebSocketModuleContentHandler
223
+
224
+ void BlobWebSocketModuleContentHandler::ProcessMessage(
225
+ string &&message,
226
+ msrn::JSValueObject &params) noexcept /*override*/
227
+ {
228
+ params[blobKeys.Data] = std::move(message);
229
+ }
230
+
231
+ void BlobWebSocketModuleContentHandler::ProcessMessage(
232
+ vector<uint8_t> &&message,
233
+ msrn::JSValueObject &params) noexcept /*override*/
234
+ {
235
+ auto blob = msrn::JSValueObject{
236
+ {blobKeys.Offset, 0},
237
+ {blobKeys.Size, message.size()},
238
+ {blobKeys.BlobId, m_blobPersistor->StoreMessage(std::move(message))}};
239
+
240
+ params[blobKeys.Data] = std::move(blob);
241
+ params[blobKeys.Type] = blobKeys.Blob;
242
+ }
243
+
244
+ #pragma endregion IWebSocketModuleContentHandler
245
+
246
+ void BlobWebSocketModuleContentHandler::Register(int64_t socketID) noexcept {
247
+ scoped_lock lock{m_mutex};
248
+ m_socketIds.insert(socketID);
249
+ }
250
+
251
+ void BlobWebSocketModuleContentHandler::Unregister(int64_t socketID) noexcept {
252
+ scoped_lock lock{m_mutex};
253
+
254
+ auto itr = m_socketIds.find(socketID);
255
+ if (itr != m_socketIds.end())
256
+ m_socketIds.erase(itr);
257
+ }
258
+
259
+ #pragma endregion BlobWebSocketModuleContentHandler
260
+
261
+ #pragma region BlobModuleRequestBodyHandler
262
+
263
+ BlobModuleRequestBodyHandler::BlobModuleRequestBodyHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
264
+ : m_blobPersistor{blobPersistor} {}
265
+
266
+ #pragma region IRequestBodyHandler
267
+
268
+ bool BlobModuleRequestBodyHandler::Supports(msrn::JSValueObject &data) /*override*/ {
269
+ auto itr = data.find(blobKeys.Blob);
270
+
271
+ return itr != data.cend() && !(*itr).second.AsString().empty();
272
+ }
273
+
274
+ msrn::JSValueObject BlobModuleRequestBodyHandler::ToRequestBody(
275
+ msrn::JSValueObject &data,
276
+ string &contentType) /*override*/ {
277
+ auto type = contentType;
278
+ auto itr = data.find(blobKeys.Type);
279
+ if (itr != data.cend() && !(*itr).second.AsString().empty()) {
280
+ type = (*itr).second.AsString();
281
+ }
282
+ if (type.empty()) {
283
+ type = "application/octet-stream";
284
+ }
285
+
286
+ auto &blob = data[blobKeys.Blob].AsObject();
287
+ auto blobId = blob[blobKeys.BlobId].AsString();
288
+ auto bytes = m_blobPersistor->ResolveMessage(
289
+ std::move(blobId), blob[blobKeys.Offset].AsInt64(), blob[blobKeys.Size].AsInt64());
290
+
291
+ return {
292
+ {blobKeys.Type, type},
293
+ {blobKeys.Size, bytes.size()},
294
+ {"bytes", msrn::JSValueArray(bytes.cbegin(), bytes.cend())}};
295
+ }
296
+
297
+ #pragma endregion IRequestBodyHandler
298
+
299
+ #pragma endregion BlobModuleRequestBodyHandler
300
+
301
+ #pragma region BlobModuleResponseHandler
302
+
303
+ BlobModuleResponseHandler::BlobModuleResponseHandler(shared_ptr<IBlobPersistor> blobPersistor) noexcept
304
+ : m_blobPersistor{blobPersistor} {}
305
+
306
+ #pragma region IResponseHandler
307
+
308
+ bool BlobModuleResponseHandler::Supports(string &responseType) /*override*/ {
309
+ return blobKeys.Blob == responseType;
310
+ }
311
+
312
+ msrn::JSValueObject BlobModuleResponseHandler::ToResponseData(vector<uint8_t> &&content) /*override*/ {
313
+ return {
314
+ {blobKeys.Offset, 0},
315
+ {blobKeys.Size, content.size()},
316
+ {blobKeys.BlobId, m_blobPersistor->StoreMessage(std::move(content))}};
317
+ }
318
+
319
+ #pragma endregion IResponseHandler
320
+
321
+ #pragma endregion BlobModuleResponseHandler
322
+
323
+ } // namespace Microsoft::React::Networking
@@ -0,0 +1,133 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #include "IBlobResource.h"
7
+
8
+ #include <IBlobPersistor.h>
9
+ #include <Modules/IRequestBodyHandler.h>
10
+ #include <Modules/IResponseHandler.h>
11
+ #include <Modules/IWebSocketModuleContentHandler.h>
12
+
13
+ // React Native Windows
14
+ #include <ReactPropertyBag.h>
15
+
16
+ // Boost Libraries
17
+ #include <boost/uuid/uuid_generators.hpp>
18
+
19
+ // Standard Library
20
+ #include <mutex>
21
+ #include <unordered_set>
22
+
23
+ namespace Microsoft::React::Networking {
24
+
25
+ class MemoryBlobPersistor final : public IBlobPersistor {
26
+ std::unordered_map<std::string, std::vector<uint8_t>> m_blobs;
27
+ std::mutex m_mutex;
28
+ boost::uuids::random_generator m_guidGenerator;
29
+
30
+ public:
31
+ #pragma region IBlobPersistor
32
+
33
+ winrt::array_view<uint8_t const> ResolveMessage(std::string &&blobId, int64_t offset, int64_t size) override;
34
+
35
+ void RemoveMessage(std::string &&blobId) noexcept override;
36
+
37
+ void StoreMessage(std::vector<uint8_t> &&message, std::string &&blobId) noexcept override;
38
+
39
+ std::string StoreMessage(std::vector<uint8_t> &&message) noexcept override;
40
+
41
+ #pragma endregion IBlobPersistor
42
+ };
43
+
44
+ class BlobWebSocketModuleContentHandler final : public IWebSocketModuleContentHandler {
45
+ std::unordered_set<int64_t> m_socketIds;
46
+ std::mutex m_mutex;
47
+ std::shared_ptr<IBlobPersistor> m_blobPersistor;
48
+
49
+ public:
50
+ BlobWebSocketModuleContentHandler(std::shared_ptr<IBlobPersistor> blobPersistor) noexcept;
51
+
52
+ #pragma region IWebSocketModuleContentHandler
53
+
54
+ void ProcessMessage(std::string &&message, winrt::Microsoft::ReactNative::JSValueObject &params) noexcept override;
55
+
56
+ void ProcessMessage(std::vector<uint8_t> &&message, winrt::Microsoft::ReactNative::JSValueObject &params) noexcept
57
+ override;
58
+
59
+ #pragma endregion IWebSocketModuleContentHandler
60
+
61
+ void Register(int64_t socketID) noexcept;
62
+
63
+ void Unregister(int64_t socketID) noexcept;
64
+ };
65
+
66
+ class BlobModuleRequestBodyHandler final : public IRequestBodyHandler {
67
+ std::shared_ptr<IBlobPersistor> m_blobPersistor;
68
+
69
+ public:
70
+ BlobModuleRequestBodyHandler(std::shared_ptr<IBlobPersistor> blobPersistor) noexcept;
71
+
72
+ #pragma region IRequestBodyHandler
73
+
74
+ bool Supports(winrt::Microsoft::ReactNative::JSValueObject &data) override;
75
+
76
+ winrt::Microsoft::ReactNative::JSValueObject ToRequestBody(
77
+ winrt::Microsoft::ReactNative::JSValueObject &data,
78
+ std::string &contentType) override;
79
+
80
+ #pragma endregion IRequestBodyHandler
81
+ };
82
+
83
+ class BlobModuleResponseHandler final : public IResponseHandler {
84
+ std::shared_ptr<IBlobPersistor> m_blobPersistor;
85
+
86
+ public:
87
+ BlobModuleResponseHandler(std::shared_ptr<IBlobPersistor> blobPersistor) noexcept;
88
+
89
+ #pragma region IResponseHandler
90
+
91
+ bool Supports(std::string &responseType) override;
92
+
93
+ winrt::Microsoft::ReactNative::JSValueObject ToResponseData(std::vector<uint8_t> &&content) override;
94
+
95
+ #pragma endregion IResponseHandler
96
+ };
97
+
98
+ class DefaultBlobResource : public IBlobResource, public std::enable_shared_from_this<DefaultBlobResource> {
99
+ std::shared_ptr<MemoryBlobPersistor> m_blobPersistor;
100
+ std::shared_ptr<BlobWebSocketModuleContentHandler> m_contentHandler;
101
+ std::shared_ptr<BlobModuleRequestBodyHandler> m_requestBodyHandler;
102
+ std::shared_ptr<BlobModuleResponseHandler> m_responseHandler;
103
+ winrt::Microsoft::ReactNative::ReactPropertyBag m_propertyBag;
104
+ BlobCallbacks m_callbacks;
105
+
106
+ public:
107
+ DefaultBlobResource(
108
+ std::shared_ptr<MemoryBlobPersistor> blobPersistor,
109
+ std::shared_ptr<BlobWebSocketModuleContentHandler> contentHandler,
110
+ std::shared_ptr<BlobModuleRequestBodyHandler> requestBodyHandler,
111
+ std::shared_ptr<BlobModuleResponseHandler> responseHandler,
112
+ winrt::Microsoft::ReactNative::ReactPropertyBag propertyBag);
113
+
114
+ #pragma region IBlobResource
115
+
116
+ void SendOverSocket(std::string &&blobId, int64_t offset, int64_t size, int64_t socketId) noexcept override;
117
+
118
+ void CreateFromParts(winrt::Microsoft::ReactNative::JSValueArray &&parts, std::string &&blobId) noexcept override;
119
+
120
+ void Release(std::string &&blobId) noexcept override;
121
+
122
+ void AddNetworkingHandler() noexcept override;
123
+
124
+ void AddWebSocketHandler(int64_t id) noexcept override;
125
+
126
+ void RemoveWebSocketHandler(int64_t id) noexcept override;
127
+
128
+ BlobCallbacks &Callbacks() noexcept override;
129
+
130
+ #pragma endregion IBlobResource
131
+ };
132
+
133
+ } // namespace Microsoft::React::Networking
@@ -0,0 +1,56 @@
1
+ // Copyright (c) Microsoft Corporation.
2
+ // Licensed under the MIT License.
3
+
4
+ #pragma once
5
+
6
+ #include <IBlobPersistor.h>
7
+
8
+ // React Native Windows
9
+ #include <JSValue.h>
10
+
11
+ // Windows API
12
+ #include <winrt/Windows.Foundation.h>
13
+
14
+ // Standard Library
15
+ #include <functional>
16
+ #include <memory>
17
+ #include <string>
18
+
19
+ namespace Microsoft::React::Networking {
20
+
21
+ struct IBlobResource {
22
+ struct BlobCallbacks {
23
+ std::function<void(std::string &&errorText)> OnError;
24
+ };
25
+
26
+ struct BlobFieldNames {
27
+ const char *Blob;
28
+ const char *BlobId;
29
+ const char *Offset;
30
+ const char *Size;
31
+ const char *Type;
32
+ const char *Data;
33
+ };
34
+
35
+ static std::shared_ptr<IBlobResource> Make(winrt::Windows::Foundation::IInspectable const &inspectableProperties);
36
+
37
+ static const BlobFieldNames &FieldNames() noexcept;
38
+
39
+ virtual ~IBlobResource() noexcept {}
40
+
41
+ virtual void SendOverSocket(std::string &&blobId, int64_t offset, int64_t size, int64_t socketId) noexcept = 0;
42
+
43
+ virtual void CreateFromParts(winrt::Microsoft::ReactNative::JSValueArray &&parts, std::string &&blobId) noexcept = 0;
44
+
45
+ virtual void Release(std::string &&blobId) noexcept = 0;
46
+
47
+ virtual void AddNetworkingHandler() noexcept = 0;
48
+
49
+ virtual void AddWebSocketHandler(int64_t id) noexcept = 0;
50
+
51
+ virtual void RemoveWebSocketHandler(int64_t id) noexcept = 0;
52
+
53
+ virtual BlobCallbacks &Callbacks() noexcept = 0;
54
+ };
55
+
56
+ } // namespace Microsoft::React::Networking
@@ -199,6 +199,7 @@
199
199
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\SourceCodeModule.cpp" />
200
200
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\StatusBarManagerModule.cpp" />
201
201
  <ClCompile Include="$(MSBuildThisFileDirectory)Modules\WebSocketModule.cpp" />
202
+ <ClCompile Include="$(MSBuildThisFileDirectory)Networking\DefaultBlobResource.cpp" />
202
203
  <ClCompile Include="$(MSBuildThisFileDirectory)Networking\OriginPolicyHttpFilter.cpp" />
203
204
  <ClCompile Include="$(MSBuildThisFileDirectory)Networking\RedirectHttpFilter.cpp" />
204
205
  <ClCompile Include="$(MSBuildThisFileDirectory)Networking\WinRTHttpResource.cpp" />
@@ -307,6 +308,7 @@
307
308
  <ClInclude Include="$(MSBuildThisFileDirectory)BaseFileReaderResource.h" />
308
309
  <ClInclude Include="$(MSBuildThisFileDirectory)CppRuntimeOptions.h" />
309
310
  <ClInclude Include="$(MSBuildThisFileDirectory)HermesSamplingProfiler.h" />
311
+ <ClInclude Include="$(MSBuildThisFileDirectory)IBlobPersistor.h" />
310
312
  <ClInclude Include="$(MSBuildThisFileDirectory)IFileReaderResource.h" />
311
313
  <ClInclude Include="$(MSBuildThisFileDirectory)JSI\ByteArrayBuffer.h" />
312
314
  <ClInclude Include="$(MSBuildThisFileDirectory)JSI\ChakraApi.h" />
@@ -319,7 +321,6 @@
319
321
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\BlobModule.h" />
320
322
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\CxxModuleUtilities.h" />
321
323
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\FileReaderModule.h" />
322
- <ClInclude Include="$(MSBuildThisFileDirectory)Modules\IBlobPersistor.h" />
323
324
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\IHttpModuleProxy.h" />
324
325
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\IRequestBodyHandler.h" />
325
326
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\IResponseHandler.h" />
@@ -329,6 +330,8 @@
329
330
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\HttpModule.h" />
330
331
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\NetworkingModule.h" />
331
332
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\WebSocketTurboModule.h" />
333
+ <ClInclude Include="$(MSBuildThisFileDirectory)Networking\DefaultBlobResource.h" />
334
+ <ClInclude Include="$(MSBuildThisFileDirectory)Networking\IBlobResource.h" />
332
335
  <ClInclude Include="$(MSBuildThisFileDirectory)Networking\IHttpResource.h" />
333
336
  <ClInclude Include="$(MSBuildThisFileDirectory)Networking\IRedirectEventSource.h" />
334
337
  <ClInclude Include="$(MSBuildThisFileDirectory)Networking\IWebSocketResource.h" />
@@ -271,6 +271,9 @@
271
271
  <ClCompile Include="$(MSBuildThisFileDirectory)JSI\V8RuntimeHolder.cpp" />
272
272
  <ClCompile Include="$(MSBuildThisFileDirectory)SafeLoadLibrary.cpp" />
273
273
  <ClCompile Include="$(MSBuildThisFileDirectory)Hasher.cpp" />
274
+ <ClCompile Include="$(MSBuildThisFileDirectory)Networking\DefaultBlobResource.cpp">
275
+ <Filter>Source Files\Networking</Filter>
276
+ </ClCompile>
274
277
  </ItemGroup>
275
278
  <ItemGroup>
276
279
  <Filter Include="Source Files">
@@ -597,9 +600,6 @@
597
600
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\IResponseHandler.h">
598
601
  <Filter>Header Files\Modules</Filter>
599
602
  </ClInclude>
600
- <ClInclude Include="$(MSBuildThisFileDirectory)Modules\IBlobPersistor.h">
601
- <Filter>Header Files\Modules</Filter>
602
- </ClInclude>
603
603
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\CxxModuleUtilities.h">
604
604
  <Filter>Header Files\Modules</Filter>
605
605
  </ClInclude>
@@ -738,6 +738,15 @@
738
738
  <ClInclude Include="$(MSBuildThisFileDirectory)Modules\WebSocketTurboModule.h">
739
739
  <Filter>Header Files\Modules</Filter>
740
740
  </ClInclude>
741
+ <ClInclude Include="$(MSBuildThisFileDirectory)Networking\IBlobResource.h">
742
+ <Filter>Header Files\Networking</Filter>
743
+ </ClInclude>
744
+ <ClInclude Include="$(MSBuildThisFileDirectory)Networking\DefaultBlobResource.h">
745
+ <Filter>Header Files\Networking</Filter>
746
+ </ClInclude>
747
+ <ClInclude Include="$(MSBuildThisFileDirectory)IBlobPersistor.h">
748
+ <Filter>Header Files</Filter>
749
+ </ClInclude>
741
750
  </ItemGroup>
742
751
  <ItemGroup>
743
752
  <None Include="$(MSBuildThisFileDirectory)tracing\rnw.wprp">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-windows",
3
- "version": "0.0.0-canary.672",
3
+ "version": "0.0.0-canary.673",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -26,7 +26,7 @@
26
26
  "@react-native-community/cli": "12.0.0-alpha.3",
27
27
  "@react-native-community/cli-platform-android": "12.0.0-alpha.3",
28
28
  "@react-native-community/cli-platform-ios": "12.0.0-alpha.3",
29
- "@react-native-windows/cli": "0.0.0-canary.175",
29
+ "@react-native-windows/cli": "0.0.0-canary.176",
30
30
  "@react-native/assets": "1.0.0",
31
31
  "@react-native/assets-registry": "0.73.0-nightly-20230606-396cdac62",
32
32
  "@react-native/codegen": "0.73.0-nightly-20230615-2ae163a7e",
@@ -62,7 +62,7 @@
62
62
  "yargs": "^17.6.2"
63
63
  },
64
64
  "devDependencies": {
65
- "@react-native-windows/codegen": "0.0.0-canary.62",
65
+ "@react-native-windows/codegen": "0.0.0-canary.63",
66
66
  "@rnw-scripts/babel-react-native-config": "0.0.0",
67
67
  "@rnw-scripts/eslint-config": "1.2.1",
68
68
  "@rnw-scripts/jest-out-of-tree-snapshot-resolver": "^1.1.4",