react-native-windows 0.72.1 → 0.72.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Libraries/Core/ReactNativeVersion.js +1 -1
- package/Libraries/Network/RCTNetworking.windows.js +10 -16
- package/Microsoft.ReactNative/Fabric/ImageRequest.cpp +11 -14
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +1 -1
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -3
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -7
- package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +11 -10
- package/Microsoft.ReactNative.Cxx/JSValueReader.h +1 -1
- package/Microsoft.ReactNative.Cxx/JSValueWriter.h +1 -1
- package/Microsoft.ReactNative.Cxx/ModuleRegistration.h +22 -0
- package/Microsoft.ReactNative.Cxx/NativeModules.h +5 -0
- package/Microsoft.ReactNative.Cxx/StructInfo.h +4 -4
- package/Microsoft.ReactNative.Managed/packages.lock.json +2 -71
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/React.Cpp.props +2 -3
- package/Shared/BaseFileReaderResource.cpp +95 -0
- package/Shared/BaseFileReaderResource.h +41 -0
- package/Shared/CreateModules.h +27 -5
- package/Shared/IFileReaderResource.h +36 -0
- package/Shared/Modules/BlobModule.cpp +93 -297
- package/Shared/Modules/BlobModule.h +25 -87
- package/Shared/Modules/CxxModuleUtilities.cpp +32 -0
- package/Shared/Modules/CxxModuleUtilities.h +17 -0
- package/Shared/Modules/FileReaderModule.cpp +118 -51
- package/Shared/Modules/FileReaderModule.h +27 -1
- package/Shared/Modules/HttpModule.cpp +133 -9
- package/Shared/Modules/HttpModule.h +33 -0
- package/Shared/Modules/IRequestBodyHandler.h +6 -4
- package/Shared/Modules/IResponseHandler.h +3 -3
- package/Shared/Modules/IUriHandler.h +3 -3
- package/Shared/Modules/IWebSocketModuleContentHandler.h +6 -4
- package/Shared/Modules/WebSocketModule.cpp +190 -7
- package/Shared/Modules/WebSocketTurboModule.h +52 -0
- package/Shared/Networking/DefaultBlobResource.cpp +323 -0
- package/Shared/Networking/DefaultBlobResource.h +133 -0
- package/Shared/Networking/IBlobResource.h +56 -0
- package/Shared/Networking/IHttpResource.h +6 -5
- package/Shared/Networking/WinRTHttpResource.cpp +40 -32
- package/Shared/Networking/WinRTHttpResource.h +4 -3
- package/Shared/Networking/WinRTTypes.h +3 -3
- package/Shared/Shared.vcxitems +8 -1
- package/Shared/Shared.vcxitems.filters +24 -3
- package/package.json +13 -13
- package/types/experimental.d.ts +101 -0
- package/types/index.d.ts +216 -0
- package/types/modules/BatchedBridge.d.ts +32 -0
- package/types/modules/Codegen.d.ts +74 -0
- package/types/modules/Devtools.d.ts +31 -0
- package/types/modules/LaunchScreen.d.ts +18 -0
- package/types/modules/globals.d.ts +579 -0
- package/types/private/TimerMixin.d.ts +19 -0
- package/types/private/Utilities.d.ts +10 -0
- package/types/public/DeprecatedPropertiesAlias.d.ts +185 -0
- package/types/public/Insets.d.ts +15 -0
- package/types/public/ReactNativeRenderer.d.ts +144 -0
- package/types/public/ReactNativeTypes.d.ts +143 -0
- package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +0 -44
- package/Microsoft.ReactNative/Base/CoreNativeModules.h +0 -30
- /package/Shared/{Modules/IBlobPersistor.h → IBlobPersistor.h} +0 -0
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
#include "HttpModule.h"
|
|
7
7
|
|
|
8
|
+
#include <CreateModules.h>
|
|
8
9
|
#include <Modules/CxxModuleUtilities.h>
|
|
9
10
|
#include <ReactPropertyBag.h>
|
|
10
11
|
|
|
@@ -14,6 +15,7 @@
|
|
|
14
15
|
|
|
15
16
|
using facebook::react::Instance;
|
|
16
17
|
using folly::dynamic;
|
|
18
|
+
using std::function;
|
|
17
19
|
using std::shared_ptr;
|
|
18
20
|
using std::string;
|
|
19
21
|
using std::weak_ptr;
|
|
@@ -23,12 +25,15 @@ using winrt::Microsoft::ReactNative::ReactPropertyBag;
|
|
|
23
25
|
using winrt::Microsoft::ReactNative::ReactPropertyId;
|
|
24
26
|
using winrt::Windows::Foundation::IInspectable;
|
|
25
27
|
|
|
28
|
+
namespace msrn = winrt::Microsoft::ReactNative;
|
|
29
|
+
|
|
26
30
|
namespace {
|
|
27
31
|
|
|
28
32
|
using Microsoft::React::Modules::SendEvent;
|
|
29
33
|
using Microsoft::React::Networking::IHttpResource;
|
|
30
34
|
|
|
31
|
-
constexpr char
|
|
35
|
+
constexpr char s_moduleName[] = "Networking";
|
|
36
|
+
constexpr wchar_t s_moduleNameW[] = L"Networking";
|
|
32
37
|
|
|
33
38
|
// React event names
|
|
34
39
|
constexpr char completedResponse[] = "didCompleteNetworkResponse";
|
|
@@ -38,6 +43,15 @@ constexpr char receivedIncrementalData[] = "didReceiveNetworkIncrementalData";
|
|
|
38
43
|
constexpr char receivedDataProgress[] = "didReceiveNetworkDataProgress";
|
|
39
44
|
constexpr char receivedData[] = "didReceiveNetworkData";
|
|
40
45
|
|
|
46
|
+
constexpr wchar_t completedResponseW[] = L"didCompleteNetworkResponse";
|
|
47
|
+
constexpr wchar_t receivedResponseW[] = L"didReceiveNetworkResponse";
|
|
48
|
+
constexpr wchar_t sentDataW[] = L"didSendNetworkData";
|
|
49
|
+
constexpr wchar_t receivedIncrementalDataW[] = L"didReceiveNetworkIncrementalData";
|
|
50
|
+
constexpr wchar_t receivedDataProgressW[] = L"didReceiveNetworkDataProgress";
|
|
51
|
+
constexpr wchar_t receivedDataW[] = L"didReceiveNetworkData";
|
|
52
|
+
|
|
53
|
+
msrn::ReactModuleProvider s_moduleProvider = msrn::MakeTurboModuleProvider<Microsoft::React::HttpTurboModule>();
|
|
54
|
+
|
|
41
55
|
static void SetUpHttpResource(
|
|
42
56
|
shared_ptr<IHttpResource> resource,
|
|
43
57
|
weak_ptr<Instance> weakReactInstance,
|
|
@@ -65,10 +79,11 @@ static void SetUpHttpResource(
|
|
|
65
79
|
});
|
|
66
80
|
|
|
67
81
|
// Explicitly declaring function type to avoid type inference ambiguity.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
function<void(int64_t, msrn::JSValueObject &&)> onDataDynamic =
|
|
83
|
+
[weakReactInstance](int64_t requestId, msrn::JSValueObject &&responseData) {
|
|
84
|
+
auto responseDynamic = Microsoft::React::Modules::ToDynamic(msrn::JSValue{std::move(responseData)});
|
|
85
|
+
SendEvent(weakReactInstance, receivedData, dynamic::array(requestId, std::move(responseDynamic)));
|
|
86
|
+
};
|
|
72
87
|
resource->SetOnData(std::move(onDataDynamic));
|
|
73
88
|
|
|
74
89
|
resource->SetOnIncrementalData(
|
|
@@ -101,6 +116,104 @@ static void SetUpHttpResource(
|
|
|
101
116
|
|
|
102
117
|
namespace Microsoft::React {
|
|
103
118
|
|
|
119
|
+
#pragma region HttpTurboModule
|
|
120
|
+
|
|
121
|
+
void HttpTurboModule::Initialize(msrn::ReactContext const &reactContext) noexcept {
|
|
122
|
+
m_context = reactContext;
|
|
123
|
+
m_resource = IHttpResource::Make(m_context.Properties().Handle());
|
|
124
|
+
|
|
125
|
+
m_resource->SetOnRequestSuccess([context = m_context](int64_t requestId) {
|
|
126
|
+
SendEvent(context, completedResponseW, msrn::JSValueArray{requestId});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
m_resource->SetOnResponse([context = m_context](int64_t requestId, IHttpResource::Response &&response) {
|
|
130
|
+
auto headers = msrn::JSValueObject{};
|
|
131
|
+
for (auto &header : response.Headers) {
|
|
132
|
+
headers[header.first] = header.second;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// TODO: Test response content?
|
|
136
|
+
auto args = msrn::JSValueArray{requestId, response.StatusCode, std::move(headers), response.Url};
|
|
137
|
+
|
|
138
|
+
SendEvent(context, receivedResponseW, std::move(args));
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
m_resource->SetOnData([context = m_context](int64_t requestId, string &&responseData) {
|
|
142
|
+
SendEvent(context, receivedDataW, msrn::JSValueArray{requestId, std::move(responseData)});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Explicitly declaring function type to avoid type inference ambiguity.
|
|
146
|
+
function<void(int64_t, msrn::JSValueObject &&)> onDataObject =
|
|
147
|
+
[context = m_context](int64_t requestId, msrn::JSValueObject &&responseData) {
|
|
148
|
+
SendEvent(context, receivedDataW, msrn::JSValueArray{requestId, std::move(responseData)});
|
|
149
|
+
};
|
|
150
|
+
m_resource->SetOnData(std::move(onDataObject));
|
|
151
|
+
|
|
152
|
+
m_resource->SetOnIncrementalData(
|
|
153
|
+
[context = m_context](int64_t requestId, string &&responseData, int64_t progress, int64_t total) {
|
|
154
|
+
SendEvent(
|
|
155
|
+
context, receivedIncrementalDataW, msrn::JSValueArray{requestId, std::move(responseData), progress, total});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
m_resource->SetOnDataProgress([context = m_context](int64_t requestId, int64_t progress, int64_t total) {
|
|
159
|
+
SendEvent(context, receivedDataProgressW, msrn::JSValueArray{requestId, progress, total});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
m_resource->SetOnResponseComplete([context = m_context](int64_t requestId) {
|
|
163
|
+
SendEvent(context, completedResponseW, msrn::JSValueArray{requestId});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
m_resource->SetOnError([context = m_context](int64_t requestId, string &&message, bool isTimeout) {
|
|
167
|
+
auto args = msrn::JSValueArray{requestId, std::move(message)};
|
|
168
|
+
if (isTimeout) {
|
|
169
|
+
args.push_back(true);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
SendEvent(context, completedResponseW, std::move(args));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
void HttpTurboModule::SendRequest(
|
|
177
|
+
ReactNativeSpecs::NetworkingIOSSpec_sendRequest_query &&query,
|
|
178
|
+
function<void(double)> const &callback) noexcept {
|
|
179
|
+
m_requestId++;
|
|
180
|
+
auto &headersObj = query.headers.AsObject();
|
|
181
|
+
IHttpResource::Headers headers;
|
|
182
|
+
for (auto &entry : headersObj) {
|
|
183
|
+
headers.emplace(entry.first, entry.second.AsString());
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
m_resource->SendRequest(
|
|
187
|
+
std::move(query.method),
|
|
188
|
+
std::move(query.url),
|
|
189
|
+
m_requestId,
|
|
190
|
+
std::move(headers),
|
|
191
|
+
query.data.MoveObject(),
|
|
192
|
+
std::move(query.responseType),
|
|
193
|
+
query.incrementalUpdates,
|
|
194
|
+
static_cast<int64_t>(query.timeout),
|
|
195
|
+
query.withCredentials,
|
|
196
|
+
[&callback](int64_t requestId) { callback({static_cast<double>(requestId)}); });
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
void HttpTurboModule::AbortRequest(double requestId) noexcept {
|
|
200
|
+
m_resource->AbortRequest(static_cast<int64_t>(requestId));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
void HttpTurboModule::ClearCookies(function<void(bool)> const &callback) noexcept {
|
|
204
|
+
m_resource->ClearCookies();
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
void HttpTurboModule::AddListener(string &&eventName) noexcept { /*NOOP*/
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
void HttpTurboModule::RemoveListeners(double count) noexcept { /*NOOP*/
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
#pragma endregion HttpTurboModule
|
|
214
|
+
|
|
215
|
+
#pragma region HttpModule
|
|
216
|
+
|
|
104
217
|
HttpModule::HttpModule(IInspectable const &inspectableProperties) noexcept
|
|
105
218
|
: m_holder{std::make_shared<ModuleHolder>()},
|
|
106
219
|
m_inspectableProperties{inspectableProperties},
|
|
@@ -115,7 +228,7 @@ HttpModule::~HttpModule() noexcept /*override*/ {
|
|
|
115
228
|
#pragma region CxxModule
|
|
116
229
|
|
|
117
230
|
string HttpModule::getName() /*override*/ {
|
|
118
|
-
return
|
|
231
|
+
return s_moduleName;
|
|
119
232
|
}
|
|
120
233
|
|
|
121
234
|
std::map<string, dynamic> HttpModule::getConstants() {
|
|
@@ -142,6 +255,7 @@ std::vector<facebook::xplat::module::CxxModule::Method> HttpModule::getMethods()
|
|
|
142
255
|
SetUpHttpResource(resource, holder->Module->getInstance(), holder->Module->m_inspectableProperties);
|
|
143
256
|
holder->Module->m_isResourceSetup = true;
|
|
144
257
|
}
|
|
258
|
+
holder->Module->m_requestId++;
|
|
145
259
|
|
|
146
260
|
auto params = facebook::xplat::jsArgAsObject(args, 0);
|
|
147
261
|
IHttpResource::Headers headers;
|
|
@@ -152,9 +266,9 @@ std::vector<facebook::xplat::module::CxxModule::Method> HttpModule::getMethods()
|
|
|
152
266
|
resource->SendRequest(
|
|
153
267
|
params["method"].asString(),
|
|
154
268
|
params["url"].asString(),
|
|
155
|
-
|
|
269
|
+
holder->Module->m_requestId,
|
|
156
270
|
std::move(headers),
|
|
157
|
-
|
|
271
|
+
Modules::ToJSValue(params["data"]).MoveObject(),
|
|
158
272
|
params["responseType"].asString(),
|
|
159
273
|
params["incrementalUpdates"].asBool(),
|
|
160
274
|
static_cast<int64_t>(params["timeout"].asDouble()),
|
|
@@ -211,8 +325,18 @@ std::vector<facebook::xplat::module::CxxModule::Method> HttpModule::getMethods()
|
|
|
211
325
|
|
|
212
326
|
#pragma endregion CxxModule
|
|
213
327
|
|
|
328
|
+
#pragma endregion HttpModule
|
|
329
|
+
|
|
214
330
|
/*extern*/ const char *GetHttpModuleName() noexcept {
|
|
215
|
-
return
|
|
331
|
+
return s_moduleName;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/*extern*/ const wchar_t *GetHttpTurboModuleName() noexcept {
|
|
335
|
+
return s_moduleNameW;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/*extern*/ const msrn::ReactModuleProvider &GetHttpModuleProvider() noexcept {
|
|
339
|
+
return s_moduleProvider;
|
|
216
340
|
}
|
|
217
341
|
|
|
218
342
|
} // namespace Microsoft::React
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
|
+
#include <NativeNetworkingIOSSpec.g.h>
|
|
7
|
+
#include <NativeModules.h>
|
|
6
8
|
#include <Networking/IHttpResource.h>
|
|
7
9
|
|
|
8
10
|
// React Native
|
|
@@ -13,6 +15,36 @@
|
|
|
13
15
|
|
|
14
16
|
namespace Microsoft::React {
|
|
15
17
|
|
|
18
|
+
REACT_MODULE(HttpTurboModule, L"Networking")
|
|
19
|
+
struct HttpTurboModule {
|
|
20
|
+
using ModuleSpec = ReactNativeSpecs::NetworkingIOSSpec;
|
|
21
|
+
|
|
22
|
+
REACT_INIT(Initialize)
|
|
23
|
+
void Initialize(winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept;
|
|
24
|
+
|
|
25
|
+
REACT_METHOD(SendRequest, L"sendRequest")
|
|
26
|
+
void SendRequest(
|
|
27
|
+
ReactNativeSpecs::NetworkingIOSSpec_sendRequest_query &&query,
|
|
28
|
+
std::function<void(double)> const &callback) noexcept;
|
|
29
|
+
|
|
30
|
+
REACT_METHOD(AbortRequest, L"abortRequest")
|
|
31
|
+
void AbortRequest(double requestId) noexcept;
|
|
32
|
+
|
|
33
|
+
REACT_METHOD(ClearCookies, L"clearCookies")
|
|
34
|
+
void ClearCookies(std::function<void(bool)> const &callback) noexcept;
|
|
35
|
+
|
|
36
|
+
REACT_METHOD(AddListener, L"addListener")
|
|
37
|
+
void AddListener(std::string &&eventName) noexcept;
|
|
38
|
+
|
|
39
|
+
REACT_METHOD(RemoveListeners, L"removeListeners")
|
|
40
|
+
void RemoveListeners(double count) noexcept;
|
|
41
|
+
|
|
42
|
+
private:
|
|
43
|
+
std::shared_ptr<Networking::IHttpResource> m_resource;
|
|
44
|
+
winrt::Microsoft::ReactNative::ReactContext m_context;
|
|
45
|
+
int64_t m_requestId{0};
|
|
46
|
+
};
|
|
47
|
+
|
|
16
48
|
///
|
|
17
49
|
/// Realizes <c>NativeModules</c> projection.
|
|
18
50
|
/// <remarks>See src\Libraries\Network\RCTNetworking.windows.js</remarks>
|
|
@@ -53,6 +85,7 @@ class HttpModule : public facebook::xplat::module::CxxModule {
|
|
|
53
85
|
std::shared_ptr<Networking::IHttpResource> m_resource;
|
|
54
86
|
std::shared_ptr<ModuleHolder> m_holder;
|
|
55
87
|
bool m_isResourceSetup{false};
|
|
88
|
+
int64_t m_requestId{0};
|
|
56
89
|
|
|
57
90
|
// Property bag high level reference.
|
|
58
91
|
winrt::Windows::Foundation::IInspectable m_inspectableProperties;
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
#include <
|
|
6
|
+
// React Native Windows
|
|
7
|
+
#include <JSValue.h>
|
|
8
8
|
|
|
9
9
|
// Standard Library
|
|
10
10
|
#include <string>
|
|
@@ -26,7 +26,7 @@ struct IRequestBodyHandler {
|
|
|
26
26
|
/// true - <paramref name="data" /> contains a blob reference.
|
|
27
27
|
/// false - <paramref name="data" /> does not contain a blob reference.
|
|
28
28
|
/// </returns>
|
|
29
|
-
virtual bool Supports(
|
|
29
|
+
virtual bool Supports(winrt::Microsoft::ReactNative::JSValueObject &data) = 0;
|
|
30
30
|
|
|
31
31
|
/// <summary>
|
|
32
32
|
/// Returns the {@link RequestBody} for the JS body payload.
|
|
@@ -46,7 +46,9 @@ struct IRequestBodyHandler {
|
|
|
46
46
|
/// "bytes" - Raw body content
|
|
47
47
|
/// NOTE: This is an arbitrary key. Pending non-folly structured object to model request body.
|
|
48
48
|
/// </returns>
|
|
49
|
-
virtual
|
|
49
|
+
virtual winrt::Microsoft::ReactNative::JSValueObject ToRequestBody(
|
|
50
|
+
winrt::Microsoft::ReactNative::JSValueObject &data,
|
|
51
|
+
std::string &contentType) = 0;
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
} // namespace Microsoft::React
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
#include <
|
|
3
|
+
// React Native Windows
|
|
4
|
+
#include <JSValue.h>
|
|
5
5
|
|
|
6
6
|
// Standard Library
|
|
7
7
|
#include <string>
|
|
@@ -21,7 +21,7 @@ struct IResponseHandler {
|
|
|
21
21
|
/// <summary>
|
|
22
22
|
/// Returns the JS body payload for the {@link ResponseBody}.
|
|
23
23
|
/// </summary>
|
|
24
|
-
virtual
|
|
24
|
+
virtual winrt::Microsoft::ReactNative::JSValueObject ToResponseData(std::vector<uint8_t> &&content) = 0;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
} // namespace Microsoft::React
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
|
-
//
|
|
7
|
-
#include <
|
|
6
|
+
// React Native Windows
|
|
7
|
+
#include <JSValue.h>
|
|
8
8
|
|
|
9
9
|
// Standard Library
|
|
10
10
|
#include <string>
|
|
@@ -31,7 +31,7 @@ struct IUriHandler {
|
|
|
31
31
|
/// "size" - Number of bytes fetched from blob
|
|
32
32
|
/// "name" - File name obtained from the URI
|
|
33
33
|
/// "lastModified - Last write to local file in milliseconds
|
|
34
|
-
virtual
|
|
34
|
+
virtual winrt::Microsoft::ReactNative::JSValueObject Fetch(std::string &uri) = 0;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
} // namespace Microsoft::React
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
#pragma once
|
|
5
5
|
|
|
6
|
-
// React Native
|
|
7
|
-
#include <
|
|
6
|
+
// React Native Windows
|
|
7
|
+
#include <JSValue.h>
|
|
8
8
|
|
|
9
9
|
// Standard Library
|
|
10
10
|
#include <string>
|
|
@@ -18,9 +18,11 @@ namespace Microsoft::React {
|
|
|
18
18
|
struct IWebSocketModuleContentHandler {
|
|
19
19
|
virtual ~IWebSocketModuleContentHandler() noexcept {}
|
|
20
20
|
|
|
21
|
-
virtual void ProcessMessage(std::string &&message,
|
|
21
|
+
virtual void ProcessMessage(std::string &&message, winrt::Microsoft::ReactNative::JSValueObject ¶ms) noexcept = 0;
|
|
22
22
|
|
|
23
|
-
virtual void ProcessMessage(
|
|
23
|
+
virtual void ProcessMessage(
|
|
24
|
+
std::vector<uint8_t> &&message,
|
|
25
|
+
winrt::Microsoft::ReactNative::JSValueObject ¶ms) noexcept = 0;
|
|
24
26
|
};
|
|
25
27
|
|
|
26
28
|
} // namespace Microsoft::React
|
|
@@ -4,11 +4,16 @@
|
|
|
4
4
|
#include "pch.h"
|
|
5
5
|
|
|
6
6
|
#include <Modules/WebSocketModule.h>
|
|
7
|
+
#include <Modules/WebSocketTurboModule.h>
|
|
7
8
|
|
|
9
|
+
#include <CreateModules.h>
|
|
8
10
|
#include <Modules/CxxModuleUtilities.h>
|
|
9
11
|
#include <Modules/IWebSocketModuleContentHandler.h>
|
|
10
12
|
#include <ReactPropertyBag.h>
|
|
11
13
|
|
|
14
|
+
// fmt
|
|
15
|
+
#include <fmt/format.h>
|
|
16
|
+
|
|
12
17
|
// React Native
|
|
13
18
|
#include <cxxreact/Instance.h>
|
|
14
19
|
#include <cxxreact/JsArgumentHelpers.h>
|
|
@@ -19,6 +24,8 @@
|
|
|
19
24
|
// Standard Libriary
|
|
20
25
|
#include <iomanip>
|
|
21
26
|
|
|
27
|
+
namespace msrn = winrt::Microsoft::ReactNative;
|
|
28
|
+
|
|
22
29
|
using namespace facebook::xplat;
|
|
23
30
|
|
|
24
31
|
using facebook::react::Instance;
|
|
@@ -26,6 +33,7 @@ using folly::dynamic;
|
|
|
26
33
|
|
|
27
34
|
using std::shared_ptr;
|
|
28
35
|
using std::string;
|
|
36
|
+
using std::vector;
|
|
29
37
|
using std::weak_ptr;
|
|
30
38
|
|
|
31
39
|
using winrt::Microsoft::ReactNative::IReactPropertyBag;
|
|
@@ -42,7 +50,10 @@ using Microsoft::React::WebSocketModule;
|
|
|
42
50
|
using Microsoft::React::Modules::SendEvent;
|
|
43
51
|
using Microsoft::React::Networking::IWebSocketResource;
|
|
44
52
|
|
|
45
|
-
constexpr char
|
|
53
|
+
constexpr char s_moduleName[] = "WebSocketModule";
|
|
54
|
+
constexpr wchar_t s_moduleNameW[] = L"WebSocketModule";
|
|
55
|
+
|
|
56
|
+
msrn::ReactModuleProvider s_moduleProvider = msrn::MakeTurboModuleProvider<Microsoft::React::WebSocketTurboModule>();
|
|
46
57
|
|
|
47
58
|
static shared_ptr<IWebSocketResource>
|
|
48
59
|
GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedState> weakState) {
|
|
@@ -105,7 +116,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
|
|
|
105
116
|
if (!strongInstance)
|
|
106
117
|
return;
|
|
107
118
|
|
|
108
|
-
|
|
119
|
+
auto args = msrn::JSValueObject{{"id", id}, {"type", isBinary ? "binary" : "text"}};
|
|
109
120
|
shared_ptr<Microsoft::React::IWebSocketModuleContentHandler> contentHandler;
|
|
110
121
|
auto propId = ReactPropertyId<ReactNonAbiValue<weak_ptr<Microsoft::React::IWebSocketModuleContentHandler>>>{
|
|
111
122
|
L"BlobModule.ContentHandler"};
|
|
@@ -117,7 +128,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
|
|
|
117
128
|
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(message));
|
|
118
129
|
winrt::com_array<uint8_t> arr;
|
|
119
130
|
CryptographicBuffer::CopyToByteArray(buffer, arr);
|
|
120
|
-
auto data =
|
|
131
|
+
auto data = vector<uint8_t>(arr.begin(), arr.end());
|
|
121
132
|
|
|
122
133
|
contentHandler->ProcessMessage(std::move(data), args);
|
|
123
134
|
} else {
|
|
@@ -127,7 +138,7 @@ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedS
|
|
|
127
138
|
args["data"] = message;
|
|
128
139
|
}
|
|
129
140
|
|
|
130
|
-
SendEvent(weakInstance, "websocketMessage", std::move(args));
|
|
141
|
+
SendEvent(weakInstance, "websocketMessage", Microsoft::React::Modules::ToDynamic(std::move(args)));
|
|
131
142
|
});
|
|
132
143
|
ws->SetOnClose([id, weakInstance](IWebSocketResource::CloseCode code, const string &reason) {
|
|
133
144
|
auto strongInstance = weakInstance.lock();
|
|
@@ -179,7 +190,7 @@ void WebSocketModule::SetResourceFactory(
|
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
string WebSocketModule::getName() {
|
|
182
|
-
return
|
|
193
|
+
return s_moduleName;
|
|
183
194
|
}
|
|
184
195
|
|
|
185
196
|
std::map<string, dynamic> WebSocketModule::getConstants() {
|
|
@@ -187,7 +198,7 @@ std::map<string, dynamic> WebSocketModule::getConstants() {
|
|
|
187
198
|
}
|
|
188
199
|
|
|
189
200
|
// clang-format off
|
|
190
|
-
|
|
201
|
+
vector<facebook::xplat::module::CxxModule::Method> WebSocketModule::getMethods()
|
|
191
202
|
{
|
|
192
203
|
return
|
|
193
204
|
{
|
|
@@ -312,8 +323,172 @@ void WebSocketModuleProxy::SendBinary(std::string &&base64String, int64_t id) no
|
|
|
312
323
|
|
|
313
324
|
#pragma endregion WebSocketModuleProxy
|
|
314
325
|
|
|
326
|
+
#pragma region WebSocketTurboModule
|
|
327
|
+
|
|
328
|
+
shared_ptr<IWebSocketResource> WebSocketTurboModule::CreateResource(int64_t id, string &&url) noexcept {
|
|
329
|
+
shared_ptr<IWebSocketResource> rc;
|
|
330
|
+
try {
|
|
331
|
+
rc = IWebSocketResource::Make();
|
|
332
|
+
} catch (const winrt::hresult_error &e) {
|
|
333
|
+
auto error = fmt::format("[0x{:0>8x}] {}", static_cast<uint32_t>(e.code()), winrt::to_string(e.message()));
|
|
334
|
+
SendEvent(m_context, L"webSocketFailed", {{"id", id}, {"message", std::move(error)}});
|
|
335
|
+
|
|
336
|
+
return nullptr;
|
|
337
|
+
} catch (const std::exception &e) {
|
|
338
|
+
SendEvent(m_context, L"webSocketFailed", {{"id", id}, {"message", e.what()}});
|
|
339
|
+
|
|
340
|
+
return nullptr;
|
|
341
|
+
} catch (...) {
|
|
342
|
+
SendEvent(
|
|
343
|
+
m_context, L"webSocketFailed", {{"id", id}, {"message", "Unidentified error creating IWebSocketResource"}});
|
|
344
|
+
|
|
345
|
+
return nullptr;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Set up resource
|
|
349
|
+
rc->SetOnConnect([id, context = m_context]() {
|
|
350
|
+
SendEvent(context, L"websocketOpen", msrn::JSValueObject{{"id", id}});
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
rc->SetOnMessage([id, context = m_context](size_t length, const string &message, bool isBinary) {
|
|
354
|
+
auto args = msrn::JSValueObject{{"id", id}, {"type", isBinary ? "binary" : "text"}};
|
|
355
|
+
shared_ptr<IWebSocketModuleContentHandler> contentHandler;
|
|
356
|
+
auto propId =
|
|
357
|
+
ReactPropertyId<ReactNonAbiValue<weak_ptr<IWebSocketModuleContentHandler>>>{L"BlobModule.ContentHandler"};
|
|
358
|
+
auto propBag = context.Properties();
|
|
359
|
+
if (auto prop = propBag.Get(propId))
|
|
360
|
+
contentHandler = prop.Value().lock();
|
|
361
|
+
|
|
362
|
+
if (contentHandler) {
|
|
363
|
+
if (isBinary) {
|
|
364
|
+
auto buffer = CryptographicBuffer::DecodeFromBase64String(winrt::to_hstring(message));
|
|
365
|
+
winrt::com_array<uint8_t> arr;
|
|
366
|
+
CryptographicBuffer::CopyToByteArray(buffer, arr);
|
|
367
|
+
auto data = vector<uint8_t>(arr.begin(), arr.end());
|
|
368
|
+
|
|
369
|
+
contentHandler->ProcessMessage(std::move(data), args);
|
|
370
|
+
} else {
|
|
371
|
+
contentHandler->ProcessMessage(string{message}, args);
|
|
372
|
+
}
|
|
373
|
+
} else {
|
|
374
|
+
args["data"] = message;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
SendEvent(context, L"websocketMessage", std::move(args));
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
rc->SetOnClose([id, context = m_context](IWebSocketResource::CloseCode code, const string &reason) {
|
|
381
|
+
auto args = msrn::JSValueObject{{"id", id}, {"code", static_cast<uint16_t>(code)}, {"reason", reason}};
|
|
382
|
+
|
|
383
|
+
SendEvent(context, L"websocketClosed", std::move(args));
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
rc->SetOnError([id, context = m_context](const IWebSocketResource::Error &err) {
|
|
387
|
+
auto errorObj = msrn::JSValueObject{{"id", id}, {"message", err.Message}};
|
|
388
|
+
|
|
389
|
+
SendEvent(context, L"websocketFailed", std::move(errorObj));
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
m_resourceMap.emplace(static_cast<double>(id), rc);
|
|
393
|
+
|
|
394
|
+
return rc;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
void WebSocketTurboModule::Initialize(msrn::ReactContext const &reactContext) noexcept {
|
|
398
|
+
m_context = reactContext.Handle();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
void WebSocketTurboModule::Connect(
|
|
402
|
+
string &&url,
|
|
403
|
+
std::optional<vector<string>> protocols,
|
|
404
|
+
ReactNativeSpecs::WebSocketModuleSpec_connect_options &&options,
|
|
405
|
+
double socketID) noexcept {
|
|
406
|
+
IWebSocketResource::Protocols rcProtocols;
|
|
407
|
+
for (const auto &protocol : protocols.value_or(vector<string>{})) {
|
|
408
|
+
rcProtocols.push_back(protocol);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
IWebSocketResource::Options rcOptions;
|
|
412
|
+
auto &optHeaders = options.headers;
|
|
413
|
+
if (optHeaders.has_value()) {
|
|
414
|
+
auto &headersVal = optHeaders.value();
|
|
415
|
+
for (const auto &headerVal : headersVal.AsArray()) {
|
|
416
|
+
// Each header JSValueObject should only contain one key-value pair
|
|
417
|
+
const auto &entry = *headerVal.AsObject().cbegin();
|
|
418
|
+
rcOptions.emplace(winrt::to_hstring(entry.first), entry.second.AsString());
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
weak_ptr<IWebSocketResource> weakRc;
|
|
423
|
+
auto rcItr = m_resourceMap.find(socketID);
|
|
424
|
+
if (rcItr != m_resourceMap.cend()) {
|
|
425
|
+
weakRc = (*rcItr).second;
|
|
426
|
+
} else {
|
|
427
|
+
weakRc = CreateResource(static_cast<int64_t>(socketID), string{url});
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (auto rc = weakRc.lock()) {
|
|
431
|
+
rc->Connect(std::move(url), rcProtocols, rcOptions);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
void WebSocketTurboModule::Close(double code, string &&reason, double socketID) noexcept {
|
|
436
|
+
auto rcItr = m_resourceMap.find(socketID);
|
|
437
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
438
|
+
return; // TODO: Send error instead?
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
442
|
+
if (auto rc = weakRc.lock()) {
|
|
443
|
+
rc->Close(static_cast<IWebSocketResource::CloseCode>(code), std::move(reason));
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
void WebSocketTurboModule::Send(string &&message, double forSocketID) noexcept {
|
|
448
|
+
auto rcItr = m_resourceMap.find(forSocketID);
|
|
449
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
450
|
+
return; // TODO: Send error instead?
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
454
|
+
if (auto rc = weakRc.lock()) {
|
|
455
|
+
rc->Send(std::move(message));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
void WebSocketTurboModule::SendBinary(string &&base64String, double forSocketID) noexcept {
|
|
460
|
+
auto rcItr = m_resourceMap.find(forSocketID);
|
|
461
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
462
|
+
return; // TODO: Send error instead?
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
466
|
+
if (auto rc = weakRc.lock()) {
|
|
467
|
+
rc->SendBinary(std::move(base64String));
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
void WebSocketTurboModule::Ping(double socketID) noexcept {
|
|
472
|
+
auto rcItr = m_resourceMap.find(socketID);
|
|
473
|
+
if (rcItr == m_resourceMap.cend()) {
|
|
474
|
+
return; // TODO: Send error instead?
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
weak_ptr<IWebSocketResource> weakRc = (*rcItr).second;
|
|
478
|
+
if (auto rc = weakRc.lock()) {
|
|
479
|
+
rc->Ping();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// See react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
|
|
484
|
+
void WebSocketTurboModule::AddListener(string && /*eventName*/) noexcept {}
|
|
485
|
+
|
|
486
|
+
void WebSocketTurboModule::RemoveListeners(double /*count*/) noexcept {}
|
|
487
|
+
|
|
488
|
+
#pragma endregion WebSocketTurboModule
|
|
489
|
+
|
|
315
490
|
/*extern*/ const char *GetWebSocketModuleName() noexcept {
|
|
316
|
-
return
|
|
491
|
+
return s_moduleName;
|
|
317
492
|
}
|
|
318
493
|
|
|
319
494
|
/*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateWebSocketModule(
|
|
@@ -324,4 +499,12 @@ void WebSocketModuleProxy::SendBinary(std::string &&base64String, int64_t id) no
|
|
|
324
499
|
return nullptr;
|
|
325
500
|
}
|
|
326
501
|
|
|
502
|
+
/*extern*/ const wchar_t *GetWebSocketTurboModuleName() noexcept {
|
|
503
|
+
return s_moduleNameW;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/*extern*/ const msrn::ReactModuleProvider &GetWebSocketModuleProvider() noexcept {
|
|
507
|
+
return s_moduleProvider;
|
|
508
|
+
}
|
|
509
|
+
|
|
327
510
|
} // namespace Microsoft::React
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright (c) Microsoft Corporation.
|
|
2
|
+
// Licensed under the MIT License.
|
|
3
|
+
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <NativeWebSocketModuleSpec.g.h>
|
|
7
|
+
#include <Modules/IWebSocketModuleProxy.h>
|
|
8
|
+
#include <NativeModules.h>
|
|
9
|
+
#include <Networking/IWebSocketResource.h>
|
|
10
|
+
|
|
11
|
+
namespace Microsoft::React {
|
|
12
|
+
|
|
13
|
+
REACT_MODULE(WebSocketTurboModule, L"WebSocketModule")
|
|
14
|
+
struct WebSocketTurboModule {
|
|
15
|
+
using ModuleSpec = ReactNativeSpecs::WebSocketModuleSpec;
|
|
16
|
+
|
|
17
|
+
REACT_INIT(Initialize)
|
|
18
|
+
void Initialize(winrt::Microsoft::ReactNative::ReactContext const &reactContext) noexcept;
|
|
19
|
+
|
|
20
|
+
REACT_METHOD(Connect, L"connect")
|
|
21
|
+
void Connect(
|
|
22
|
+
std::string &&url,
|
|
23
|
+
std::optional<std::vector<std::string>> protocols,
|
|
24
|
+
ReactNativeSpecs::WebSocketModuleSpec_connect_options &&options,
|
|
25
|
+
double socketID) noexcept;
|
|
26
|
+
|
|
27
|
+
REACT_METHOD(Close, L"close")
|
|
28
|
+
void Close(double code, std::string &&reason, double socketID) noexcept;
|
|
29
|
+
|
|
30
|
+
REACT_METHOD(Send, L"send")
|
|
31
|
+
void Send(std::string &&message, double forSocketID) noexcept;
|
|
32
|
+
|
|
33
|
+
REACT_METHOD(SendBinary, L"sendBinary")
|
|
34
|
+
void SendBinary(std::string &&base64String, double forSocketID) noexcept;
|
|
35
|
+
|
|
36
|
+
REACT_METHOD(Ping, L"ping")
|
|
37
|
+
void Ping(double socketID) noexcept;
|
|
38
|
+
|
|
39
|
+
REACT_METHOD(AddListener, L"addListener")
|
|
40
|
+
void AddListener(std::string &&eventName) noexcept;
|
|
41
|
+
|
|
42
|
+
REACT_METHOD(RemoveListeners, L"removeListeners")
|
|
43
|
+
void RemoveListeners(double count) noexcept;
|
|
44
|
+
|
|
45
|
+
private:
|
|
46
|
+
std::shared_ptr<Networking::IWebSocketResource> CreateResource(int64_t id, std::string &&url) noexcept;
|
|
47
|
+
|
|
48
|
+
winrt::Microsoft::ReactNative::ReactContext m_context;
|
|
49
|
+
std::unordered_map<double, std::shared_ptr<Networking::IWebSocketResource>> m_resourceMap;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
} // namespace Microsoft::React
|