react-native-windows 0.74.36 → 0.74.37
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/Microsoft.ReactNative/Fabric/AbiViewProps.cpp +8 -10
- package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +41 -37
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/HostPlatformColor.h +3 -8
- package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorParser.h +0 -1
- package/Microsoft.ReactNative.Cxx/NativeModules.h +9 -0
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/Shared/Networking/WinRTWebSocketResource.cpp +371 -6
- package/Shared/Networking/WinRTWebSocketResource.h +118 -0
- package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +6 -6
- package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +6 -6
- package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +6 -6
- package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +6 -6
- package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +6 -6
- package/codegen/react/components/rnwcore/AndroidSwitch.g.h +6 -6
- package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +6 -6
- package/codegen/react/components/rnwcore/InputAccessory.g.h +6 -6
- package/codegen/react/components/rnwcore/ModalHostView.g.h +6 -6
- package/codegen/react/components/rnwcore/PullToRefreshView.g.h +6 -6
- package/codegen/react/components/rnwcore/SafeAreaView.g.h +6 -6
- package/codegen/react/components/rnwcore/Switch.g.h +6 -6
- package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +6 -6
- package/package.json +3 -3
|
@@ -77,14 +77,12 @@ winrt::Microsoft::ReactNative::Color Color::ReadValue(
|
|
|
77
77
|
switch (reader.ValueType()) {
|
|
78
78
|
case JSValueType::Int64: {
|
|
79
79
|
auto argb = reader.GetInt64();
|
|
80
|
-
return winrt::make<Color>(facebook::react::Color{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
static_cast<uint8_t>(argb & 0xFF)},
|
|
87
|
-
{}});
|
|
80
|
+
return winrt::make<Color>(facebook::react::Color{/*color*/
|
|
81
|
+
{static_cast<uint8_t>((argb >> 24) & 0xFF),
|
|
82
|
+
static_cast<uint8_t>((argb >> 16) & 0xFF),
|
|
83
|
+
static_cast<uint8_t>((argb >> 8) & 0xFF),
|
|
84
|
+
static_cast<uint8_t>(argb & 0xFF)},
|
|
85
|
+
{}});
|
|
88
86
|
}
|
|
89
87
|
case JSValueType::Object: {
|
|
90
88
|
std::vector<std::string> platformColors;
|
|
@@ -96,10 +94,10 @@ winrt::Microsoft::ReactNative::Color Color::ReadValue(
|
|
|
96
94
|
SkipValue<JSValue>(reader); // Skip this property
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
|
-
return winrt::make<Color>(facebook::react::Color{/*
|
|
97
|
+
return winrt::make<Color>(facebook::react::Color{/*color*/ {}, std::move(platformColors)});
|
|
100
98
|
}
|
|
101
99
|
default:
|
|
102
|
-
return winrt::make<Color>(facebook::react::Color{/*
|
|
100
|
+
return winrt::make<Color>(facebook::react::Color{/*color*/ {0, 0, 0, 0}, {}});
|
|
103
101
|
}
|
|
104
102
|
}
|
|
105
103
|
|
|
@@ -183,7 +183,7 @@ void ComponentView::updateProps(
|
|
|
183
183
|
updateShadowProps(oldViewProps, newViewProps);
|
|
184
184
|
}
|
|
185
185
|
if (oldViewProps.tooltip != newViewProps.tooltip) {
|
|
186
|
-
if (!m_tooltipTracked && newViewProps.tooltip) {
|
|
186
|
+
if (!m_tooltipTracked && newViewProps.tooltip && !newViewProps.tooltip->empty()) {
|
|
187
187
|
TooltipService::GetCurrent(m_reactContext.Properties())->StartTracking(*this);
|
|
188
188
|
m_tooltipTracked = true;
|
|
189
189
|
} else if (m_tooltipTracked && !newViewProps.tooltip) {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#include <react/renderer/core/LayoutConstraints.h>
|
|
11
11
|
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
|
|
12
12
|
#include <winrt/Microsoft.ReactNative.Composition.h>
|
|
13
|
+
#include <winrt/Windows.UI.ViewManagement.h>
|
|
13
14
|
#include "TextDrawing.h"
|
|
14
15
|
#include "dwmapi.h"
|
|
15
16
|
|
|
@@ -49,7 +50,9 @@ facebook::react::AttributedStringBox CreateTooltipAttributedString(const std::st
|
|
|
49
50
|
auto fragment = facebook::react::AttributedString::Fragment{};
|
|
50
51
|
fragment.string = tooltip;
|
|
51
52
|
fragment.textAttributes.fontSize = tooltipFontSize;
|
|
52
|
-
|
|
53
|
+
fragment.textAttributes.fontSizeMultiplier =
|
|
54
|
+
static_cast<float>(winrt::Windows::UI::ViewManagement::UISettings().TextScaleFactor());
|
|
55
|
+
attributedString.appendFragment(std::move(fragment));
|
|
53
56
|
return facebook::react::AttributedStringBox{attributedString};
|
|
54
57
|
}
|
|
55
58
|
|
|
@@ -231,14 +234,13 @@ void TooltipTracker::OnUnmounted(
|
|
|
231
234
|
}
|
|
232
235
|
|
|
233
236
|
void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentView &view) noexcept {
|
|
234
|
-
auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
|
|
235
|
-
|
|
236
|
-
auto selfView =
|
|
237
|
-
winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
|
|
238
|
-
auto parentHwnd = selfView->GetHwndForParenting();
|
|
239
237
|
DestroyTimer();
|
|
240
238
|
|
|
241
239
|
if (!m_hwndTip) {
|
|
240
|
+
auto viewCompView = view.as<winrt::Microsoft::ReactNative::Composition::ViewComponentView>();
|
|
241
|
+
auto selfView =
|
|
242
|
+
winrt::get_self<winrt::Microsoft::ReactNative::Composition::implementation::ViewComponentView>(viewCompView);
|
|
243
|
+
auto parentHwnd = selfView->GetHwndForParenting();
|
|
242
244
|
auto tooltipData = std::make_unique<TooltipData>(view);
|
|
243
245
|
tooltipData->attributedString = CreateTooltipAttributedString(*selfView->viewProps()->tooltip);
|
|
244
246
|
|
|
@@ -256,37 +258,39 @@ void TooltipTracker::ShowTooltip(const winrt::Microsoft::ReactNative::ComponentV
|
|
|
256
258
|
facebook::react::TextLayoutManager::GetTextLayout(
|
|
257
259
|
tooltipData->attributedString, {} /*paragraphAttributes*/, layoutConstraints, tooltipData->textLayout);
|
|
258
260
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
261
|
+
if (tooltipData->textLayout) {
|
|
262
|
+
DWRITE_TEXT_METRICS tm;
|
|
263
|
+
winrt::check_hresult(tooltipData->textLayout->GetMetrics(&tm));
|
|
264
|
+
|
|
265
|
+
tooltipData->width =
|
|
266
|
+
static_cast<int>((tm.width + tooltipHorizontalPadding + tooltipHorizontalPadding) * scaleFactor);
|
|
267
|
+
tooltipData->height = static_cast<int>((tm.height + tooltipTopPadding + tooltipBottomPadding) * scaleFactor);
|
|
268
|
+
|
|
269
|
+
POINT pt = {static_cast<LONG>(m_pos.X), static_cast<LONG>(m_pos.Y)};
|
|
270
|
+
ClientToScreen(parentHwnd, &pt);
|
|
271
|
+
|
|
272
|
+
RegisterTooltipWndClass();
|
|
273
|
+
HINSTANCE hInstance = GetModuleHandle(NULL);
|
|
274
|
+
m_hwndTip = CreateWindow(
|
|
275
|
+
c_tooltipWindowClassName,
|
|
276
|
+
L"Tooltip",
|
|
277
|
+
WS_POPUP,
|
|
278
|
+
pt.x - tooltipData->width / 2,
|
|
279
|
+
static_cast<int>(pt.y - tooltipData->height - (toolTipPlacementMargin * scaleFactor)),
|
|
280
|
+
tooltipData->width,
|
|
281
|
+
tooltipData->height,
|
|
282
|
+
parentHwnd,
|
|
283
|
+
NULL,
|
|
284
|
+
hInstance,
|
|
285
|
+
tooltipData.get());
|
|
286
|
+
|
|
287
|
+
DWM_WINDOW_CORNER_PREFERENCE preference = DWMWCP_ROUNDSMALL;
|
|
288
|
+
UINT borderThickness = 0;
|
|
289
|
+
DwmSetWindowAttribute(m_hwndTip, DWMWA_WINDOW_CORNER_PREFERENCE, &preference, sizeof(preference));
|
|
290
|
+
|
|
291
|
+
tooltipData.release();
|
|
292
|
+
AnimateWindow(m_hwndTip, toolTipAnimationTimeMs, AW_BLEND);
|
|
293
|
+
}
|
|
290
294
|
}
|
|
291
295
|
}
|
|
292
296
|
|
|
@@ -12,13 +12,10 @@ namespace facebook::react {
|
|
|
12
12
|
|
|
13
13
|
struct Color {
|
|
14
14
|
bool operator==(const Color &otherColor) const {
|
|
15
|
-
return
|
|
16
|
-
(m_isUndefined == otherColor.m_isUndefined && m_color == otherColor.m_color &&
|
|
17
|
-
m_platformColor == otherColor.m_platformColor);
|
|
15
|
+
return m_color == otherColor.m_color && m_platformColor == otherColor.m_platformColor;
|
|
18
16
|
}
|
|
19
17
|
bool operator!=(const Color &otherColor) const {
|
|
20
|
-
return
|
|
21
|
-
m_platformColor != otherColor.m_platformColor;
|
|
18
|
+
return m_color != otherColor.m_color || m_platformColor != otherColor.m_platformColor;
|
|
22
19
|
}
|
|
23
20
|
|
|
24
21
|
winrt::Windows::UI::Color AsWindowsColor() const {
|
|
@@ -36,13 +33,12 @@ struct Color {
|
|
|
36
33
|
return RGB(m_color.R, m_color.G, m_color.B) | (m_color.A << 24);
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
bool m_isUndefined;
|
|
40
36
|
winrt::Windows::UI::Color m_color;
|
|
41
37
|
std::vector<std::string> m_platformColor;
|
|
42
38
|
};
|
|
43
39
|
|
|
44
40
|
namespace HostPlatformColor {
|
|
45
|
-
static const facebook::react::Color UndefinedColor{
|
|
41
|
+
static const facebook::react::Color UndefinedColor{{0, 0, 0, 0} /*Black*/, {} /*Empty PlatformColors*/};
|
|
46
42
|
} // namespace HostPlatformColor
|
|
47
43
|
|
|
48
44
|
inline Color hostPlatformColorFromComponents(ColorComponents components) {
|
|
@@ -53,7 +49,6 @@ inline Color hostPlatformColorFromComponents(ColorComponents components) {
|
|
|
53
49
|
static_cast<uint8_t>((int)round(components.green * ratio) & 0xff),
|
|
54
50
|
static_cast<uint8_t>((int)round(components.blue * ratio) & 0xff)};
|
|
55
51
|
return {
|
|
56
|
-
/* .m_isUndefined = */ false,
|
|
57
52
|
/* .m_color = */ color,
|
|
58
53
|
/* .m_platformColor = */ {}};
|
|
59
54
|
}
|
|
@@ -19,7 +19,6 @@ parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId,
|
|
|
19
19
|
auto map = (std::unordered_map<std::string, std::vector<std::string>>)value;
|
|
20
20
|
if (map.find("windowsbrush") != map.end()) {
|
|
21
21
|
facebook::react::Color color = {
|
|
22
|
-
/* .m_isDefined = */ true,
|
|
23
22
|
/* .m_color = */ {},
|
|
24
23
|
/* .m_platformColor = */ std::move(map["windowsbrush"]),
|
|
25
24
|
};
|
|
@@ -1360,6 +1360,15 @@ inline ReactModuleProvider MakeTurboModuleProvider() noexcept {
|
|
|
1360
1360
|
return MakeModuleProvider<TModule>();
|
|
1361
1361
|
}
|
|
1362
1362
|
|
|
1363
|
+
// Clang does not allow a virtual function address to be a constexpr statement
|
|
1364
|
+
#if !defined(CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS)
|
|
1365
|
+
#if defined(__clang__)
|
|
1366
|
+
#define CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS
|
|
1367
|
+
#else
|
|
1368
|
+
#define CONSTEXPR_SUPPORTED_ON_VIRTUAL_FN_ADDRESS constexpr
|
|
1369
|
+
#endif
|
|
1370
|
+
#endif
|
|
1371
|
+
|
|
1363
1372
|
} // namespace winrt::Microsoft::ReactNative
|
|
1364
1373
|
|
|
1365
1374
|
namespace React {
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
-->
|
|
11
11
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
12
12
|
<PropertyGroup>
|
|
13
|
-
<ReactNativeWindowsVersion>0.74.
|
|
13
|
+
<ReactNativeWindowsVersion>0.74.37</ReactNativeWindowsVersion>
|
|
14
14
|
<ReactNativeWindowsMajor>0</ReactNativeWindowsMajor>
|
|
15
15
|
<ReactNativeWindowsMinor>74</ReactNativeWindowsMinor>
|
|
16
|
-
<ReactNativeWindowsPatch>
|
|
16
|
+
<ReactNativeWindowsPatch>37</ReactNativeWindowsPatch>
|
|
17
17
|
<ReactNativeWindowsCanary>false</ReactNativeWindowsCanary>
|
|
18
|
-
<ReactNativeWindowsCommitId>
|
|
18
|
+
<ReactNativeWindowsCommitId>4ad063f22757b42a70478b2c145520e621fd2bf5</ReactNativeWindowsCommitId>
|
|
19
19
|
</PropertyGroup>
|
|
20
20
|
</Project>
|
|
@@ -21,16 +21,18 @@
|
|
|
21
21
|
|
|
22
22
|
using Microsoft::Common::Utilities::CheckedReinterpretCast;
|
|
23
23
|
|
|
24
|
+
using Mso::DispatchQueue;
|
|
25
|
+
|
|
24
26
|
using std::function;
|
|
25
27
|
using std::lock_guard;
|
|
26
28
|
using std::mutex;
|
|
27
|
-
using std::size_t;
|
|
28
29
|
using std::string;
|
|
29
30
|
using std::vector;
|
|
30
31
|
|
|
31
32
|
using winrt::fire_and_forget;
|
|
32
33
|
using winrt::hresult;
|
|
33
34
|
using winrt::hresult_error;
|
|
35
|
+
using winrt::hstring;
|
|
34
36
|
using winrt::resume_background;
|
|
35
37
|
using winrt::resume_on_signal;
|
|
36
38
|
using winrt::Windows::Foundation::IAsyncAction;
|
|
@@ -38,6 +40,7 @@ using winrt::Windows::Foundation::Uri;
|
|
|
38
40
|
using winrt::Windows::Networking::Sockets::IMessageWebSocket;
|
|
39
41
|
using winrt::Windows::Networking::Sockets::IMessageWebSocketMessageReceivedEventArgs;
|
|
40
42
|
using winrt::Windows::Networking::Sockets::IWebSocket;
|
|
43
|
+
using winrt::Windows::Networking::Sockets::IWebSocketClosedEventArgs;
|
|
41
44
|
using winrt::Windows::Networking::Sockets::MessageWebSocket;
|
|
42
45
|
using winrt::Windows::Networking::Sockets::SocketMessageType;
|
|
43
46
|
using winrt::Windows::Networking::Sockets::WebSocketClosedEventArgs;
|
|
@@ -54,9 +57,9 @@ namespace {
|
|
|
54
57
|
///
|
|
55
58
|
/// Implements an awaiter for Mso::DispatchQueue
|
|
56
59
|
///
|
|
57
|
-
auto resume_in_queue(const
|
|
60
|
+
auto resume_in_queue(const DispatchQueue &queue) noexcept {
|
|
58
61
|
struct awaitable {
|
|
59
|
-
awaitable(const
|
|
62
|
+
awaitable(const DispatchQueue &queue) noexcept : m_queue{queue} {}
|
|
60
63
|
|
|
61
64
|
bool await_ready() const noexcept {
|
|
62
65
|
return false;
|
|
@@ -79,10 +82,367 @@ auto resume_in_queue(const Mso::DispatchQueue &queue) noexcept {
|
|
|
79
82
|
return awaitable{queue};
|
|
80
83
|
} // resume_in_queue
|
|
81
84
|
|
|
85
|
+
DispatchQueue GetCurrentOrSerialQueue() noexcept {
|
|
86
|
+
auto queue = DispatchQueue::CurrentQueue();
|
|
87
|
+
if (!queue)
|
|
88
|
+
queue = DispatchQueue::MakeSerialQueue();
|
|
89
|
+
|
|
90
|
+
return queue;
|
|
91
|
+
}
|
|
92
|
+
|
|
82
93
|
} // namespace
|
|
83
94
|
|
|
84
95
|
namespace Microsoft::React::Networking {
|
|
85
96
|
|
|
97
|
+
#pragma region WinRTWebSocketResource2
|
|
98
|
+
|
|
99
|
+
WinRTWebSocketResource2::WinRTWebSocketResource2(
|
|
100
|
+
IMessageWebSocket &&socket,
|
|
101
|
+
IDataWriter &&writer,
|
|
102
|
+
vector<ChainValidationResult> &&certExceptions,
|
|
103
|
+
DispatchQueue callingQueue)
|
|
104
|
+
: m_socket{std::move(socket)},
|
|
105
|
+
m_writer(std::move(writer)),
|
|
106
|
+
m_readyState{ReadyState::Connecting},
|
|
107
|
+
m_connectPerformed{CreateEvent(/*attributes*/ nullptr, /*manual reset*/ true, /*state*/ false, /*name*/ nullptr)},
|
|
108
|
+
m_callingQueue{callingQueue} {
|
|
109
|
+
for (const auto &certException : certExceptions) {
|
|
110
|
+
m_socket.Control().IgnorableServerCertificateErrors().Append(certException);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// private
|
|
115
|
+
WinRTWebSocketResource2::WinRTWebSocketResource2(
|
|
116
|
+
IMessageWebSocket &&socket,
|
|
117
|
+
vector<ChainValidationResult> &&certExceptions)
|
|
118
|
+
: WinRTWebSocketResource2(
|
|
119
|
+
std::move(socket),
|
|
120
|
+
DataWriter{socket.OutputStream()},
|
|
121
|
+
std::move(certExceptions),
|
|
122
|
+
GetCurrentOrSerialQueue()) {}
|
|
123
|
+
|
|
124
|
+
WinRTWebSocketResource2::WinRTWebSocketResource2(vector<ChainValidationResult> &&certExceptions)
|
|
125
|
+
: WinRTWebSocketResource2(MessageWebSocket{}, std::move(certExceptions)) {}
|
|
126
|
+
|
|
127
|
+
WinRTWebSocketResource2::~WinRTWebSocketResource2() noexcept /*override*/
|
|
128
|
+
{}
|
|
129
|
+
|
|
130
|
+
void WinRTWebSocketResource2::Fail(string &&message, ErrorType type) noexcept {
|
|
131
|
+
auto self = shared_from_this();
|
|
132
|
+
|
|
133
|
+
self->m_backgroundQueue.Post([self, message = std::move(message), type]() {
|
|
134
|
+
self->m_readyState = ReadyState::Closed;
|
|
135
|
+
self->m_callingQueue.Post([self, message = std::move(message), type]() {
|
|
136
|
+
if (self->m_errorHandler) {
|
|
137
|
+
self->m_errorHandler({std::move(message), type});
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
void WinRTWebSocketResource2::Fail(hresult &&error, ErrorType type) noexcept {
|
|
144
|
+
Fail(Utilities::HResultToString(std::move(error)), type);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
void WinRTWebSocketResource2::Fail(hresult_error const &error, ErrorType type) noexcept {
|
|
148
|
+
Fail(Utilities::HResultToString(error), type);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
void WinRTWebSocketResource2::OnMessageReceived(
|
|
152
|
+
IMessageWebSocket const &,
|
|
153
|
+
IMessageWebSocketMessageReceivedEventArgs const &args) {
|
|
154
|
+
auto self = shared_from_this();
|
|
155
|
+
string response;
|
|
156
|
+
|
|
157
|
+
IDataReader reader{nullptr};
|
|
158
|
+
// Use WinRT ABI to avoid throwing exceptions on expected code paths
|
|
159
|
+
HRESULT hr =
|
|
160
|
+
reinterpret_cast<ABI::Windows::Networking::Sockets::IMessageWebSocketMessageReceivedEventArgs *>(
|
|
161
|
+
winrt::get_abi(args))
|
|
162
|
+
->GetDataReader(reinterpret_cast<ABI::Windows::Storage::Streams::IDataReader **>(winrt::put_abi(reader)));
|
|
163
|
+
|
|
164
|
+
if (FAILED(hr)) {
|
|
165
|
+
string errorMessage;
|
|
166
|
+
ErrorType errorType;
|
|
167
|
+
// See
|
|
168
|
+
// https://docs.microsoft.com/uwp/api/windows.networking.sockets.messagewebsocketmessagereceivedeventargs.getdatareader?view=winrt-22621#remarks
|
|
169
|
+
if (hr == WININET_E_CONNECTION_ABORTED) {
|
|
170
|
+
errorMessage = "[0x80072EFE] Underlying TCP connection suddenly terminated";
|
|
171
|
+
errorType = ErrorType::Connection;
|
|
172
|
+
// Note: It is not clear whether all read-related errors should close the socket.
|
|
173
|
+
Close(CloseCode::BadPayload, std::move(errorMessage));
|
|
174
|
+
} else {
|
|
175
|
+
errorMessage = Utilities::HResultToString(hr);
|
|
176
|
+
errorType = ErrorType::Receive;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
self->Fail(std::move(errorMessage), errorType);
|
|
180
|
+
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
auto len = reader.UnconsumedBufferLength();
|
|
186
|
+
if (args.MessageType() == SocketMessageType::Utf8) {
|
|
187
|
+
reader.UnicodeEncoding(UnicodeEncoding::Utf8);
|
|
188
|
+
vector<uint8_t> data(len);
|
|
189
|
+
reader.ReadBytes(data);
|
|
190
|
+
|
|
191
|
+
response = string(CheckedReinterpretCast<char *>(data.data()), data.size());
|
|
192
|
+
} else {
|
|
193
|
+
auto buffer = reader.ReadBuffer(len);
|
|
194
|
+
auto data = CryptographicBuffer::EncodeToBase64String(buffer);
|
|
195
|
+
|
|
196
|
+
response = winrt::to_string(std::wstring_view(data));
|
|
197
|
+
}
|
|
198
|
+
} catch (hresult_error const &e) {
|
|
199
|
+
return self->Fail(e, ErrorType::Receive);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Posting inside try-catch block causes errors.
|
|
203
|
+
self->m_callingQueue.Post([self, response = std::move(response), messageType = args.MessageType()]() {
|
|
204
|
+
if (self->m_readHandler) {
|
|
205
|
+
self->m_readHandler(response.length(), response, messageType == SocketMessageType::Binary);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
void WinRTWebSocketResource2::OnClosed(IWebSocket const &sender, IWebSocketClosedEventArgs const &args) {
|
|
211
|
+
auto self = shared_from_this();
|
|
212
|
+
|
|
213
|
+
self->m_backgroundQueue.Post([self]() { self->m_readyState = ReadyState::Closed; });
|
|
214
|
+
|
|
215
|
+
self->m_callingQueue.Post([self]() {
|
|
216
|
+
if (self->m_closeHandler) {
|
|
217
|
+
self->m_closeHandler(self->m_closeCode, self->m_closeReason);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
fire_and_forget WinRTWebSocketResource2::PerformConnect(Uri &&uri) noexcept {
|
|
223
|
+
auto self = shared_from_this();
|
|
224
|
+
auto coUri = std::move(uri);
|
|
225
|
+
|
|
226
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
227
|
+
|
|
228
|
+
auto async = self->m_socket.ConnectAsync(coUri);
|
|
229
|
+
co_await lessthrow_await_adapter<IAsyncAction>{async};
|
|
230
|
+
|
|
231
|
+
co_await resume_in_queue(self->m_callingQueue);
|
|
232
|
+
|
|
233
|
+
auto result = async.ErrorCode();
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
if (result >= 0) { // Non-failing HRESULT
|
|
237
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
238
|
+
self->m_readyState = ReadyState::Open;
|
|
239
|
+
|
|
240
|
+
co_await resume_in_queue(self->m_callingQueue);
|
|
241
|
+
if (self->m_connectHandler) {
|
|
242
|
+
self->m_connectHandler();
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
self->Fail(std::move(result), ErrorType::Connection);
|
|
246
|
+
}
|
|
247
|
+
} catch (hresult_error const &e) {
|
|
248
|
+
self->Fail(e, ErrorType::Connection);
|
|
249
|
+
} catch (std::exception const &e) {
|
|
250
|
+
self->Fail(e.what(), ErrorType::Connection);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
SetEvent(self->m_connectPerformed.get());
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
fire_and_forget WinRTWebSocketResource2::PerformClose() noexcept {
|
|
257
|
+
auto self = shared_from_this();
|
|
258
|
+
|
|
259
|
+
co_await resume_on_signal(self->m_connectPerformed.get());
|
|
260
|
+
|
|
261
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
262
|
+
|
|
263
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close
|
|
264
|
+
co_await self->SendPendingMessages();
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
self->m_socket.Close(static_cast<uint16_t>(m_closeCode), winrt::to_hstring(m_closeReason));
|
|
268
|
+
self->m_readyState = ReadyState::Closing;
|
|
269
|
+
} catch (winrt::hresult_invalid_argument const &e) {
|
|
270
|
+
Fail(e, ErrorType::Close);
|
|
271
|
+
} catch (hresult_error const &e) {
|
|
272
|
+
Fail(e, ErrorType::Close);
|
|
273
|
+
} catch (const std::exception &e) {
|
|
274
|
+
Fail(e.what(), ErrorType::Close);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
fire_and_forget WinRTWebSocketResource2::PerformWrite(string &&message, bool isBinary) noexcept {
|
|
279
|
+
auto self = shared_from_this();
|
|
280
|
+
string coMessage = std::move(message);
|
|
281
|
+
|
|
282
|
+
co_await resume_in_queue(self->m_backgroundQueue); // Ensure writes happen sequentially
|
|
283
|
+
self->m_outgoingMessages.emplace(std::move(coMessage), isBinary);
|
|
284
|
+
|
|
285
|
+
co_await resume_on_signal(self->m_connectPerformed.get());
|
|
286
|
+
|
|
287
|
+
co_await resume_in_queue(self->m_backgroundQueue);
|
|
288
|
+
|
|
289
|
+
co_await self->SendPendingMessages();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
IAsyncAction WinRTWebSocketResource2::SendPendingMessages() noexcept {
|
|
293
|
+
auto self = shared_from_this();
|
|
294
|
+
|
|
295
|
+
while (!self->m_outgoingMessages.empty()) {
|
|
296
|
+
if (self->m_readyState != ReadyState::Open) {
|
|
297
|
+
co_return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
size_t length = 0;
|
|
301
|
+
string messageLocal;
|
|
302
|
+
bool isBinaryLocal;
|
|
303
|
+
try {
|
|
304
|
+
std::tie(messageLocal, isBinaryLocal) = self->m_outgoingMessages.front();
|
|
305
|
+
self->m_outgoingMessages.pop();
|
|
306
|
+
if (isBinaryLocal) {
|
|
307
|
+
self->m_socket.Control().MessageType(SocketMessageType::Binary);
|
|
308
|
+
|
|
309
|
+
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(messageLocal));
|
|
310
|
+
if (buffer) {
|
|
311
|
+
length = buffer.Length();
|
|
312
|
+
self->m_writer.WriteBuffer(buffer);
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
self->m_socket.Control().MessageType(SocketMessageType::Utf8);
|
|
316
|
+
|
|
317
|
+
length = messageLocal.size();
|
|
318
|
+
winrt::array_view<const uint8_t> view(
|
|
319
|
+
CheckedReinterpretCast<const uint8_t *>(messageLocal.c_str()),
|
|
320
|
+
CheckedReinterpretCast<const uint8_t *>(messageLocal.c_str()) + messageLocal.length());
|
|
321
|
+
self->m_writer.WriteBytes(view);
|
|
322
|
+
}
|
|
323
|
+
} catch (hresult_error const &e) { // TODO: Remove after fixing unit tests exceptions.
|
|
324
|
+
self->Fail(e, ErrorType::Send);
|
|
325
|
+
co_return;
|
|
326
|
+
} catch (const std::exception &e) {
|
|
327
|
+
self->Fail(e.what(), ErrorType::Send);
|
|
328
|
+
co_return;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
auto async = self->m_writer.StoreAsync();
|
|
332
|
+
co_await lessthrow_await_adapter<DataWriterStoreOperation>{async};
|
|
333
|
+
|
|
334
|
+
auto result = async.ErrorCode();
|
|
335
|
+
if (result < 0) {
|
|
336
|
+
Fail(std::move(result), ErrorType::Send);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
#pragma region IWebSocketResource
|
|
342
|
+
|
|
343
|
+
void WinRTWebSocketResource2::Connect(string &&url, const Protocols &protocols, const Options &options) noexcept {
|
|
344
|
+
// Register MessageReceived BEFORE calling Connect
|
|
345
|
+
// https://learn.microsoft.com/en-us/uwp/api/windows.networking.sockets.messagewebsocket.messagereceived?view=winrt-22621
|
|
346
|
+
m_socket.MessageReceived([self = shared_from_this()](
|
|
347
|
+
IMessageWebSocket const &sender, IMessageWebSocketMessageReceivedEventArgs const &args) {
|
|
348
|
+
self->OnMessageReceived(sender, args);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
m_socket.Closed([self = shared_from_this()](IWebSocket const &sender, IWebSocketClosedEventArgs const &args) {
|
|
352
|
+
self->OnClosed(sender, args);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
auto supportedProtocols = m_socket.Control().SupportedProtocols();
|
|
356
|
+
for (const auto &protocol : protocols) {
|
|
357
|
+
supportedProtocols.Append(winrt::to_hstring(protocol));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
Uri uri{nullptr};
|
|
361
|
+
bool hasOriginHeader{false};
|
|
362
|
+
try {
|
|
363
|
+
uri = Uri{winrt::to_hstring(url)};
|
|
364
|
+
|
|
365
|
+
for (const auto &header : options) {
|
|
366
|
+
m_socket.SetRequestHeader(header.first, winrt::to_hstring(header.second));
|
|
367
|
+
if (boost::iequals(header.first, L"Origin")) {
|
|
368
|
+
hasOriginHeader = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// #12626 - If Origin header is not provided, set to connect endpoint.
|
|
373
|
+
if (!hasOriginHeader) {
|
|
374
|
+
auto scheme = uri.SchemeName();
|
|
375
|
+
auto host = uri.Host();
|
|
376
|
+
auto port = uri.Port();
|
|
377
|
+
|
|
378
|
+
if (scheme == L"ws") {
|
|
379
|
+
scheme = L"http";
|
|
380
|
+
} else if (scheme == L"wss") {
|
|
381
|
+
scheme = L"https";
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Only add a port if a port is defined.
|
|
385
|
+
hstring originPort = port != 0 ? L":" + winrt::to_hstring(port) : L"";
|
|
386
|
+
auto origin = hstring{scheme + L"://" + host + originPort};
|
|
387
|
+
|
|
388
|
+
m_socket.SetRequestHeader(L"Origin", std::move(origin));
|
|
389
|
+
}
|
|
390
|
+
} catch (hresult_error const &e) {
|
|
391
|
+
Fail(e, ErrorType::Connection);
|
|
392
|
+
|
|
393
|
+
SetEvent(m_connectPerformed.get());
|
|
394
|
+
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
PerformConnect(std::move(uri));
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void WinRTWebSocketResource2::Ping() noexcept {}
|
|
402
|
+
|
|
403
|
+
void WinRTWebSocketResource2::Send(string &&message) noexcept {
|
|
404
|
+
PerformWrite(std::move(message), false);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
void WinRTWebSocketResource2::SendBinary(string &&base64String) noexcept {
|
|
408
|
+
PerformWrite(std::move(base64String), true);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
void WinRTWebSocketResource2::Close(CloseCode code, const string &reason) noexcept {
|
|
412
|
+
m_closeCode = code;
|
|
413
|
+
m_closeReason = reason;
|
|
414
|
+
PerformClose();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
IWebSocketResource::ReadyState WinRTWebSocketResource2::GetReadyState() const noexcept {
|
|
418
|
+
return m_readyState;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
void WinRTWebSocketResource2::SetOnConnect(function<void()> &&handler) noexcept {
|
|
422
|
+
m_connectHandler = std::move(handler);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
void WinRTWebSocketResource2::SetOnPing(function<void()> && /*handler*/) noexcept {}
|
|
426
|
+
|
|
427
|
+
void WinRTWebSocketResource2::SetOnSend(function<void(size_t)> && /*handler*/) noexcept {}
|
|
428
|
+
|
|
429
|
+
void WinRTWebSocketResource2::SetOnMessage(function<void(size_t, const string &, bool isBinary)> &&handler) noexcept {
|
|
430
|
+
m_readHandler = std::move(handler);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
void WinRTWebSocketResource2::SetOnClose(function<void(CloseCode, const string &)> &&handler) noexcept {
|
|
434
|
+
m_closeHandler = std::move(handler);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
void WinRTWebSocketResource2::SetOnError(function<void(Error &&)> &&handler) noexcept {
|
|
438
|
+
m_errorHandler = std::move(handler);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
#pragma endregion IWebSocketResource
|
|
442
|
+
|
|
443
|
+
#pragma endregion WinRTWebSocketResource2
|
|
444
|
+
|
|
445
|
+
#pragma region Legacy resource
|
|
86
446
|
// private
|
|
87
447
|
WinRTWebSocketResource::WinRTWebSocketResource(
|
|
88
448
|
IMessageWebSocket &&socket,
|
|
@@ -331,7 +691,7 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
|
|
|
331
691
|
response = string(CheckedReinterpretCast<char *>(data.data()), data.size());
|
|
332
692
|
} else {
|
|
333
693
|
auto buffer = reader.ReadBuffer(len);
|
|
334
|
-
|
|
694
|
+
hstring data = CryptographicBuffer::EncodeToBase64String(buffer);
|
|
335
695
|
|
|
336
696
|
response = winrt::to_string(std::wstring_view(data));
|
|
337
697
|
}
|
|
@@ -360,7 +720,7 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
|
|
|
360
720
|
}
|
|
361
721
|
}
|
|
362
722
|
|
|
363
|
-
winrt::Windows::Foundation::Collections::IVector<
|
|
723
|
+
winrt::Windows::Foundation::Collections::IVector<hstring> supportedProtocols =
|
|
364
724
|
m_socket.Control().SupportedProtocols();
|
|
365
725
|
for (const auto &protocol : protocols) {
|
|
366
726
|
supportedProtocols.Append(winrt::to_hstring(protocol));
|
|
@@ -382,7 +742,10 @@ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, c
|
|
|
382
742
|
scheme = L"https";
|
|
383
743
|
}
|
|
384
744
|
|
|
385
|
-
|
|
745
|
+
// Only add a port if a port is defined
|
|
746
|
+
hstring originPort = port != 0 ? L":" + winrt::to_hstring(port) : L"";
|
|
747
|
+
auto origin = hstring{scheme + L"://" + host + originPort};
|
|
748
|
+
|
|
386
749
|
m_socket.SetRequestHeader(L"Origin", std::move(origin));
|
|
387
750
|
}
|
|
388
751
|
|
|
@@ -458,4 +821,6 @@ void WinRTWebSocketResource::SetOnError(function<void(Error &&)> &&handler) noex
|
|
|
458
821
|
|
|
459
822
|
#pragma endregion IWebSocketResource
|
|
460
823
|
|
|
824
|
+
#pragma endregion Legacy resource
|
|
825
|
+
|
|
461
826
|
} // namespace Microsoft::React::Networking
|