react-native-windows 0.72.0 → 0.72.2
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/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Network/RCTNetworking.windows.js +10 -16
- package/Microsoft.ReactNative/Fabric/ImageRequest.cpp +11 -14
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +1 -1
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -3
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -7
- package/Microsoft.ReactNative/Modules/LinkingManagerModule.cpp +1 -1
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +11 -10
- package/Microsoft.ReactNative.Managed/packages.lock.json +2 -71
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/React.Cpp.props +2 -3
- package/Shared/BaseFileReaderResource.cpp +95 -0
- package/Shared/BaseFileReaderResource.h +41 -0
- package/Shared/CreateModules.h +27 -5
- package/Shared/IFileReaderResource.h +36 -0
- package/Shared/Modules/BlobModule.cpp +93 -297
- package/Shared/Modules/BlobModule.h +25 -87
- package/Shared/Modules/CxxModuleUtilities.cpp +32 -0
- package/Shared/Modules/CxxModuleUtilities.h +17 -0
- package/Shared/Modules/FileReaderModule.cpp +118 -51
- package/Shared/Modules/FileReaderModule.h +27 -1
- package/Shared/Modules/HttpModule.cpp +133 -9
- package/Shared/Modules/HttpModule.h +33 -0
- package/Shared/Modules/IRequestBodyHandler.h +6 -4
- package/Shared/Modules/IResponseHandler.h +3 -3
- package/Shared/Modules/IUriHandler.h +3 -3
- package/Shared/Modules/IWebSocketModuleContentHandler.h +6 -4
- package/Shared/Modules/WebSocketModule.cpp +190 -7
- package/Shared/Modules/WebSocketTurboModule.h +52 -0
- package/Shared/Networking/DefaultBlobResource.cpp +323 -0
- package/Shared/Networking/DefaultBlobResource.h +133 -0
- package/Shared/Networking/IBlobResource.h +56 -0
- package/Shared/Networking/IHttpResource.h +6 -5
- package/Shared/Networking/WinRTHttpResource.cpp +40 -32
- package/Shared/Networking/WinRTHttpResource.h +4 -3
- package/Shared/Networking/WinRTTypes.h +3 -3
- package/Shared/Shared.vcxitems +8 -1
- package/Shared/Shared.vcxitems.filters +24 -3
- package/package.json +11 -11
- package/types/experimental.d.ts +101 -0
- package/types/index.d.ts +216 -0
- package/types/modules/BatchedBridge.d.ts +32 -0
- package/types/modules/Codegen.d.ts +74 -0
- package/types/modules/Devtools.d.ts +31 -0
- package/types/modules/LaunchScreen.d.ts +18 -0
- package/types/modules/globals.d.ts +579 -0
- package/types/private/TimerMixin.d.ts +19 -0
- package/types/private/Utilities.d.ts +10 -0
- package/types/public/DeprecatedPropertiesAlias.d.ts +185 -0
- package/types/public/Insets.d.ts +15 -0
- package/types/public/ReactNativeRenderer.d.ts +144 -0
- package/types/public/ReactNativeTypes.d.ts +143 -0
- package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +0 -44
- package/Microsoft.ReactNative/Base/CoreNativeModules.h +0 -30
- /package/Shared/{Modules/IBlobPersistor.h → IBlobPersistor.h} +0 -0
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
#include "pch.h"
|
|
5
5
|
|
|
6
6
|
#include <Modules/WebSocketModule.h>
|
|
7
|
+
#include <Modules/WebSocketTurboModule.h>
|
|
7
8
|
|
|
9
|
+
#include <CreateModules.h>
|
|
8
10
|
#include <Modules/CxxModuleUtilities.h>
|
|
9
11
|
#include <Modules/IWebSocketModuleContentHandler.h>
|
|
10
12
|
#include <ReactPropertyBag.h>
|
|
11
13
|
|
|
14
|
+
// fmt
|
|
15
|
+
#include <fmt/format.h>
|
|
16
|
+
|
|
12
17
|
// React Native
|
|
13
18
|
#include <cxxreact/Instance.h>
|
|
14
19
|
#include <cxxreact/JsArgumentHelpers.h>
|
|
@@ -19,6 +24,8 @@
|
|
|
19
24
|
// Standard Libriary
|
|
20
25
|
#include <iomanip>
|
|
21
26
|
|
|
27
|
+
namespace msrn = winrt::Microsoft::ReactNative;
|
|
28
|
+
|
|
22
29
|
using namespace facebook::xplat;
|
|
23
30
|
|
|
24
31
|
using facebook::react::Instance;
|
|
@@ -26,6 +33,7 @@ using folly::dynamic;
|
|
|
26
33
|
|
|
27
34
|
using std::shared_ptr;
|
|
28
35
|
using std::string;
|
|
36
|
+
using std::vector;
|
|
29
37
|
using std::weak_ptr;
|
|
30
38
|
|
|
31
39
|
using winrt::Microsoft::ReactNative::IReactPropertyBag;
|
|
@@ -42,7 +50,10 @@ using Microsoft::React::WebSocketModule;
|
|
|
42
50
|
using Microsoft::React::Modules::SendEvent;
|
|
43
51
|
using Microsoft::React::Networking::IWebSocketResource;
|
|
44
52
|
|
|
45
|
-
constexpr char
|
|
53
|
+
constexpr char s_moduleName[] = "WebSocketModule";
|
|
54
|
+
constexpr wchar_t s_moduleNameW[] = L"WebSocketModule";
|
|
55
|
+
|
|
56
|
+
msrn::ReactModuleProvider s_moduleProvider = msrn::MakeTurboModuleProvider<Microsoft::React::WebSocketTurboModule>();
|
|
46
57
|
|
|
47
58
|
static shared_ptr<IWebSocketResource>
|
|
48
59
|
GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedState> weakState) {
|
|
@@ -105,7 +116,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
|
|
|
105
116
|
if (!strongInstance)
|
|
106
117
|
return;
|
|
107
118
|
|
|
108
|
-
|
|
119
|
+
auto args = msrn::JSValueObject{{"id", id}, {"type", isBinary ? "binary" : "text"}};
|
|
109
120
|
shared_ptr<Microsoft::React::IWebSocketModuleContentHandler> contentHandler;
|
|
110
121
|
auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<Microsoft::React::IWebSocketModuleContentHandler>>>{
|
|
111
122
|
L"BlobModule.ContentHandler"};
|
|
@@ -117,7 +128,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
|
|
|
117
128
|
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(message));
|
|
118
129
|
winrt::com_array<uint8_t> arr;
|
|
119
130
|
CryptographicBuffer::CopyToByteArray(buffer, arr);
|
|
120
|
-
auto data =
|
|
131
|
+
auto data = vector<uint8_t>(arr.begin(), arr.end());
|
|
121
132
|
|
|
122
133
|
contentHandler->ProcessMessage(std::move(data), args);
|
|
123
134
|
} else {
|
|
@@ -127,7 +138,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
|
|
|
127
138
|
args["data"] = message;
|
|
128
139
|
}
|
|
129
140
|
|
|
130
|
-
SendEvent(weakInstance, "websocketMessage", std::move(args));
|
|
141
|
+
SendEvent(weakInstance, "websocketMessage", Microsoft::React::Modules::ToDynamic(std::move(args)));
|
|
131
142
|
});
|
|
132
143
|
ws->SetOnClose([id, weakInstance](IWebSocketResource::CloseCode code, const string &reason) {
|
|
133
144
|
auto strongInstance = weakInstance.lock();
|
|
@@ -179,7 +190,7 @@ void WebSocketModule::SetResourceFactory(
|
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
string WebSocketModule::getName() {
|
|
182
|
-
return
|
|
193
|
+
return s_moduleName;
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
std::map<string, dynamic> WebSocketModule::getConstants() {
|
|
@@ -187,7 +198,7 @@ std::map<string, dynamic> WebSocketModule::getConstants() {
|
|
|
187
198
|
}
|
|
188
199
|
|
|
189
200
|
// clang-format off
|
|
190
|
-
|
|
201
|
+
vector<facebook::xplat::module::CxxModule::Method> WebSocketModule::getMethods()
|
|
191
202
|
{
|
|
192
203
|
return
|
|
193
204
|
{
|
|
@@ -312,8 +323,172 @@ void WebSocketModuleProxy::SendBinary(std::string &&base64String, int64_t id) no
|
|
|
312
323
|
|
|
313
324
|
#pragma endregion WebSocketModuleProxy
|
|
314
325
|
|
|
326
|
+
#pragma region WebSocketTurboModule
|
|
327
|
+
|
|
328
|
+
shared_ptr<IWebSocketResource> WebSocketTurboModule::CreateResource(int64_t id, string &&url) noexcept {
|
|
329
|
+
shared_ptr<IWebSocketResource> rc;
|
|
330
|
+
try {
|
|
331
|
+
rc = IWebSocketResource::Make();
|
|
332
|
+
} catch (const winrt::hresult_error &e) {
|
|
333
|
+
auto error = fmt::format("[0x{:0>8x}] {}", static_cast<uint32_t>(e.code()), winrt::to_string(e.message()));
|
|
334
|
+
SendEvent(m_context, L"webSocketFailed", {{"id", id}, {"message", std::move(error)}});
|
|
335
|
+
|
|
336
|
+
return nullptr;
|
|
337
|
+
} catch (const std::exception &e) {
|
|
338
|
+
SendEvent(m_context, L"webSocketFailed", {{"id", id}, {"message", e.what()}});
|
|
339
|
+
|
|
340
|
+
return nullptr;
|
|
341
|
+
} catch (...) {
|
|
342
|
+
SendEvent(
|
|
343
|
+
m_context, L"webSocketFailed", {{"id", id}, {"message", "Unidentified error creating IWebSocketResource"}});
|
|
344
|
+
|
|
345
|
+
return nullptr;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Set up resource
|
|
349
|
+
rc->SetOnConnect([id, context = m_context]() {
|
|
350
|
+
SendEvent(context, L"websocketOpen", msrn::JSValueObject{{"id", id}});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
rc->SetOnMessage([id, context = m_context](size_t length, const string &message, bool isBinary) {
|
|
354
|
+
auto args = msrn::JSValueObject{{"id", id}, {"type", isBinary ? "binary" : "text"}};
|
|
355
|
+
shared_ptr<IWebSocketModuleContentHandler> contentHandler;
|
|
356
|
+
auto propId =
|
|
357
|
+
ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleContentHandler>>>{L"BlobModule.ContentHandler"};
|
|
358
|
+
auto propBag = context.Properties();
|
|
359
|
+
if (auto prop = propBag.Get(propId))
|
|
360
|
+
contentHandler = prop.Value().lock();
|
|
361
|
+
|
|
362
|
+
if (contentHandler) {
|
|
363
|
+
if (isBinary) {
|
|
364
|
+
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(message));
|
|
365
|
+
winrt::com_array<uint8_t> arr;
|
|
366
|
+
CryptographicBuffer::CopyToByteArray(buffer, arr);
|
|
367
|
+
auto data = vector<uint8_t>(arr.begin(), arr.end());
|
|
368
|
+
|
|
369
|
+
contentHandler->ProcessMessage(std::move(data), args);
|
|
370
|
+
} else {
|
|
371
|
+
contentHandler->ProcessMessage(string{message}, args);
|
|
372
|
+
}
|
|
373
|
+
} else {
|
|
374
|
+
args["data"] = message;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
SendEvent(context, L"websocketMessage", std::move(args));
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
rc->SetOnClose([id, context = m_context](IWebSocketResource::CloseCode code, const string &reason) {
|
|
381
|
+
auto args = msrn::JSValueObject{{"id", id}, {"code", static_cast<uint16_t>(code)}, {"reason", reason}};
|
|
382
|
+
|
|
383
|
+
SendEvent(context, L"websocketClosed", std::move(args));
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
rc->SetOnError([id, context = m_context](const IWebSocketResource::Error &err) {
|
|
387
|
+
auto errorObj = msrn::JSValueObject{{"id", id}, {"message", err.Message}};
|
|
388
|
+
|
|
389
|
+
SendEvent(context, L"websocketFailed", std::move(errorObj));
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
m_resourceMap.emplace(static_cast<double>(id), rc);
|
|
393
|
+
|
|
394
|
+
return rc;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
void WebSocketTurboModule::Initialize(msrn::ReactContext const &reactContext) noexcept {
|
|
398
|
+
m_context = reactContext.Handle();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void WebSocketTurboModule::Connect(
|
|
402
|
+
string &&url,
|
|
403
|
+
std::optional<vector<string>> protocols,
|
|
404
|
+
ReactNativeSpecs::WebSocketModuleSpec_connect_options &&options,
|
|
405
|
+
double socketID) noexcept {
|
|
406
|
+
IWebSocketResource::Protocols rcProtocols;
|
|
407
|
+
for (const auto &protocol : protocols.value_or(vector<string>{})) {
|
|
408
|
+
rcProtocols.push_back(protocol);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
IWebSocketResource::Options rcOptions;
|
|
412
|
+
auto &optHeaders = options.headers;
|
|
413
|
+
if (optHeaders.has_value()) {
|
|
414
|
+
auto &headersVal = optHeaders.value();
|
|
415
|
+
for (const auto &headerVal : headersVal.AsArray()) {
|
|
416
|
+
// Each header JSValueObject should only contain one key-value pair
|
|
417
|
+
const auto &entry = *headerVal.AsObject().cbegin();
|
|
418
|
+
rcOptions.emplace(winrt::to_hstring(entry.first), entry.second.AsString());
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
weak_ptr<IWebSocketResource> weakRc;
|
|
423
|
+
auto rcItr = m_resourceMap.find(socketID);
|
|
424
|
+
if (rcItr != m_resourceMap.cend()) {
|
|
425
|
+
weakRc = (*rcItr).second;
|
|
426
|
+
} else {
|
|
427
|
+
weakRc = CreateResource(static_cast<int64_t>(socketID), string{url});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (auto rc = weakRc.lock()) {
|
|
431
|
+
rc->Connect(std::move(url), rcProtocols, rcOptions);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
void WebSocketTurboModule::Close(double code, string &&reason, double socketID) noexcept {
|
|
436
|
+
auto rcItr = m_resourceMap.find(socketID);
|
|
437
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
438
|
+
return; // TODO: Send error instead?
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
442
|
+
if (auto rc = weakRc.lock()) {
|
|
443
|
+
rc->Close(static_cast<IWebSocketResource::CloseCode>(code), std::move(reason));
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
void WebSocketTurboModule::Send(string &&message, double forSocketID) noexcept {
|
|
448
|
+
auto rcItr = m_resourceMap.find(forSocketID);
|
|
449
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
450
|
+
return; // TODO: Send error instead?
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
454
|
+
if (auto rc = weakRc.lock()) {
|
|
455
|
+
rc->Send(std::move(message));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
void WebSocketTurboModule::SendBinary(string &&base64String, double forSocketID) noexcept {
|
|
460
|
+
auto rcItr = m_resourceMap.find(forSocketID);
|
|
461
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
462
|
+
return; // TODO: Send error instead?
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
466
|
+
if (auto rc = weakRc.lock()) {
|
|
467
|
+
rc->SendBinary(std::move(base64String));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
void WebSocketTurboModule::Ping(double socketID) noexcept {
|
|
472
|
+
auto rcItr = m_resourceMap.find(socketID);
|
|
473
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
474
|
+
return; // TODO: Send error instead?
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
478
|
+
if (auto rc = weakRc.lock()) {
|
|
479
|
+
rc->Ping();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// See react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
|
|
484
|
+
void WebSocketTurboModule::AddListener(string && /*eventName*/) noexcept {}
|
|
485
|
+
|
|
486
|
+
void WebSocketTurboModule::RemoveListeners(double /*count*/) noexcept {}
|
|
487
|
+
|
|
488
|
+
#pragma endregion WebSocketTurboModule
|
|
489
|
+
|
|
315
490
|
/*extern*/ const char *GetWebSocketModuleName() noexcept {
|
|
316
|
-
return
|
|
491
|
+
return s_moduleName;
|
|
317
492
|
}
|
|
318
493
|
|
|
319
494
|
/*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateWebSocketModule(
|
|
@@ -324,4 +499,12 @@ void WebSocketModuleProxy::SendBinary(std::string &&base64String, int64_t id) no
|
|
|
324
499
|
return nullptr;
|
|
325
500
|
}
|
|
326
501
|
|
|
502
|
+
/*extern*/ const wchar_t *GetWebSocketTurboModuleName() noexcept {
|
|
503
|
+
return s_moduleNameW;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/*extern*/ const msrn::ReactModuleProvider &GetWebSocketModuleProvider() noexcept {
|
|
507
|
+
return s_moduleProvider;
|
|
508
|
+
}
|
|
509
|
+
|
|
327
510
|
} // namespace Microsoft::React
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <NativeWebSocketModuleSpec.g.h>
|
|
7
|
+
#include <Modules/IWebSocketModuleProxy.h>
|
|
8
|
+
#include <NativeModules.h>
|
|
9
|
+
#include <Networking/IWebSocketResource.h>
|
|
10
|
+
|
|
11
|
+
namespace Microsoft::React {
|
|
12
|
+
|
|
13
|
+
REACT_MODULE(WebSocketTurboModule, L"WebSocketModule")
|
|
14
|
+
struct WebSocketTurboModule {
|
|
15
|
+
using ModuleSpec = ReactNativeSpecs::WebSocketModuleSpec;
|
|
16
|
+
|
|
17
|
+
REACT_INIT(Initialize)
|
|
18
|
+
void Initialize(winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept;
|
|
19
|
+
|
|
20
|
+
REACT_METHOD(Connect, L"connect")
|
|
21
|
+
void Connect(
|
|
22
|
+
std::string &&url,
|
|
23
|
+
std::optional<std::vector<std::string>> protocols,
|
|
24
|
+
ReactNativeSpecs::WebSocketModuleSpec_connect_options &&options,
|
|
25
|
+
double socketID) noexcept;
|
|
26
|
+
|
|
27
|
+
REACT_METHOD(Close, L"close")
|
|
28
|
+
void Close(double code, std::string &&reason, double socketID) noexcept;
|
|
29
|
+
|
|
30
|
+
REACT_METHOD(Send, L"send")
|
|
31
|
+
void Send(std::string &&message, double forSocketID) noexcept;
|
|
32
|
+
|
|
33
|
+
REACT_METHOD(SendBinary, L"sendBinary")
|
|
34
|
+
void SendBinary(std::string &&base64String, double forSocketID) noexcept;
|
|
35
|
+
|
|
36
|
+
REACT_METHOD(Ping, L"ping")
|
|
37
|
+
void Ping(double socketID) noexcept;
|
|
38
|
+
|
|
39
|
+
REACT_METHOD(AddListener, L"addListener")
|
|
40
|
+
void AddListener(std::string &&eventName) noexcept;
|
|
41
|
+
|
|
42
|
+
REACT_METHOD(RemoveListeners, L"removeListeners")
|
|
43
|
+
void RemoveListeners(double count) noexcept;
|
|
44
|
+
|
|
45
|
+
private:
|
|
46
|
+
std::shared_ptr<Networking::IWebSocketResource> CreateResource(int64_t id, std::string &&url) noexcept;
|
|
47
|
+
|
|
48
|
+
winrt::Microsoft::ReactNative::ReactContext m_context;
|
|
49
|
+
std::unordered_map<double, std::shared_ptr<Networking::IWebSocketResource>> m_resourceMap;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
} // namespace Microsoft::React
|
|
@@ -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 ¶ms) noexcept /*override*/
|
|
227
|
+
{
|
|
228
|
+
params[blobKeys.Data] = std::move(message);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
void BlobWebSocketModuleContentHandler::ProcessMessage(
|
|
232
|
+
vector<uint8_t> &&message,
|
|
233
|
+
msrn::JSValueObject ¶ms) 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
|