diff --git a/.vscode/settings.json b/.vscode/settings.json
index 72f1efd6407..9fc3b99723a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -23,7 +23,7 @@
"**/lib/**/*.js": true,
"**/node_modules": false
},
- "editor.formatOnSave": true,
+ "editor.formatOnSave": false,
"eslint.format.enable": true,
"eslint.packageManager": "yarn",
"eslint.enable": true,
diff --git a/change/react-native-windows-55a74ced-a538-484a-98a1-8cb1b4e939b7.json b/change/react-native-windows-55a74ced-a538-484a-98a1-8cb1b4e939b7.json
new file mode 100644
index 00000000000..98f65462a5e
--- /dev/null
+++ b/change/react-native-windows-55a74ced-a538-484a-98a1-8cb1b4e939b7.json
@@ -0,0 +1,7 @@
+{
+ "type": "patch",
+ "comment": "Use TurboModules for networking in MSRN (#11867)",
+ "packageName": "react-native-windows",
+ "email": "julio.rocha@microsoft.com",
+ "dependentChangeType": "patch"
+}
diff --git a/packages/playground/windows/playground-win32-packaged.sln b/packages/playground/windows/playground-win32-packaged.sln
index 1fe18bc49c2..a76a97e8b21 100644
--- a/packages/playground/windows/playground-win32-packaged.sln
+++ b/packages/playground/windows/playground-win32-packaged.sln
@@ -44,12 +44,12 @@ Global
..\..\..\vnext\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
- Release|ARM = Release|ARM
+ Debug|ARM = Debug|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
+ Release|ARM = Release|ARM
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8B88FFAE-4DBC-49A2-AFA5-D2477D4AD189}.Debug|ARM.ActiveCfg = Debug|Win32
diff --git a/packages/playground/windows/playground-win32.sln b/packages/playground/windows/playground-win32.sln
index 1ef1890150c..d8a150d7efd 100644
--- a/packages/playground/windows/playground-win32.sln
+++ b/packages/playground/windows/playground-win32.sln
@@ -44,12 +44,12 @@ Global
..\..\..\vnext\Shared\Shared.vcxitems*{f7d32bd0-2749-483e-9a0d-1635ef7e3136}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|ARM = Debug|ARM
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
- Release|ARM = Release|ARM
+ Debug|ARM = Debug|ARM
Release|x64 = Release|x64
Release|x86 = Release|x86
+ Release|ARM = Release|ARM
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{8B88FFAE-4DBC-49A2-AFA5-D2477D4AD189}.Debug|ARM.ActiveCfg = Debug|Win32
diff --git a/vnext/.editorconfig b/vnext/.editorconfig
index 2cec6e9f5b6..d49049a8967 100644
--- a/vnext/.editorconfig
+++ b/vnext/.editorconfig
@@ -28,5 +28,8 @@ csharp_prefer_simple_default_expression = false:none
indent_style = tab
indent_size = 4
+[overrides.json]
+insert_final_newline = false
+
[package.json]
insert_final_newline = false
diff --git a/vnext/Desktop.IntegrationTests/HttpOriginPolicyIntegrationTest.cpp b/vnext/Desktop.IntegrationTests/HttpOriginPolicyIntegrationTest.cpp
index c9026cc9831..44cfe5f2fdb 100644
--- a/vnext/Desktop.IntegrationTests/HttpOriginPolicyIntegrationTest.cpp
+++ b/vnext/Desktop.IntegrationTests/HttpOriginPolicyIntegrationTest.cpp
@@ -15,7 +15,6 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace http = boost::beast::http;
-using folly::dynamic;
using Microsoft::React::Networking::IHttpResource;
using Microsoft::React::Networking::OriginPolicy;
using std::make_shared;
@@ -146,10 +145,10 @@ TEST_CLASS(HttpOriginPolicyIntegrationTest)
string{server1Args.Url},
0, /*requestId*/
std::move(clientArgs.RequestHeaders),
- dynamic::object("string", ""), /*data*/
+ { { "string", "" } }, /*data*/
"text",
false, /*useIncrementalUpdates*/
- 0, /*timeout*/
+ 0, /*timeout*/
clientArgs.WithCredentials, /*withCredentials*/
[](int64_t){} /*reactCallback*/
);
@@ -200,10 +199,10 @@ TEST_CLASS(HttpOriginPolicyIntegrationTest)
string{serverArgs.Url},
0, /*requestId*/
std::move(clientArgs.RequestHeaders),
- dynamic::object("string", ""), /*data*/
+ { { "string", "" } }, /*data*/
"text",
false, /*useIncrementalUpdates*/
- 0, /*timeout*/
+ 0, /*timeout*/
clientArgs.WithCredentials, /*withCredentials*/
[](int64_t) {} /*reactCallback*/
);
@@ -298,12 +297,12 @@ TEST_CLASS(HttpOriginPolicyIntegrationTest)
{
{"ValidHeader", "AnyValue"}
},
- dynamic::object("string", ""), /*data*/
+ { { "string", "" } }, /*data*/
"text",
- false /*useIncrementalUpdates*/,
- 0 /*timeout*/,
- false /*withCredentials*/,
- [](int64_t) {} /*callback*/
+ false /*useIncrementalUpdates*/,
+ 0 /*timeout*/,
+ false /*withCredentials*/,
+ [](int64_t) {} /*callback*/
);
getDataPromise.get_future().wait();
diff --git a/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp b/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp
index 172ccb41b4a..5a4e3e46ba3 100644
--- a/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp
+++ b/vnext/Desktop.IntegrationTests/RNTesterIntegrationTests.cpp
@@ -26,7 +26,6 @@ TEST_MODULE_INITIALIZE(InitModule) {
using Microsoft::React::SetRuntimeOptionBool;
SetRuntimeOptionBool("WebSocket.AcceptSelfSigned", true);
- SetRuntimeOptionBool("UseBeastWebSocket", false);
SetRuntimeOptionBool("Blob.EnableModule", true);
// WebSocketJSExecutor can't register native log hooks.
diff --git a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj
index 9a4a31503bd..a893bd9caf8 100644
--- a/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj
+++ b/vnext/Desktop.IntegrationTests/React.Windows.Desktop.IntegrationTests.vcxproj
@@ -36,6 +36,7 @@
+
@@ -47,22 +48,32 @@
true
-
+
BOOST_ASIO_HAS_IOCP;
+ CORE_ABI;
_WIN32_WINNT=$(WinVer);
WIN32;
_WINDOWS;
FOLLY_NO_CONFIG;
NOMINMAX;
_HAS_AUTO_PTR_ETC;
- RN_PLATFORM=windesktop;
+ RN_PLATFORM=win32;
RN_EXPORT=;
JSI_EXPORT=;
%(PreprocessorDefinitions)
%(AdditionalOptions) /bigobj
- $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+
+ $(VCInstallDir)UnitTest\include;
+ "$(ReactNativeWindowsDir)Microsoft.ReactNative";
+ "$(ReactNativeWindowsDir)\Shared\tracing";
+ %(AdditionalIncludeDirectories)
+
true
@@ -128,4 +139,23 @@
+
+
+
+
+ $(OutputPath)..\React.Windows.Desktop\facebook.react.winmd
+
+
+ $(OutputPath)..\React.Windows.Desktop\Microsoft.Internal.winmd
+
+
+ $(OutputPath)..\React.Windows.Desktop\Microsoft.ReactNative.winmd
+
+
+
\ No newline at end of file
diff --git a/vnext/Desktop.UnitTests/BaseWebSocketTests.cpp b/vnext/Desktop.UnitTests/BaseWebSocketTests.cpp
deleted file mode 100644
index c5e68faa19a..00000000000
--- a/vnext/Desktop.UnitTests/BaseWebSocketTests.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-#include
-#include
-#include
-
-using namespace boost::beast;
-using namespace Microsoft::VisualStudio::CppUnitTestFramework;
-
-using boost::system::error_code;
-using Microsoft::React::Beast::Test::TestWebSocketResource;
-using std::future;
-using std::make_unique;
-using std::promise;
-using std::string;
-
-namespace {
-
-constexpr char testUrl[] = "ws://localhost";
-
-} // namespace
-
-namespace Microsoft::React::Test {
-
-using CloseCode = IWebSocketResource::CloseCode;
-using Error = IWebSocketResource::Error;
-
-// We turn clang format off here because it does not work with some of the
-// test macros.
-// clang-format off
-
-TEST_CLASS(BaseWebSocketTest){
- BEGIN_TEST_CLASS_ATTRIBUTE()
- TEST_CLASS_ATTRIBUTE(L"Ignore", L"true")
- END_TEST_CLASS_ATTRIBUTE()
-
- TEST_METHOD(CreateAndSetHandlers){
- auto ws = make_unique(Url(testUrl));
-
- Assert::IsFalse(nullptr == ws);
- ws->SetOnConnect([]() {});
- ws->SetOnPing([]() {});
- ws->SetOnSend([](size_t length) {});
- ws->SetOnMessage([](size_t length, const string &buffer, bool isBinary) {});
- ws->SetOnClose([](CloseCode, const string &) {});
- ws->SetOnError([](const Error &error) {});
- }
-
- TEST_METHOD(ConnectSucceeds) {
- string errorMessage;
- bool connected = false;
- auto ws = make_unique(Url(testUrl));
- ws->SetOnError([&errorMessage](Error err) { errorMessage = err.Message; });
- ws->SetOnConnect([&connected]() { connected = true; });
-
- ws->Connect(testUrl, {}, {});
- ws->Close(CloseCode::Normal, {});
-
- Assert::AreEqual({}, errorMessage);
- Assert::IsTrue(connected);
- }
-
- TEST_METHOD(ConnectFails) {
- string errorMessage;
- bool connected = false;
- auto ws = make_unique(Url(testUrl));
- ws->SetOnError([&errorMessage](Error err) { errorMessage = err.Message; });
- ws->SetOnConnect([&connected]() { connected = true; });
- ws->SetConnectResult([]() -> error_code {
- return make_error_code(errc::state_not_recoverable);
- });
-
- ws->Connect(testUrl, {}, {});
- ws->Close(CloseCode::Normal, {});
-
- Assert::AreNotEqual({}, errorMessage);
- Assert::IsFalse(connected);
- }
-
- BEGIN_TEST_METHOD_ATTRIBUTE(HandshakeFails)
- TEST_IGNORE()
- END_TEST_METHOD_ATTRIBUTE()
- TEST_METHOD(HandshakeFails) {
- string errorMessage;
- bool connected = false;
- auto ws = make_unique(Url(testUrl));
- ws->SetOnError([&errorMessage](Error err) { errorMessage = err.Message; });
- ws->SetOnConnect([&connected]() { connected = true; });
- ws->SetHandshakeResult([](string, string) -> error_code {
- return make_error_code(errc::state_not_recoverable);
- });
-
- ws->Connect(testUrl, {}, {});
- ws->Close(CloseCode::Normal, {});
-
- Assert::AreNotEqual({}, errorMessage);
- Assert::IsFalse(connected);
- }
-
- BEGIN_TEST_METHOD_ATTRIBUTE(CloseSucceeds)
- TEST_IGNORE()
- END_TEST_METHOD_ATTRIBUTE()
- TEST_METHOD(CloseSucceeds) {
- string errorMessage;
- promise connected;
- bool closed = false;
- auto ws = make_unique(Url(testUrl));
- ws->SetOnError([&errorMessage](Error err) { errorMessage = err.Message; });
- ws->SetOnConnect([&connected]() { connected.set_value(); });
- ws->SetOnClose(
- [&closed](CloseCode code, const string &message) { closed = true; });
-
- ws->SetCloseResult(
- []() -> error_code { return make_error_code(errc::success); });
-
- ws->Connect(testUrl, {}, {});
- connected.get_future().wait();
-
- ws->Close(CloseCode::Normal, "Normal");
-
- Assert::AreNotEqual({}, errorMessage);
- Assert::IsTrue(closed);
- }
-};
-
-// clange-format on
-
-} // namespace Microsoft::React::Test
diff --git a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj
index 2cedc1f52ec..695663f154a 100644
--- a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj
+++ b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj
@@ -45,7 +45,7 @@
- $(ReactNativeWindowsDir)Mso;$(ReactNativeWindowsDir)Common;$(ReactNativeWindowsDir)Desktop;$(ReactNativeWindowsDir)stubs;$(ReactNativeWindowsDir)Shared;$(ReactNativeWindowsDir)include\Shared;$(MSBuildThisFileDirectory);$(IncludePath)
+ $(ReactNativeWindowsDir)Mso;$(ReactNativeWindowsDir)Common;$(ReactNativeWindowsDir)Desktop;$(ReactNativeWindowsDir)stubs;$(ReactNativeWindowsDir)Shared;$(ReactNativeWindowsDir)include\Shared;$(ReactNativeWindowsDir)Microsoft.ReactNative.Cxx;$(MSBuildThisFileDirectory);$(IncludePath)
@@ -83,9 +83,10 @@
-
- true
-
+
+
+
+
diff --git a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj.filters b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj.filters
index 26416f07216..31fa896968d 100644
--- a/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj.filters
+++ b/vnext/Desktop.UnitTests/React.Windows.Desktop.UnitTests.vcxproj.filters
@@ -7,9 +7,6 @@
Source Files
-
- Unit Tests
-
Unit Tests
diff --git a/vnext/Desktop.UnitTests/RedirectHttpFilterUnitTest.cpp b/vnext/Desktop.UnitTests/RedirectHttpFilterUnitTest.cpp
index 920a3ca918a..858aad58c60 100644
--- a/vnext/Desktop.UnitTests/RedirectHttpFilterUnitTest.cpp
+++ b/vnext/Desktop.UnitTests/RedirectHttpFilterUnitTest.cpp
@@ -8,6 +8,8 @@
#include "WinRTNetworkingMocks.h"
// Windows API
+#include
+// Leaving a line so clang-format does not mess up include ordering
#include
#include
diff --git a/vnext/Desktop/BeastWebSocketResource.cpp b/vnext/Desktop/BeastWebSocketResource.cpp
deleted file mode 100644
index 2951bd61562..00000000000
--- a/vnext/Desktop/BeastWebSocketResource.cpp
+++ /dev/null
@@ -1,764 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-#include "pch.h"
-
-#include "BeastWebSocketResource.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "Unicode.h"
-
-using namespace boost::archive::iterators;
-using namespace boost::asio;
-using namespace boost::beast;
-
-using boost::asio::async_initiate;
-using boost::asio::ip::tcp;
-
-using std::function;
-using std::make_unique;
-using std::shared_ptr;
-using std::size_t;
-using std::string;
-using std::unique_ptr;
-
-namespace Microsoft::React {
-
-#pragma region BeastWebSocketResource
-
-BeastWebSocketResource::BeastWebSocketResource() noexcept {}
-
-#pragma region IWebSocketResource members
-
-void BeastWebSocketResource::Connect(
- std::string &&urlString,
- const Protocols &protocols,
- const Options &options) noexcept {
- Url url(std::move(urlString));
-
- if (url.scheme == "ws") {
- if (url.port.empty())
- url.port = "80";
-
- m_concreteResource = std::make_shared(std::move(url));
- } else if (url.scheme == "wss") {
- if (url.port.empty())
- url.port = "443";
-
- m_concreteResource = std::make_shared(std::move(url));
- }
-
- m_concreteResource->SetOnClose(std::move(m_closeHandler));
- m_concreteResource->SetOnConnect(std::move(m_connectHandler));
- m_concreteResource->SetOnError(std::move(m_errorHandler));
- m_concreteResource->SetOnMessage(std::move(m_readHandler));
- m_concreteResource->SetOnPing(std::move(m_pingHandler));
- m_concreteResource->SetOnSend(std::move(m_writeHandler));
-}
-
-void BeastWebSocketResource::Close(CloseCode code, const string &reason) noexcept {
- m_concreteResource->Close(code, reason);
-}
-
-void BeastWebSocketResource::Send(string &&message) noexcept {
- m_concreteResource->Send(std::move(message));
-}
-
-void BeastWebSocketResource::SendBinary(string &&base64String) noexcept {
- m_concreteResource->SendBinary(std::move(base64String));
-}
-
-void BeastWebSocketResource::Ping() noexcept {
- m_concreteResource->Ping();
-}
-
-#pragma endregion IWebSocketResource members
-
-#pragma region Handler setters
-
-void BeastWebSocketResource::SetOnConnect(function &&handler) noexcept {
- m_connectHandler = std::move(handler);
-}
-
-void BeastWebSocketResource::SetOnPing(function &&handler) noexcept {
- m_pingHandler = std::move(handler);
-}
-
-void BeastWebSocketResource::SetOnSend(function &&handler) noexcept {
- m_writeHandler = std::move(handler);
-}
-
-void BeastWebSocketResource::SetOnMessage(function &&handler) noexcept {
- m_readHandler = std::move(handler);
-}
-
-void BeastWebSocketResource::SetOnClose(function &&handler) noexcept {
- m_closeHandler = std::move(handler);
-}
-
-void BeastWebSocketResource::SetOnError(function &&handler) noexcept {
- m_errorHandler = std::move(handler);
-}
-
-IWebSocketResource::ReadyState BeastWebSocketResource::GetReadyState() const noexcept {
- return m_concreteResource->GetReadyState();
-}
-
-#pragma endregion Handler setters
-
-#pragma endregion BeastWebSocketResource
-
-namespace Beast {
-
-#pragma region BaseWebSocketResource members
-
-template
-BaseWebSocketResource::BaseWebSocketResource(Url &&url) : m_url{std::move(url)} {}
-
-template
-BaseWebSocketResource::~BaseWebSocketResource() noexcept {
- if (!m_context.stopped()) {
- if (!m_closeRequested)
- Close(CloseCode::GoingAway, "Terminating instance");
- else if (!m_closeInProgress)
- PerformClose();
- }
-}
-
-template
-void BaseWebSocketResource::Handshake() {
- // TODO: Enable if we want a configurable timeout.
- // m_stream->set_option(websocket::stream_base::timeout::suggested(role_type::client));
- m_stream->async_handshake(
- m_url.host,
- m_url.Target(),
- bind_front_handler(&BaseWebSocketResource::OnHandshake, SharedFromThis()));
-}
-
-template
-void BaseWebSocketResource::OnHandshake(error_code ec) {
- if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Handshake});
- } else {
- m_handshakePerformed = true;
- m_readyState = ReadyState::Open;
-
- if (m_connectHandler)
- m_connectHandler();
-
- // Start read cycle.
- PerformRead();
-
- // Perform writes, if enqueued.
- if (!m_writeRequests.empty())
- PerformWrite();
-
- // Perform pings, if enqueued.
- if (m_pingRequests > 0)
- PerformPing();
-
- // Perform close, if requested.
- if (m_closeRequested && !m_closeInProgress)
- PerformClose();
- }
-}
-
-template
-void BaseWebSocketResource::PerformRead() {
- if (ReadyState::Closing == m_readyState || ReadyState::Closed == m_readyState) {
- return;
- }
-
- // Check if there are more bytes available than a header length (2).
- m_stream->async_read(
- m_bufferIn, bind_front_handler(&BaseWebSocketResource::OnRead, SharedFromThis()));
-}
-
-template
-void BaseWebSocketResource::OnRead(error_code ec, size_t size) {
- if (boost::asio::error::operation_aborted == ec) {
- // Nothing to do.
- } else if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Receive});
- } else {
- string message{buffers_to_string(m_bufferIn.data())};
-
- if (m_stream->got_binary()) {
- // ISS:2906983
- typedef base64_from_binary> encode_base64;
-
- // NOTE: Encoding the base64 string makes the message's length different
- // from the 'size' argument.
- std::ostringstream os;
- std::copy(encode_base64(message.c_str()), encode_base64(message.c_str() + size), ostream_iterator(os));
- message = os.str();
-
- auto padSize = ((4 - message.length()) % 4) % 4;
- message.append(padSize, '=');
- }
-
- if (m_readHandler)
- m_readHandler(size, std::move(message), m_stream->got_binary());
-
- m_bufferIn.consume(size);
- } // if (ec)
-
- // Enqueue another read.
- PerformRead();
-}
-
-template
-void BaseWebSocketResource::PerformWrite() {
- assert(!m_writeRequests.empty());
- assert(!m_writeInProgress);
- m_writeInProgress = true;
-
- std::pair request = m_writeRequests.front();
- m_writeRequests.pop();
-
- m_stream->binary(request.second);
-
- // Auto-fragment disabled. Adjust write buffer to the largest message length
- // processed.
- if (request.first.length() > m_stream->write_buffer_bytes())
- m_stream->write_buffer_bytes(request.first.length());
-
- m_stream->async_write(
- buffer(request.first),
- bind_front_handler(&BaseWebSocketResource::OnWrite, SharedFromThis()));
-}
-
-template
-void BaseWebSocketResource::OnWrite(error_code ec, size_t size) {
- if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Send});
- } else {
- if (m_writeHandler)
- m_writeHandler(size);
- }
-
- m_writeInProgress = false;
-
- if (!m_writeRequests.empty())
- PerformWrite();
-}
-
-template
-void BaseWebSocketResource::PerformPing() {
- assert(m_pingRequests > 0);
- assert(!m_pingInProgress);
- m_pingInProgress = true;
-
- --m_pingRequests;
-
- m_stream->async_ping(
- websocket::ping_data(),
- bind_front_handler(&BaseWebSocketResource::OnPing, SharedFromThis()));
-}
-
-template
-void BaseWebSocketResource::OnPing(error_code ec) {
- if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Ping});
- } else if (m_pingHandler)
- m_pingHandler();
-
- m_pingInProgress = false;
-
- if (m_pingRequests > 0)
- PerformPing();
-}
-
-template
-void BaseWebSocketResource::PerformClose() {
- m_closeInProgress = true;
- m_readyState = ReadyState::Closing;
-
- m_stream->async_close(
- ToBeastCloseCode(m_closeCodeRequest),
- bind_front_handler(&BaseWebSocketResource::OnClose, SharedFromThis()));
-
- // Synchronize context thread.
- Stop();
-}
-
-template
-void BaseWebSocketResource::OnClose(error_code ec) {
- if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Close});
- } else {
- m_readyState = ReadyState::Closed;
-
- if (m_closeHandler)
- m_closeHandler(m_closeCodeRequest, m_closeReasonRequest);
- }
-}
-
-template
-void BaseWebSocketResource::Stop() {
- if (m_workGuard)
- m_workGuard->reset();
-
- if (m_contextThread.joinable() && std::this_thread::get_id() != m_contextThread.get_id())
- m_contextThread.join();
-}
-
-template
-void BaseWebSocketResource::EnqueueWrite(const string &message, bool binary) {
- post(m_context, [self = SharedFromThis(), message = std::move(message), binary]() {
- self->m_writeRequests.emplace(std::move(message), binary);
-
- if (!self->m_writeInProgress && ReadyState::Open == self->m_readyState)
- self->PerformWrite();
- });
-}
-
-template
-websocket::close_code BaseWebSocketResource::ToBeastCloseCode(
- IWebSocketResource::CloseCode closeCode) {
- static_assert(
- static_cast(IWebSocketResource::CloseCode::Abnormal) ==
- static_cast(websocket::close_code::abnormal),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::BadPayload) ==
- static_cast(websocket::close_code::bad_payload),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::GoingAway) ==
- static_cast(websocket::close_code::going_away),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::InternalError) ==
- static_cast(websocket::close_code::internal_error),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::NeedsExtension) ==
- static_cast(websocket::close_code::needs_extension),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::Normal) ==
- static_cast(websocket::close_code::normal),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::NoStatus) ==
- static_cast(websocket::close_code::no_status),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::PolicyError) ==
- static_cast(websocket::close_code::policy_error),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::ProtocolError) ==
- static_cast(websocket::close_code::protocol_error),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::Reserved1) ==
- static_cast(websocket::close_code::reserved1),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::Reserved2) ==
- static_cast(websocket::close_code::reserved2),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::Reserved3) ==
- static_cast(websocket::close_code::reserved3),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::ServiceRestart) ==
- static_cast(websocket::close_code::service_restart),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::TooBig) ==
- static_cast(websocket::close_code::too_big),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::TryAgainLater) ==
- static_cast(websocket::close_code::try_again_later),
- "Exception type enums don't match");
- static_assert(
- static_cast(IWebSocketResource::CloseCode::UnknownData) ==
- static_cast(websocket::close_code::unknown_data),
- "Exception type enums don't match");
-
- return static_cast(closeCode);
-}
-
-#pragma region IWebSocketResource members
-
-template
-void BaseWebSocketResource::Connect(
- std::string &&url,
- const Protocols &protocols,
- const Options &options) noexcept {
- // "Cannot call Connect more than once");
- assert(ReadyState::Connecting == m_readyState);
-
- // TODO: Enable?
- // m_stream->set_option(websocket::stream_base::timeout::suggested(role_type::client));
- m_stream->set_option(websocket::stream_base::decorator([options = options](websocket::request_type &req) {
- // Collect headers
- for (const auto &header : options) {
- req.insert(Microsoft::Common::Unicode::Utf16ToUtf8(header.first), header.second);
- }
- }));
-
- if (!protocols.empty()) {
- for (auto &protocol : protocols) {
- // ISS:2152951 - collect protocols
- }
- }
-
- tcp::resolver resolver(m_context);
- resolver.async_resolve(
- m_url.host,
- m_url.port,
- bind_front_handler(&BaseWebSocketResource::OnResolve, SharedFromThis()));
-
- m_contextThread = std::thread([self = SharedFromThis()]() {
- self->m_workGuard = make_unique>(make_work_guard(self->m_context));
- self->m_context.run();
- });
-}
-
-template
-void BaseWebSocketResource::OnResolve(
- error_code ec,
- typename tcp::resolver::results_type results) {
- if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Resolution});
-
- return;
- }
-
- // Connect
- get_lowest_layer(*m_stream).async_connect(
- results, bind_front_handler(&BaseWebSocketResource::OnConnect, SharedFromThis()));
-}
-
-template
-void BaseWebSocketResource::OnConnect(
- error_code ec,
- tcp::resolver::results_type::endpoint_type endpoints) {
- if (ec) {
- if (m_errorHandler)
- m_errorHandler({ec.message(), ErrorType::Connection});
- } else {
- Handshake();
- }
-}
-
-template
-void BaseWebSocketResource::Close(CloseCode code, const string &reason) noexcept {
- if (m_closeRequested)
- return;
-
- m_closeRequested = true;
- m_closeCodeRequest = code;
- m_closeReasonRequest = std::move(reason);
-
- assert(!m_closeInProgress);
- // Give priority to Connect().
- if (m_handshakePerformed)
- PerformClose();
- else
- Stop(); // Synchronize the context thread.
-}
-
-template
-void BaseWebSocketResource::Send(string &&message) noexcept {
- EnqueueWrite(std::move(message), false);
-}
-
-template
-void BaseWebSocketResource::SendBinary(string &&base64String) noexcept {
- m_stream->binary(true);
-
- string message;
- try {
- typedef transform_width, 8, 6> decode_base64;
-
- // A correctly formed base64 string should have from 0 to three '=' trailing
- // characters. Skip those.
- size_t padSize = std::count(base64String.begin(), base64String.end(), '=');
- message = string(decode_base64(base64String.begin()), decode_base64(base64String.end() - padSize));
- } catch (const std::exception &) {
- if (m_errorHandler)
- m_errorHandler({"", ErrorType::Send});
-
- return;
- }
-
- EnqueueWrite(std::move(message), true);
-}
-
-template
-void BaseWebSocketResource::Ping() noexcept {
- if (ReadyState::Closed == m_readyState)
- return;
-
- ++m_pingRequests;
- if (!m_pingInProgress && ReadyState::Open == m_readyState)
- PerformPing();
-}
-
-#pragma endregion IWebSocketResource members
-
-#pragma region Handler setters
-
-template
-void BaseWebSocketResource::SetOnConnect(function &&handler) noexcept {
- m_connectHandler = std::move(handler);
-}
-
-template
-void BaseWebSocketResource::SetOnPing(function &&handler) noexcept {
- m_pingHandler = std::move(handler);
-}
-
-template
-void BaseWebSocketResource::SetOnSend(function &&handler) noexcept {
- m_writeHandler = std::move(handler);
-}
-
-template
-void BaseWebSocketResource::SetOnMessage(
- function &&handler) noexcept {
- m_readHandler = std::move(handler);
-}
-
-template
-void BaseWebSocketResource::SetOnClose(
- function &&handler) noexcept {
- m_closeHandler = std::move(handler);
-}
-
-template
-void BaseWebSocketResource::SetOnError(function &&handler) noexcept {
- m_errorHandler = std::move(handler);
-}
-
-template
-IWebSocketResource::ReadyState BaseWebSocketResource::GetReadyState() const noexcept {
- return m_readyState;
-}
-
-#pragma endregion Handler setters
-
-#pragma endregion BaseWebSocketResource members
-
-#pragma region WebSocketResource members
-
-WebSocketResource::WebSocketResource(Url &&url) : BaseWebSocketResource(std::move(url)) {
- this->m_stream = make_unique>(this->m_context);
- this->m_stream->auto_fragment(false); // ISS:2906963 Re-enable message fragmenting.
-}
-
-shared_ptr> WebSocketResource::SharedFromThis() /*override*/
-{
- return this->shared_from_this();
-}
-
-#pragma endregion WebSocketResource members
-
-#pragma region SecureWebSocketResource members
-
-SecureWebSocketResource::SecureWebSocketResource(Url &&url) : BaseWebSocketResource(std::move(url)) {
- auto ssl = ssl::context(ssl::context::sslv23_client);
- this->m_stream = make_unique>>(this->m_context, ssl);
- this->m_stream->auto_fragment(false); // ISS:2906963 Re-enable message fragmenting.
-}
-
-void SecureWebSocketResource::Handshake() {
- // Prefer shared_from_this() in concrete classes. SharedFromThis() falis to compile.
- this->m_stream->next_layer().async_handshake(
- ssl::stream_base::client, bind_front_handler(&SecureWebSocketResource::OnSslHandshake, shared_from_this()));
-}
-
-void SecureWebSocketResource::OnSslHandshake(error_code ec) {
- if (ec && m_errorHandler) {
- m_errorHandler({ec.message(), ErrorType::Connection});
- } else {
- BaseWebSocketResource::Handshake();
- }
-}
-
-shared_ptr>> SecureWebSocketResource::SharedFromThis()
-/*override*/ {
- return this->shared_from_this();
-}
-
-#pragma endregion SecureWebSocketResource members
-
-namespace Test {
-
-#pragma region MockStream
-
-MockStream::MockStream(io_context &context)
- : m_context{context},
- ConnectResult{[]() { return error_code{}; }},
- HandshakeResult{[](string, string) { return error_code{}; }},
- ReadResult{[]() { return std::make_pair({}, 0); }},
- CloseResult{[]() { return error_code{}; }} {}
-
-io_context::executor_type MockStream::get_executor() noexcept {
- return m_context.get_executor();
-}
-
-void MockStream::binary(bool value) {}
-
-bool MockStream::got_binary() const {
- return false;
-}
-
-bool MockStream::got_text() const {
- return !got_binary();
-}
-
-void MockStream::write_buffer_bytes(size_t amount) {}
-
-size_t MockStream::write_buffer_bytes() const {
- return 8;
-}
-
-void MockStream::set_option(websocket::stream_base::decorator opt) {}
-
-void MockStream::get_option(websocket::stream_base::timeout &opt) {}
-
-void MockStream::set_option(websocket::stream_base::timeout const &opt) {}
-
-void MockStream::set_option(websocket::permessage_deflate const &o) {}
-
-void MockStream::get_option(websocket::permessage_deflate &o) {}
-
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, void(error_code, tcp::endpoint))
-MockStream::async_connect(tcp::resolver::iterator const &endpoints, RangeConnectHandler &&handler) {
- return async_initiate(
- [](RangeConnectHandler &&handler, MockStream *ms, tcp::resolver::iterator it) {
- tcp::endpoint ep; // TODO: make modifiable.
- post(ms->get_executor(), bind_handler(std::move(handler), ms->ConnectResult(), ep));
- },
- handler,
- this,
- endpoints);
-}
-
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void(error_code))
-MockStream::async_handshake(boost::string_view host, boost::string_view target, HandshakeHandler &&handler) {
- return async_initiate(
- [](HandshakeHandler &&handler, MockStream *ms, string h, string t) {
- post(ms->get_executor(), bind_handler(std::move(handler), ms->HandshakeResult(h, t)));
- },
- handler,
- this,
- host.to_string(),
- target.to_string());
-}
-
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void(error_code, size_t))
-MockStream::async_read(DynamicBuffer &buffer, ReadHandler &&handler) {
- error_code ec;
- size_t size;
- std::tie(ec, size) = ReadResult();
-
- return async_initiate(
- [ec, size](ReadHandler &&handler, MockStream *ms) {
- post(ms->get_executor(), bind_handler(std::move(handler), ec, size));
- },
- handler,
- this);
-}
-
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void(error_code, size_t))
-MockStream::async_write(ConstBufferSequence const &buffers, WriteHandler &&handler) {
- error_code ec;
- size_t size;
- std::tie(ec, size) = ReadResult(); // TODO: Why in async_write?
-
- return async_initiate(
- [ec, size](WriteHandler &&handler, MockStream *ms) {
- post(ms->get_executor(), bind_handler(std::move(handler), ec, size));
- },
- handler,
- this);
-}
-
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void(error_code))
-MockStream::async_ping(websocket::ping_data const &payload, WriteHandler &&handler) {
- return async_initiate(
- [](WriteHandler &&handler, MockStream *ms) {
- post(ms->get_executor(), bind_handler(std::move(handler), ms->PingResult()));
- },
- handler,
- this);
-}
-
-template
-BOOST_ASIO_INITFN_RESULT_TYPE(CloseHandler, void(error_code))
-MockStream::async_close(websocket::close_reason const &cr, CloseHandler &&handler) {
- return async_initiate(
- [](CloseHandler &&handler, MockStream *ms) {
- post(ms->get_executor(), bind_handler(std::move(handler), ms->CloseResult()));
- },
- handler,
- this);
-}
-
-#pragma endregion MockStream
-
-#pragma region TestWebSocket
-
-shared_ptr>
-TestWebSocketResource::SharedFromThis() /*override*/
-{
- return this->shared_from_this();
-}
-
-TestWebSocketResource::TestWebSocketResource(Url &&url) : BaseWebSocketResource(std::move(url)) {
- m_stream = make_unique(m_context);
-}
-
-void TestWebSocketResource::SetConnectResult(function &&resultFunc) {
- m_stream->ConnectResult = std::move(resultFunc);
-}
-
-void TestWebSocketResource::SetHandshakeResult(function &&resultFunc) {
- m_stream->HandshakeResult = std::move(resultFunc);
-}
-
-void TestWebSocketResource::SetCloseResult(function &&resultFunc) {
- m_stream->CloseResult = std::move(resultFunc);
-}
-
-#pragma endregion TestWebSocket
-} // namespace Test
-
-} // namespace Beast
-
-} // namespace Microsoft::React
-
-namespace boost::beast {
-
-Microsoft::React::Beast::Test::MockStream::lowest_layer_type &get_lowest_layer(
- Microsoft::React::Beast::Test::MockStream &s) noexcept {
- return s;
-}
-
-} // namespace boost::beast
diff --git a/vnext/Desktop/BeastWebSocketResource.h b/vnext/Desktop/BeastWebSocketResource.h
deleted file mode 100644
index aba52553e21..00000000000
--- a/vnext/Desktop/BeastWebSocketResource.h
+++ /dev/null
@@ -1,423 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include "IWebSocketResource.h"
-#include "Utils.h"
-
-namespace Microsoft::React {
-
-namespace Beast {
-
-template <
- typename SocketLayer = boost::beast::tcp_stream,
- typename Stream = boost::beast::websocket::stream>
-class BaseWebSocketResource : public IWebSocketResource {
- std::function m_connectHandler;
- std::function m_pingHandler;
- std::function m_writeHandler;
- std::function m_readHandler;
- std::function m_closeHandler;
-
- Url m_url;
- ReadyState m_readyState{ReadyState::Connecting};
- boost::beast::multi_buffer m_bufferIn;
- std::thread m_contextThread;
-
- ///
- /// Must be modified exclusively from the context thread.
- ///
- std::queue> m_writeRequests;
-
- std::atomic_size_t m_pingRequests{0};
- CloseCode m_closeCodeRequest{CloseCode::Normal};
- std::string m_closeReasonRequest;
-
- // Internal status flags.
- std::atomic_bool m_handshakePerformed{false};
- std::atomic_bool m_closeRequested{false};
- std::atomic_bool m_closeInProgress{false};
- std::atomic_bool m_pingInProgress{false};
- std::atomic_bool m_writeInProgress{false};
-
- ///
- /// Add the message to a write queue for eventual sending.
- ///
- ///
- /// Payload to send to the remote endpoint.
- ///
- ///
- /// Indicates whether the payload should be treated as binary data, or text.
- ///
- void EnqueueWrite(const std::string &message, bool binary);
-
- ///
- /// Dequeues a message from m_writeRequests and sends it
- /// asynchronously.
- ///
- void PerformWrite();
-
- ///
- /// If this instance is considered open, post a read request into
- /// m_bufferIn. If there is an incoming message and
- /// m_readHandler is set, call the handler. Then, post new call to this
- /// method to read further incoming data.
- ///
- void PerformRead();
-
- ///
- /// If there are pending ping requests, post an asynchronous ping.
- /// Invoke m_pingHandler if set.
- /// Call this method again if there are still pending requests.
- ///
- void PerformPing();
-
- ///
- /// Set the ready state to Closing.
- /// Post a close request for this stream.
- /// Stop this instance to drop any future read or write requests.
- ///
- void PerformClose();
-
- ///
- /// Synchronizes the context thread and allows the io_context to stop
- /// dispatching tasks.
- ///
- void Stop();
-
- boost::beast::websocket::close_code ToBeastCloseCode(IWebSocketResource::CloseCode closeCode);
-
-#pragma region Async handlers
-
- void OnResolve(boost::beast::error_code ec, typename boost::asio::ip::tcp::resolver::results_type results);
-
- void OnConnect(boost::beast::error_code ec, boost::asio::ip::tcp::resolver::results_type::endpoint_type endpoints);
-
- void OnHandshake(boost::beast::error_code ec);
-
- void OnClose(boost::beast::error_code ec);
-
- void OnRead(boost::beast::error_code ec, std::size_t size);
-
- void OnWrite(boost::beast::error_code ec, std::size_t size);
-
- void OnPing(boost::beast::error_code ec);
-
-#pragma endregion Async handlers
-
- protected:
- ///
- /// See
- /// https://www.boost.org/doc/libs/1_68_0/doc/html/boost_asio/reference/io_context.html.
- ///
- /// Dispatches tasks posted either by
- /// or arbitrary lambdas using boost::asio::post.
- ///
- ///
- /// Tasks will be run in the thread that calls this object's run
- /// method.
- ///
- boost::asio::io_context m_context;
-
- std::unique_ptr> m_workGuard;
- std::unique_ptr m_stream;
- std::function m_errorHandler;
-
- BaseWebSocketResource(Url &&url);
-
- ///
- /// Finalizes the connection setup to the remote endpoint.
- /// Sets the ready state to Open.
- ///
- ///
- /// On callback, invokes the connect handler, if set.
- /// Performs a pending write, if requested during the connection process.
- /// Performs a pending ping call, if requested during the connection process.
- /// Closes this instance, if requested during the connection process.
- ///
- ///
- /// Map of HTTP header fields sent by the remote endpoint.
- ///
- virtual void Handshake();
-
- virtual std::shared_ptr> SharedFromThis() = 0;
-
- public:
- ~BaseWebSocketResource() noexcept override;
-
-#pragma region IWebSocketResource
-
- ///
- ///
- ///
- void Connect(std::string &&url, const Protocols &protocols, const Options &options) noexcept override;
-
- ///
- ///
- ///
- void Ping() noexcept override;
-
- ///
- ///
- ///
- void Send(std::string &&message) noexcept override;
-
- ///
- ///
- ///
- void SendBinary(std::string &&base64String) noexcept override;
-
- ///
- ///
- ///
- void Close(CloseCode code, const std::string &reason) noexcept override;
-
- ReadyState GetReadyState() const noexcept override;
-
- ///
- ///
- ///
- void SetOnConnect(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnPing(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnSend(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnMessage(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnClose(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnError(std::function &&handler) noexcept override;
-
-#pragma endregion IWebSocketResource
-};
-
-class WebSocketResource : public BaseWebSocketResource<>, public std::enable_shared_from_this {
-#pragma region BaseWebSocketResource overrides
-
- std::shared_ptr> SharedFromThis() override;
-
-#pragma endregion BaseWebSocketResource overrides
-
- public:
- WebSocketResource(Url &&url);
-};
-
-class SecureWebSocketResource : public BaseWebSocketResource>,
- public std::enable_shared_from_this {
-#pragma region BaseWebSocketResource overrides
-
- void Handshake() override;
-
- void OnSslHandshake(boost::beast::error_code ec);
-
- std::shared_ptr>> SharedFromThis() override;
-
-#pragma endregion BaseWebSocketResource overrides
-
- public:
- SecureWebSocketResource(Url &&url);
-};
-
-namespace Test {
-
-///
-/// See .
-///
-class MockStream {
- boost::asio::io_context &m_context;
-
- public:
- using next_layer_type = MockStream;
- using lowest_layer_type = MockStream;
- using executor_type = boost::asio::io_context::executor_type;
-
- MockStream(boost::asio::io_context &context);
-
- boost::asio::io_context::executor_type get_executor() noexcept;
-
- // lowest_layer_type &lowest_layer();
-
- // lowest_layer_type const &lowest_layer() const;
-
- void binary(bool value);
-
- bool got_binary() const;
-
- bool got_text() const;
-
- void write_buffer_bytes(std::size_t amount);
-
- std::size_t write_buffer_bytes() const;
-
- void set_option(boost::beast::websocket::stream_base::decorator opt);
-
- void get_option(boost::beast::websocket::stream_base::timeout &opt);
-
- void set_option(boost::beast::websocket::stream_base::timeout const &opt);
-
- void set_option(boost::beast::websocket::permessage_deflate const &o);
-
- void get_option(boost::beast::websocket::permessage_deflate &o);
-
-#pragma region boost::beast::basic_stream mocks
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, void(boost::system::error_code, boost::asio::ip::tcp::endpoint))
- async_connect(boost::asio::ip::tcp::resolver::iterator const &endpoints, RangeConnectHandler &&handler);
-
-#pragma endregion boost::beast::basic_stream mocks
-
-#pragma region boost::beast::websocket::stream mocks
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void(boost::system::error_code))
- async_handshake(boost::beast::string_view host, boost::beast::string_view target, HandshakeHandler &&handler);
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void(boost::system::error_code, std::size_t))
- async_read(DynamicBuffer &buffer, ReadHandler &&handler);
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void(boost::system::error_code, std::size_t))
- async_write(ConstBufferSequence const &buffers, WriteHandler &&handler);
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void(boost::system::error_code))
- async_ping(boost::beast::websocket::ping_data const &payload, WriteHandler &&handler);
-
- template
- BOOST_ASIO_INITFN_RESULT_TYPE(CloseHandler, void(boost::system::error_code))
- async_close(boost::beast::websocket::close_reason const &cr, CloseHandler &&handler);
-
-#pragma endregion boost::beast::websocket::stream mocks
-
- std::function ConnectResult;
- std::function HandshakeResult;
- std::function()> ReadResult;
- std::function()> WriteResult;
- std::function PingResult;
- std::function CloseResult;
-};
-
-class TestWebSocketResource : public BaseWebSocketResource<
- std::nullptr_t, // Unused. MockStream works as its own next/lowest layer.
- MockStream>,
- public std::enable_shared_from_this {
-#pragma region BaseWebSocketResource overrides
-
- std::shared_ptr> SharedFromThis() override;
-
-#pragma endregion BaseWebSocketResource overrides
-
- public:
- TestWebSocketResource(Url &&url);
-
- void SetConnectResult(std::function &&resultFunc);
- void SetHandshakeResult(std::function &&resultFunc);
- void SetCloseResult(std::function &&resultFunc);
-};
-
-} // namespace Test
-
-} // namespace Beast
-
-class BeastWebSocketResource : public IWebSocketResource, public std::enable_shared_from_this {
- std::function m_connectHandler;
- std::function m_pingHandler;
- std::function m_writeHandler;
- std::function m_readHandler;
- std::function m_closeHandler;
- std::function m_errorHandler;
-
- std::shared_ptr m_concreteResource;
-
- public:
- BeastWebSocketResource() noexcept;
-
-#pragma region IWebSocketResource
-
- ///
- ///
- ///
- void Connect(std::string &&url, const Protocols &protocols, const Options &options) noexcept override;
-
- ///
- ///
- ///
- void Ping() noexcept override;
-
- ///
- ///
- ///
- void Send(std::string &&message) noexcept override;
-
- ///
- ///
- ///
- void SendBinary(std::string &&base64String) noexcept override;
-
- ///
- ///
- ///
- void Close(CloseCode code, const std::string &reason) noexcept override;
-
- ReadyState GetReadyState() const noexcept override;
-
- ///
- ///
- ///
- void SetOnConnect(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnPing(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnSend(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnMessage(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnClose(std::function &&handler) noexcept override;
-
- ///
- ///
- ///
- void SetOnError(std::function &&handler) noexcept override;
-
-#pragma endregion IWebSocketResource
-};
-
-} // namespace Microsoft::React
diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj b/vnext/Desktop/React.Windows.Desktop.vcxproj
index 6ec8867b8c6..e2fd63b7a4d 100644
--- a/vnext/Desktop/React.Windows.Desktop.vcxproj
+++ b/vnext/Desktop/React.Windows.Desktop.vcxproj
@@ -52,6 +52,7 @@
true
win32
false
+ true
true
@@ -88,7 +89,6 @@
CORE_ABI - marks ABI elements that are shared between UWP and Win32 DLLs.
-->
- ENABLE_BEAST=$(EnableBeast);
BOOST_ASIO_HAS_IOCP;
_WINSOCK_DEPRECATED_NO_WARNINGS;
_WIN32_WINNT=$(WinVer);
@@ -164,9 +164,6 @@
Create
-
- true
-
@@ -253,7 +250,6 @@
-
diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj.filters b/vnext/Desktop/React.Windows.Desktop.vcxproj.filters
index a3654c5a04b..2a8bc7afef2 100644
--- a/vnext/Desktop/React.Windows.Desktop.vcxproj.filters
+++ b/vnext/Desktop/React.Windows.Desktop.vcxproj.filters
@@ -116,9 +116,6 @@
ABI
-
- Source Files
-
Source Files\CxxReactWin32
@@ -178,9 +175,6 @@
-
- Header Files
-
Header Files
diff --git a/vnext/Desktop/WebSocketResourceFactory.cpp b/vnext/Desktop/WebSocketResourceFactory.cpp
index 8eec4708c50..a20d36f22f7 100644
--- a/vnext/Desktop/WebSocketResourceFactory.cpp
+++ b/vnext/Desktop/WebSocketResourceFactory.cpp
@@ -5,34 +5,22 @@
#include
#include
-#if ENABLE_BEAST
-#include "BeastWebSocketResource.h"
-#endif // ENABLE_BEAST
using std::shared_ptr;
using std::string;
+using winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult;
namespace Microsoft::React::Networking {
#pragma region IWebSocketResource static members
/*static*/
shared_ptr IWebSocketResource::Make() {
-#if ENABLE_BEAST
- if (GetRuntimeOptionBool("UseBeastWebSocket")) {
- return std::make_shared();
- } else {
-#endif // ENABLE_BEAST
- std::vector certExceptions;
- if (GetRuntimeOptionBool("WebSocket.AcceptSelfSigned")) {
- certExceptions.emplace_back(
- winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult::Untrusted);
- certExceptions.emplace_back(
- winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult::InvalidName);
- }
- return std::make_shared(std::move(certExceptions));
-#if ENABLE_BEAST
+ std::vector certExceptions;
+ if (GetRuntimeOptionBool("WebSocket.AcceptSelfSigned")) {
+ certExceptions.emplace_back(ChainValidationResult::Untrusted);
+ certExceptions.emplace_back(ChainValidationResult::InvalidName);
}
-#endif // ENABLE_BEAST
+ return std::make_shared(std::move(certExceptions));
}
#pragma endregion IWebSocketResource static members
diff --git a/vnext/Microsoft.ReactNative/Base/CoreNativeModules.cpp b/vnext/Microsoft.ReactNative/Base/CoreNativeModules.cpp
deleted file mode 100644
index e7cdc886edb..00000000000
--- a/vnext/Microsoft.ReactNative/Base/CoreNativeModules.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-#include "pch.h"
-#include "CoreNativeModules.h"
-
-// Modules
-#include
-#include
-#include
-#include
-#include
-
-// Shared
-#include
-
-namespace Microsoft::ReactNative {
-
-std::vector GetCoreModules(
- const std::shared_ptr &batchingUIMessageQueue,
- const std::shared_ptr
- &jsMessageQueue, // JS engine thread (what we use for external modules)
- Mso::CntPtr &&context) noexcept {
- std::vector modules;
-
- modules.emplace_back(
- "Networking",
- [props = context->Properties()]() { return Microsoft::React::CreateHttpModule(props); },
- jsMessageQueue);
-
- modules.emplace_back(
- Microsoft::React::GetBlobModuleName(),
- [props = context->Properties()]() { return Microsoft::React::CreateBlobModule(props); },
- batchingUIMessageQueue);
-
- modules.emplace_back(
- Microsoft::React::GetFileReaderModuleName(),
- [props = context->Properties()]() { return Microsoft::React::CreateFileReaderModule(props); },
- batchingUIMessageQueue);
-
- return modules;
-}
-
-} // namespace Microsoft::ReactNative
diff --git a/vnext/Microsoft.ReactNative/Base/CoreNativeModules.h b/vnext/Microsoft.ReactNative/Base/CoreNativeModules.h
deleted file mode 100644
index 19533574515..00000000000
--- a/vnext/Microsoft.ReactNative/Base/CoreNativeModules.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-
-namespace facebook::react {
-class AppState;
-struct DevSettings;
-class IUIManager;
-class MessageQueueThread;
-} // namespace facebook::react
-
-namespace Microsoft::ReactNative {
-
-struct DeviceInfo;
-struct IReactInstance;
-struct ViewManagerProvider;
-
-std::vector GetCoreModules(
- const std::shared_ptr &batchingUIMessageQueue,
- const std::shared_ptr &jsMessageQueue,
- Mso::CntPtr &&context) noexcept;
-
-} // namespace Microsoft::ReactNative
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
index f42ba04b5d0..8ed10fc993b 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj
@@ -185,7 +185,6 @@
-
@@ -421,7 +420,6 @@
-
CoreAppPage.xaml
@@ -679,4 +677,4 @@
-
+
\ No newline at end of file
diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
index 02e9b6b23f3..f6e44c0e498 100644
--- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
+++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters
@@ -15,9 +15,6 @@
-
- Base
-
Base
@@ -357,9 +354,6 @@
-
- Base
-
Modules
@@ -632,7 +626,6 @@
Views
-
diff --git a/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp b/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp
index 40a66c542f6..5088179e512 100644
--- a/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp
+++ b/vnext/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp
@@ -6,7 +6,6 @@
#include "MsoUtils.h"
#include
-#include
#include
#include
#include
@@ -30,7 +29,6 @@
#include
#include
#include
-#include
#include
#include "DynamicWriter.h"
#ifndef CORE_ABI
@@ -86,6 +84,7 @@
#include
#include "ChakraRuntimeHolder.h"
+#include
#include
#include "CrashManager.h"
#include "JsiApi.h"
@@ -392,6 +391,16 @@ void ReactInstanceWin::LoadModules(
registerTurboModule(
L"Timing", winrt::Microsoft::ReactNative::MakeTurboModuleProvider<::Microsoft::ReactNative::Timing>());
#endif
+
+ registerTurboModule(::Microsoft::React::GetBlobTurboModuleName(), ::Microsoft::React::GetBlobModuleProvider());
+
+ registerTurboModule(::Microsoft::React::GetHttpTurboModuleName(), ::Microsoft::React::GetHttpModuleProvider());
+
+ registerTurboModule(
+ ::Microsoft::React::GetFileReaderTurboModuleName(), ::Microsoft::React::GetFileReaderModuleProvider());
+
+ registerTurboModule(
+ ::Microsoft::React::GetWebSocketTurboModuleName(), ::Microsoft::React::GetWebSocketModuleProvider());
}
//! Initialize() is called from the native queue.
@@ -459,15 +468,7 @@ void ReactInstanceWin::Initialize() noexcept {
}
};
-#ifdef CORE_ABI
std::vector cxxModules;
-#else
- // Acquire default modules and then populate with custom modules.
- // Note that some of these have custom thread affinity.
- std::vector cxxModules =
- Microsoft::ReactNative::GetCoreModules(m_batchingUIThread, m_jsMessageThread.Load(), m_reactContext);
-#endif
-
auto nmp = std::make_shared();
LoadModules(nmp, m_options.TurboModuleProvider);
diff --git a/vnext/PropertySheets/React.Cpp.props b/vnext/PropertySheets/React.Cpp.props
index 34e8c8c4093..a79bfd7b87d 100644
--- a/vnext/PropertySheets/React.Cpp.props
+++ b/vnext/PropertySheets/React.Cpp.props
@@ -20,9 +20,8 @@
-
- _WIN32_WINNT_WINBLUE
- 0
+
+ _WIN32_WINNT_WIN10
diff --git a/vnext/ReactWindows-Desktop.sln b/vnext/ReactWindows-Desktop.sln
index e27cfaacf8b..5eeb8645d7b 100644
--- a/vnext/ReactWindows-Desktop.sln
+++ b/vnext/ReactWindows-Desktop.sln
@@ -106,20 +106,6 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon.UnitTests", "ReactCommon.UnitTests\ReactCommon.UnitTests.vcxproj", "{B0941079-7441-4A69-868C-FE5EC62C2E9E}"
EndProject
Global
- GlobalSection(SharedMSBuildProjectFiles) = preSolution
- Mso\Mso.vcxitems*{1958ceaa-fbe0-44e3-8a99-90ad85531ffe}*SharedItemsImports = 4
- Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
- Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{44dced9b-9c4c-48fe-8545-0930192bbc16}*SharedItemsImports = 4
- Mso\Mso.vcxitems*{44dced9b-9c4c-48fe-8545-0930192bbc16}*SharedItemsImports = 4
- Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
- Chakra\Chakra.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
- Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
- Mso\Mso.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
- Shared\Shared.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
- Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
- Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
- include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9
- EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
@@ -320,4 +306,19 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C1055EEE-3785-4C0E-8934-FBAA21BFF90C}
EndGlobalSection
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ Mso\Mso.vcxitems*{1958ceaa-fbe0-44e3-8a99-90ad85531ffe}*SharedItemsImports = 4
+ Shared\Shared.vcxitems*{2049dbe9-8d13-42c9-ae4b-413ae38fffd0}*SharedItemsImports = 9
+ Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{44dced9b-9c4c-48fe-8545-0930192bbc16}*SharedItemsImports = 4
+ Mso\Mso.vcxitems*{44dced9b-9c4c-48fe-8545-0930192bbc16}*SharedItemsImports = 4
+ Mso\Mso.vcxitems*{84e05bfa-cbaf-4f0d-bfb6-4ce85742a57e}*SharedItemsImports = 9
+ Chakra\Chakra.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
+ Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
+ Mso\Mso.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
+ Shared\Shared.vcxitems*{95048601-c3dc-475f-adf8-7c0c764c10d5}*SharedItemsImports = 4
+ Chakra\Chakra.vcxitems*{c38970c0-5fbf-4d69-90d8-cbac225ae895}*SharedItemsImports = 9
+ Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{da8b35b3-da00-4b02-bde6-6a397b3fd46b}*SharedItemsImports = 9
+ Microsoft.ReactNative.Cxx\Microsoft.ReactNative.Cxx.vcxitems*{e0d269b4-d7f0-4c4e-92cd-b2c06109a2bb}*SharedItemsImports = 4
+ include\Include.vcxitems*{ef074ba1-2d54-4d49-a28e-5e040b47cd2e}*SharedItemsImports = 9
+ EndGlobalSection
EndGlobal
diff --git a/vnext/Shared/BaseFileReaderResource.cpp b/vnext/Shared/BaseFileReaderResource.cpp
new file mode 100644
index 00000000000..6d3d76f99c3
--- /dev/null
+++ b/vnext/Shared/BaseFileReaderResource.cpp
@@ -0,0 +1,95 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#include "BaseFileReaderResource.h"
+
+// Boost Library
+#include
+#include
+#include
+
+// Windows API
+#include
+
+using std::function;
+using std::shared_ptr;
+using std::string;
+
+namespace Microsoft::React {
+
+#pragma region BaseFileReaderResource
+
+BaseFileReaderResource::BaseFileReaderResource(std::weak_ptr weakBlobPersistor) noexcept
+ : m_weakBlobPersistor{weakBlobPersistor} {}
+
+#pragma region IFileReaderResource
+
+void BaseFileReaderResource::ReadAsText(
+ string &&blobId,
+ int64_t offset,
+ int64_t size,
+ string &&encoding,
+ function &&resolver,
+ function &&rejecter) noexcept /*override*/ {
+ auto persistor = m_weakBlobPersistor.lock();
+ if (!persistor) {
+ return resolver("Could not find Blob persistor");
+ }
+
+ winrt::array_view bytes;
+ try {
+ bytes = persistor->ResolveMessage(std::move(blobId), offset, size);
+ } catch (const std::exception &e) {
+ return rejecter(e.what());
+ }
+
+ // #9982 - Handle non-UTF8 encodings
+ // See https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/nio/charset/Charset.html
+ auto result = string{bytes.cbegin(), bytes.cend()};
+
+ resolver(std::move(result));
+}
+
+void BaseFileReaderResource::ReadAsDataUrl(
+ string &&blobId,
+ int64_t offset,
+ int64_t size,
+ string &&type,
+ function &&resolver,
+ function &&rejecter) noexcept /*override*/ {
+ auto persistor = m_weakBlobPersistor.lock();
+ if (!persistor) {
+ return rejecter("Could not find Blob persistor");
+ }
+
+ winrt::array_view bytes;
+ try {
+ bytes = persistor->ResolveMessage(std::move(blobId), offset, size);
+ } catch (const std::exception &e) {
+ return rejecter(e.what());
+ }
+
+ auto result = string{"data:"};
+ result += type;
+ result += ";base64,";
+
+ // https://www.boost.org/doc/libs/1_76_0/libs/serialization/doc/dataflow.html
+ using namespace boost::archive::iterators;
+ typedef base64_from_binary> encode_base64;
+ std::ostringstream oss;
+ std::copy(encode_base64(bytes.cbegin()), encode_base64(bytes.cend()), ostream_iterator(oss));
+ result += oss.str();
+
+ resolver(std::move(result));
+}
+
+/*static*/ shared_ptr IFileReaderResource::Make(
+ std::weak_ptr weakBlobPersistor) noexcept {
+ return std::make_shared(weakBlobPersistor);
+}
+
+#pragma endregion IFileReaderResource
+
+#pragma endregion BaseFileReaderResource
+
+} // namespace Microsoft::React
diff --git a/vnext/Shared/BaseFileReaderResource.h b/vnext/Shared/BaseFileReaderResource.h
new file mode 100644
index 00000000000..8eb4989e14b
--- /dev/null
+++ b/vnext/Shared/BaseFileReaderResource.h
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "IFileReaderResource.h"
+
+// Standard Library
+#include
+
+namespace Microsoft::React {
+
+class BaseFileReaderResource : public IFileReaderResource, public std::enable_shared_from_this {
+ protected:
+ std::weak_ptr m_weakBlobPersistor;
+
+ public:
+ BaseFileReaderResource(std::weak_ptr weakBlobPersistor) noexcept;
+
+#pragma region IFileReaderResource
+
+ void ReadAsText(
+ std::string &&blobId,
+ int64_t offset,
+ int64_t size,
+ std::string &&encoding,
+ std::function &&resolver,
+ std::function &&rejecter) noexcept override;
+
+ void ReadAsDataUrl(
+ std::string &&blobId,
+ int64_t offset,
+ int64_t size,
+ std::string &&type,
+ std::function &&resolver,
+ std::function &&rejecter) noexcept override;
+
+#pragma endregion IFileReaderResource
+};
+
+} // namespace Microsoft::React
diff --git a/vnext/Shared/CreateModules.h b/vnext/Shared/CreateModules.h
index 535f26e0273..2bc4ed8abfe 100644
--- a/vnext/Shared/CreateModules.h
+++ b/vnext/Shared/CreateModules.h
@@ -5,7 +5,6 @@
// React Native
#include
-#include
// Windows API
#include
@@ -14,12 +13,16 @@
#include
// Forward declarations. Desktop projects can not access
+namespace winrt::Microsoft::ReactNative {
+struct ReactContext;
+struct ReactModuleProvider;
+} // namespace winrt::Microsoft::ReactNative
+
namespace Mso::React {
struct IReactContext;
}
-namespace facebook {
-namespace react {
+namespace facebook::react {
class MessageQueueThread;
@@ -29,11 +32,12 @@ class MessageQueueThread;
extern std::unique_ptr CreateTimingModule(
const std::shared_ptr &nativeThread) noexcept;
-} // namespace react
-} // namespace facebook
+} // namespace facebook::react
namespace Microsoft::React {
+#pragma region CxxModules
+
extern const char *GetHttpModuleName() noexcept;
extern std::unique_ptr CreateHttpModule(
winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept;
@@ -50,4 +54,22 @@ extern const char *GetFileReaderModuleName() noexcept;
extern std::unique_ptr CreateFileReaderModule(
winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept;
+#pragma endregion CxxModules
+
+#pragma region TurboModules
+
+extern const wchar_t *GetBlobTurboModuleName() noexcept;
+extern const winrt::Microsoft::ReactNative::ReactModuleProvider &GetBlobModuleProvider() noexcept;
+
+extern const wchar_t *GetHttpTurboModuleName() noexcept;
+extern const winrt::Microsoft::ReactNative::ReactModuleProvider &GetHttpModuleProvider() noexcept;
+
+extern const wchar_t *GetFileReaderTurboModuleName() noexcept;
+extern const winrt::Microsoft::ReactNative::ReactModuleProvider &GetFileReaderModuleProvider() noexcept;
+
+extern const wchar_t *GetWebSocketTurboModuleName() noexcept;
+extern const winrt::Microsoft::ReactNative::ReactModuleProvider &GetWebSocketModuleProvider() noexcept;
+
+#pragma endregion TurboModules
+
} // namespace Microsoft::React
diff --git a/vnext/Shared/Modules/IBlobPersistor.h b/vnext/Shared/IBlobPersistor.h
similarity index 100%
rename from vnext/Shared/Modules/IBlobPersistor.h
rename to vnext/Shared/IBlobPersistor.h
diff --git a/vnext/Shared/IFileReaderResource.h b/vnext/Shared/IFileReaderResource.h
new file mode 100644
index 00000000000..008db65fa1c
--- /dev/null
+++ b/vnext/Shared/IFileReaderResource.h
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "IBlobPersistor.h"
+
+// Standard Library
+#include
+#include
+
+namespace Microsoft::React {
+
+struct IFileReaderResource {
+ virtual ~IFileReaderResource() noexcept {}
+
+ virtual void ReadAsText(
+ std::string &&blobId,
+ int64_t offset,
+ int64_t size,
+ std::string &&encoding,
+ std::function &&resolver,
+ std::function &&rejecter) noexcept = 0;
+
+ virtual void ReadAsDataUrl(
+ std::string &&blobId,
+ int64_t offset,
+ int64_t size,
+ std::string &&type,
+ std::function &&resolver,
+ std::function &&rejecter) noexcept = 0;
+
+ static std::shared_ptr Make(std::weak_ptr weakBlobPersistor) noexcept;
+};
+
+} // namespace Microsoft::React
diff --git a/vnext/Shared/Modules/BlobModule.cpp b/vnext/Shared/Modules/BlobModule.cpp
index 867e45c0193..4750d3e58a1 100644
--- a/vnext/Shared/Modules/BlobModule.cpp
+++ b/vnext/Shared/Modules/BlobModule.cpp
@@ -3,208 +3,145 @@
#include "BlobModule.h"
+#include
#include
-#include
-#include
-#include
-#include
// React Native
#include
-// Windows API
-#include
-#include
-
-// Standard Library
-#include
-#include
-#include
-
using namespace facebook::xplat;
using folly::dynamic;
-using std::scoped_lock;
-using std::shared_ptr;
+using Microsoft::React::Networking::IBlobResource;
using std::string;
using std::vector;
-using std::weak_ptr;
-using winrt::Microsoft::ReactNative::IReactPropertyBag;
-using winrt::Microsoft::ReactNative::ReactNonAbiValue;
-using winrt::Microsoft::ReactNative::ReactPropertyBag;
-using winrt::Microsoft::ReactNative::ReactPropertyId;
-using winrt::Windows::Foundation::GuidHelper;
using winrt::Windows::Foundation::IInspectable;
-using winrt::Windows::Foundation::Uri;
-using winrt::Windows::Security::Cryptography::CryptographicBuffer;
-namespace fs = std::filesystem;
+namespace msrn = winrt::Microsoft::ReactNative;
namespace {
-constexpr char moduleName[] = "BlobModule";
-constexpr char blobKey[] = "blob";
-constexpr char blobIdKey[] = "blobId";
-constexpr char offsetKey[] = "offset";
-constexpr char sizeKey[] = "size";
-constexpr char typeKey[] = "type";
-constexpr char dataKey[] = "data";
+constexpr char s_moduleName[] = "BlobModule";
+constexpr wchar_t s_moduleNameW[] = L"BlobModule";
+
+const auto &blobKeys = IBlobResource::FieldNames();
+
+msrn::ReactModuleProvider s_moduleProvider = msrn::MakeTurboModuleProvider();
+
} // namespace
namespace Microsoft::React {
-#pragma region BlobModule
+#pragma region BlobTurboModule
-BlobModule::BlobModule(winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept
- : m_sharedState{std::make_shared()},
- m_blobPersistor{std::make_shared()},
- m_contentHandler{std::make_shared(m_blobPersistor)},
- m_requestBodyHandler{std::make_shared(m_blobPersistor)},
- m_responseHandler{std::make_shared(m_blobPersistor)},
- m_inspectableProperties{inspectableProperties} {
- auto propBag = ReactPropertyBag{m_inspectableProperties.try_as()};
-
- auto contentHandlerPropId =
- ReactPropertyId>>{L"BlobModule.ContentHandler"};
- auto contentHandler = weak_ptr{m_contentHandler};
- propBag.Set(contentHandlerPropId, std::move(contentHandler));
-
- auto blobPersistorPropId = ReactPropertyId>>{L"Blob.Persistor"};
- auto blobPersistor = weak_ptr{m_blobPersistor};
- propBag.Set(blobPersistorPropId, std::move(blobPersistor));
-
- m_sharedState->Module = this;
+void BlobTurboModule::Initialize(msrn::ReactContext const &reactContext) noexcept {
+ m_resource = IBlobResource::Make(reactContext.Properties().Handle());
+ m_resource->Callbacks().OnError = [&reactContext](string &&errorText) {
+ Modules::SendEvent(reactContext, L"blobFailed", {errorText});
+ };
+}
+
+ReactNativeSpecs::BlobModuleSpec_Constants BlobTurboModule::GetConstants() noexcept {
+ ReactNativeSpecs::BlobModuleSpec_Constants result;
+ result.BLOB_URI_SCHEME = blobKeys.Blob;
+ result.BLOB_URI_HOST = {};
+
+ return result;
+}
+
+void BlobTurboModule::AddNetworkingHandler() noexcept {
+ m_resource->AddNetworkingHandler();
+}
+
+void BlobTurboModule::AddWebSocketHandler(double id) noexcept {
+ m_resource->AddWebSocketHandler(static_cast(id));
+}
+
+void BlobTurboModule::RemoveWebSocketHandler(double id) noexcept {
+ m_resource->RemoveWebSocketHandler(static_cast(id));
+}
+
+void BlobTurboModule::SendOverSocket(msrn::JSValue &&blob, double socketID) noexcept {
+ m_resource->SendOverSocket(
+ blob[blobKeys.BlobId].AsString(),
+ blob[blobKeys.Offset].AsInt64(),
+ blob[blobKeys.Size].AsInt64(),
+ static_cast(socketID));
+}
+
+void BlobTurboModule::CreateFromParts(vector &&parts, string &&withId) noexcept {
+ m_resource->CreateFromParts(std::move(parts), std::move(withId));
}
-BlobModule::~BlobModule() noexcept /*override*/ {
- m_sharedState->Module = nullptr;
+void BlobTurboModule::Release(string &&blobId) noexcept {
+ m_resource->Release(std::move(blobId));
}
+#pragma endregion BlobTurboModule
+
+#pragma region BlobModule
+
+BlobModule::BlobModule(winrt::Windows::Foundation::IInspectable const &inspectableProperties) noexcept
+ : m_resource{IBlobResource::Make(inspectableProperties)} {}
+
#pragma region CxxModule
string BlobModule::getName() {
- return moduleName;
+ return s_moduleName;
}
std::map BlobModule::getConstants() {
- return {{"BLOB_URI_SCHEME", blobKey}, {"BLOB_URI_HOST", {}}};
+ return {{"BLOB_URI_SCHEME", blobKeys.Blob}, {"BLOB_URI_HOST", {}}};
}
vector BlobModule::getMethods() {
+ // See CxxNativeModule::lazyInit()
+ m_resource->Callbacks().OnError = [weakInstance = getInstance()](string &&errorText) {
+ Modules::SendEvent(weakInstance, "blobFailed", std::move(errorText));
+ };
+
return {
- {"addNetworkingHandler",
- [propBag = ReactPropertyBag{m_inspectableProperties.try_as()},
- requestBodyHandler = m_requestBodyHandler,
- responseHandler = m_responseHandler](dynamic args) {
- auto propId = ReactPropertyId>>{L"HttpModule.Proxy"};
-
- if (auto prop = propBag.Get(propId)) {
- if (auto httpHandler = prop.Value().lock()) {
- httpHandler->AddRequestBodyHandler(requestBodyHandler);
- httpHandler->AddResponseHandler(responseHandler);
- }
- }
- // TODO: else emit error?
- }},
+ {"addNetworkingHandler", [resource = m_resource](dynamic /*args*/) { resource->AddNetworkingHandler(); }},
{"addWebSocketHandler",
- [contentHandler = m_contentHandler](dynamic args) {
+ [resource = m_resource](dynamic args) {
auto id = jsArgAsInt(args, 0);
- contentHandler->Register(id);
+ resource->AddWebSocketHandler(id);
}},
{"removeWebSocketHandler",
- [contentHandler = m_contentHandler](dynamic args) {
+ [resource = m_resource](dynamic args) {
auto id = jsArgAsInt(args, 0);
- contentHandler->Unregister(id);
+ resource->RemoveWebSocketHandler(id);
}},
{"sendOverSocket",
- [weakState = weak_ptr(m_sharedState),
- persistor = m_blobPersistor,
- propBag = ReactPropertyBag{m_inspectableProperties.try_as()}](dynamic args) {
- auto propId = ReactPropertyId>>{L"WebSocketModule.Proxy"};
- shared_ptr wsProxy;
- if (auto prop = propBag.Get(propId)) {
- wsProxy = prop.Value().lock();
- }
- if (!wsProxy) {
- return;
- }
-
+ [resource = m_resource](dynamic args) {
auto blob = jsArgAsObject(args, 0);
- auto blobId = blob[blobIdKey].getString();
- auto offset = blob[offsetKey].getInt();
- auto size = blob[sizeKey].getInt();
- auto socketID = jsArgAsInt(args, 1);
-
- winrt::array_view data;
- try {
- data = persistor->ResolveMessage(std::move(blobId), offset, size);
- } catch (const std::exception &e) {
- if (auto sharedState = weakState.lock()) {
- Modules::SendEvent(sharedState->Module->getInstance(), "blobFailed", e.what());
- }
- return;
- }
-
- auto buffer = CryptographicBuffer::CreateFromByteArray(data);
- auto winrtString = CryptographicBuffer::EncodeToBase64String(std::move(buffer));
- auto base64String = Common::Unicode::Utf16ToUtf8(std::move(winrtString));
-
- wsProxy->SendBinary(std::move(base64String), socketID);
+ auto blobId = blob[blobKeys.BlobId].getString();
+ auto offset = blob[blobKeys.Offset].getInt();
+ auto size = blob[blobKeys.Size].getInt();
+ auto socketId = jsArgAsInt(args, 1);
+
+ resource->SendOverSocket(std::move(blobId), offset, size, socketId);
}},
{"createFromParts",
- // As of React Native 0.67, instance is set AFTER CxxModule::getMethods() is invoked.
- // Use getInstance() directly once
- // https://github.com/facebook/react-native/commit/1d45b20b6c6ba66df0485cdb9be36463d96cf182 becomes available.
- [persistor = m_blobPersistor, weakState = weak_ptr(m_sharedState)](dynamic args) {
- auto parts = jsArgAsArray(args, 0); // Array