react-native-windows 0.65.8 → 0.65.12

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/CHANGELOG.json CHANGED
@@ -2,7 +2,73 @@
2
2
  "name": "react-native-windows",
3
3
  "entries": [
4
4
  {
5
- "date": "Mon, 15 Nov 2021 16:09:05 GMT",
5
+ "date": "Mon, 07 Feb 2022 16:12:12 GMT",
6
+ "tag": "react-native-windows_v0.65.12",
7
+ "version": "0.65.12",
8
+ "comments": {
9
+ "patch": [
10
+ {
11
+ "comment": "Replace __APPLE__ with __clang__ where applicable (#9461)",
12
+ "author": "julio.rocha@microsoft.com",
13
+ "commit": "a6dfccfb6cb32bbfd0ab9fa565f18b1b88890ac4",
14
+ "package": "react-native-windows"
15
+ }
16
+ ]
17
+ }
18
+ },
19
+ {
20
+ "date": "Mon, 31 Jan 2022 16:12:18 GMT",
21
+ "tag": "react-native-windows_v0.65.11",
22
+ "version": "0.65.11",
23
+ "comments": {
24
+ "patch": [
25
+ {
26
+ "comment": "[0.65] Avoid capturing raw this pointer in WebSocket module",
27
+ "author": "julio.rocha@microsoft.com",
28
+ "commit": "6421adf1229ad6ee309b2c6cbf60aaa4007f670f",
29
+ "package": "react-native-windows"
30
+ }
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "date": "Mon, 17 Jan 2022 16:11:34 GMT",
36
+ "tag": "react-native-windows_v0.65.10",
37
+ "version": "0.65.10",
38
+ "comments": {
39
+ "patch": [
40
+ {
41
+ "comment": "Fork HoverState.js to allow hover events on Pressable",
42
+ "author": "saadnajmi2@gmail.com",
43
+ "commit": "5e51350579884c5db479729185f232df77a7e992",
44
+ "package": "react-native-windows"
45
+ }
46
+ ]
47
+ }
48
+ },
49
+ {
50
+ "date": "Mon, 29 Nov 2021 16:12:25 GMT",
51
+ "tag": "react-native-windows_v0.65.9",
52
+ "version": "0.65.9",
53
+ "comments": {
54
+ "patch": [
55
+ {
56
+ "comment": "[0.65] Make ADK dependency optional in dependency script",
57
+ "author": "jthysell@microsoft.com",
58
+ "commit": "e914a7396c6c31a1b12910bb705dff4aa2cbe253",
59
+ "package": "react-native-windows"
60
+ },
61
+ {
62
+ "comment": "Fix C# Module Event invocation",
63
+ "author": "vmorozov@microsoft.com",
64
+ "commit": "bce10a2d0aa3c074063a584fb25c0cbd969840ac",
65
+ "package": "react-native-windows"
66
+ }
67
+ ]
68
+ }
69
+ },
70
+ {
71
+ "date": "Mon, 15 Nov 2021 16:09:31 GMT",
6
72
  "tag": "react-native-windows_v0.65.8",
7
73
  "version": "0.65.8",
8
74
  "comments": {
package/CHANGELOG.md CHANGED
@@ -1,18 +1,51 @@
1
1
  # Change Log - react-native-windows
2
2
 
3
- This log was last generated on Mon, 15 Nov 2021 16:09:05 GMT and should not be manually modified.
3
+ This log was last generated on Mon, 07 Feb 2022 16:12:12 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
- ## 0.65.8
7
+ ## 0.65.12
8
8
 
9
- Mon, 15 Nov 2021 16:09:05 GMT
9
+ Mon, 07 Feb 2022 16:12:12 GMT
10
10
 
11
11
  ### Patches
12
12
 
13
- - Fix crash loading bundle in win32 (julio.rocha@microsoft.com)
14
- - Drop ChakraCore dependency (#9056) (julio.rocha@microsoft.com)
13
+ - Replace __APPLE__ with __clang__ where applicable (#9461) (julio.rocha@microsoft.com)
15
14
 
15
+ ## 0.65.11
16
+
17
+ Mon, 31 Jan 2022 16:12:18 GMT
18
+
19
+ ### Patches
20
+
21
+ - [0.65] Avoid capturing raw this pointer in WebSocket module (julio.rocha@microsoft.com)
22
+
23
+ ## 0.65.10
24
+
25
+ Mon, 17 Jan 2022 16:11:34 GMT
26
+
27
+ ### Patches
28
+
29
+ - Fork HoverState.js to allow hover events on Pressable (saadnajmi2@gmail.com)
30
+
31
+ ## 0.65.9
32
+
33
+ Mon, 29 Nov 2021 16:12:25 GMT
34
+
35
+ ### Patches
36
+
37
+ - [0.65] Make ADK dependency optional in dependency script (jthysell@microsoft.com)
38
+ - Fix C# Module Event invocation (vmorozov@microsoft.com)
39
+
40
+ ## 0.65.8
41
+
42
+ Mon, 15 Nov 2021 16:09:31 GMT
43
+
44
+ ### Patches
45
+
46
+ - Fix crash loading bundle in win32 (julio.rocha@microsoft.com)
47
+ - Drop ChakraCore dependency (#9056) (julio.rocha@microsoft.com)
48
+
16
49
  ## 0.65.7
17
50
 
18
51
  Mon, 01 Nov 2021 19:07:16 GMT
@@ -25,6 +25,7 @@ import usePressability from '../../Pressability/usePressability';
25
25
  import {normalizeRect, type RectOrSize} from '../../StyleSheet/Rect';
26
26
  import type {
27
27
  LayoutEvent,
28
+ MouseEvent,
28
29
  PressEvent,
29
30
  // [Windows
30
31
  BlurEvent,
@@ -71,6 +72,16 @@ type Props = $ReadOnly<{|
71
72
  */
72
73
  children: React.Node | ((state: StateCallbackType) => React.Node),
73
74
 
75
+ /**
76
+ * Duration to wait after hover in before calling `onHoverIn`.
77
+ */
78
+ delayHoverIn?: ?number,
79
+
80
+ /**
81
+ * Duration to wait after hover out before calling `onHoverOut`.
82
+ */
83
+ delayHoverOut?: ?number,
84
+
74
85
  /**
75
86
  * Duration (in milliseconds) from `onPressIn` before `onLongPress` is called.
76
87
  */
@@ -97,6 +108,16 @@ type Props = $ReadOnly<{|
97
108
  */
98
109
  onLayout?: ?(event: LayoutEvent) => mixed,
99
110
 
111
+ /**
112
+ * Called when the hover is activated to provide visual feedback.
113
+ */
114
+ onHoverIn?: ?(event: MouseEvent) => mixed,
115
+
116
+ /**
117
+ * Called when the hover is deactivated to undo visual feedback.
118
+ */
119
+ onHoverOut?: ?(event: MouseEvent) => mixed,
120
+
100
121
  /**
101
122
  * Called when a long-tap gesture is detected.
102
123
  */
@@ -180,9 +201,13 @@ function Pressable(props: Props, forwardedRef): React.Node {
180
201
  android_ripple,
181
202
  cancelable,
182
203
  children,
204
+ delayHoverIn,
205
+ delayHoverOut,
183
206
  delayLongPress,
184
207
  disabled,
185
208
  focusable,
209
+ onHoverIn,
210
+ onHoverOut,
186
211
  onLongPress,
187
212
  onPress,
188
213
  onPressIn,
@@ -246,8 +271,12 @@ function Pressable(props: Props, forwardedRef): React.Node {
246
271
  hitSlop,
247
272
  pressRectOffset: pressRetentionOffset,
248
273
  android_disableSound,
274
+ delayHoverIn,
275
+ delayHoverOut,
249
276
  delayLongPress,
250
277
  delayPressIn: unstable_pressDelay,
278
+ onHoverIn,
279
+ onHoverOut,
251
280
  onLongPress,
252
281
  onPress,
253
282
  onPressIn(event: PressEvent): void {
@@ -280,9 +309,13 @@ function Pressable(props: Props, forwardedRef): React.Node {
280
309
  android_disableSound,
281
310
  android_rippleConfig,
282
311
  cancelable,
312
+ delayHoverIn,
313
+ delayHoverOut,
283
314
  delayLongPress,
284
315
  disabled,
285
316
  hitSlop,
317
+ onHoverIn,
318
+ onHoverOut,
286
319
  onLongPress,
287
320
  onPress,
288
321
  onPressIn,
@@ -49,6 +49,10 @@ if (Platform.OS === 'web') {
49
49
  document.addEventListener('touchmove', disableHover, true);
50
50
  document.addEventListener('mousemove', enableHover, true);
51
51
  }
52
+ // [Windows
53
+ } else if (Platform.OS === 'windows') {
54
+ isEnabled = true;
55
+ // Windows]
52
56
  }
53
57
 
54
58
  export function isHoverEnabled(): boolean {
@@ -19,9 +19,9 @@ using winrt::Microsoft::ReactNative::implementation::QuirkSettings;
19
19
 
20
20
  namespace Microsoft::React {
21
21
 
22
- std::shared_ptr<IWebSocketResource> IWebSocketResource::Make(std::string &&urlString) {
22
+ std::shared_ptr<IWebSocketResource> IWebSocketResource::Make() {
23
23
  std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> certExceptions;
24
- return std::make_shared<WinRTWebSocketResource>(std::move(urlString), std::move(certExceptions));
24
+ return std::make_shared<WinRTWebSocketResource>(std::move(certExceptions));
25
25
  }
26
26
 
27
27
  } // namespace Microsoft::React
@@ -280,7 +280,7 @@ constexpr void ValidateCoroutineArg() noexcept {
280
280
  static_assert(
281
281
  !std::is_reference_v<TArg> && !std::is_pointer_v<TArg>,
282
282
  "Coroutine parameter must be passed by value for safe access"
283
- #ifndef __APPLE__
283
+ #ifndef __clang__
284
284
  ": " __FUNCSIG__
285
285
  #endif
286
286
  );
@@ -375,7 +375,7 @@ namespace Microsoft.ReactNative.Managed.CodeGen
375
375
  {
376
376
  // generates:
377
377
  // moduleBuilder.AddInitializer((IReactContext reactContext) =>
378
- // module.MyEvent = (ArgType0 arg0, ArgType1 arg1, ...) => reactContext.EmitJsEvent("eventEmitterName", "eventName", arg0, arg1, ...);
378
+ // module.MyEvent = (ArgType0 arg0, ArgType1 arg1, ...) => new ReactContext(reactContext).EmitJsEvent("eventEmitterName", "eventName", arg0, arg1, ...);
379
379
  return InvocationStatement(
380
380
  MemberAccessExpression(ReactNativeNames.ModuleBuilder, ReactNativeNames.AddInitializer),
381
381
  ParenthesizedLambdaExpression(
@@ -389,7 +389,7 @@ namespace Microsoft.ReactNative.Managed.CodeGen
389
389
  {
390
390
  // generates:
391
391
  // moduleBuilder.AddInitializer((IReactContext reactContext) =>
392
- // module.MyEvent = (ArgType0 arg0, ArgType1 arg1, ...) => reactContext.EmitJsFunction("moduleName", "eventName", arg0, arg1, ...);
392
+ // module.MyEvent = (ArgType0 arg0, ArgType1 arg1, ...) => new ReactContext(reactContext).EmitJsFunction("moduleName", "eventName", arg0, arg1, ...);
393
393
  return InvocationStatement(
394
394
  MemberAccessExpression(ReactNativeNames.ModuleBuilder, ReactNativeNames.AddInitializer),
395
395
  ParenthesizedLambdaExpression(
@@ -411,7 +411,7 @@ namespace Microsoft.ReactNative.Managed.CodeGen
411
411
  block: null,
412
412
  expressionBody: InvocationExpression(
413
413
  MemberAccessExpression(ReactNativeNames.Module, Identifier(initializer.Method.Name)),
414
- ObjectCreationExpression(ReactTypes.ReactContext, IdentifierName((ReactNativeNames.ReactContextLocalName)))
414
+ ObjectCreationExpression(ReactTypes.ReactContext, IdentifierName(ReactNativeNames.ReactContextLocalName))
415
415
  )));
416
416
  }
417
417
 
@@ -420,7 +420,8 @@ namespace Microsoft.ReactNative.Managed.CodeGen
420
420
 
421
421
  var lambdaParams = new List<ParameterSyntax>(callback.CallbackParameters.Length);
422
422
  var arguments = new List<ArgumentSyntax>(callback.CallbackParameters.Length);
423
- arguments.Add(Argument(IdentifierName(ReactNativeNames.WriterLocalName)));
423
+ arguments.Add(Argument(LiteralExpression(callback.CallbackContextName)));
424
+ arguments.Add(Argument(LiteralExpression(callback.Name)));
424
425
 
425
426
  for (int i = 0; i < callback.CallbackParameters.Length; i++)
426
427
  {
@@ -433,10 +434,10 @@ namespace Microsoft.ReactNative.Managed.CodeGen
433
434
 
434
435
  // generates:
435
436
  // module.<callackName> = (ArgType0 arg0, ArgType1 arg0, ...) =>
436
- // reactContext.<contextCallbackMethod>(
437
+ // new ReactContext(reactContext).<contextCallbackMethod>(
437
438
  // eventEmitterName,
438
439
  // eventName,
439
- // writer => writer.WriteArgs(arg0, arg1, ...)
440
+ // arg0, arg1, ...
440
441
  // )
441
442
  return
442
443
  AssignmentExpression(
@@ -446,16 +447,11 @@ namespace Microsoft.ReactNative.Managed.CodeGen
446
447
  parameterList: ParameterList(lambdaParams.ToArray()),
447
448
  block: null,
448
449
  expressionBody: InvocationExpression(
449
- MemberAccessExpression(ReactNativeNames.ReactContextLocalName, contextCallbackMethod),
450
- LiteralExpression(callback.CallbackContextName),
451
- LiteralExpression(callback.Name),
452
- ParenthesizedLambdaExpression(
453
- parameterList: ParameterList(Parameter(ReactNativeNames.WriterLocalName)),
454
- block: null,
455
- expressionBody: InvocationExpression(
456
- MemberAccessExpression(ReactTypes.JSValueWriter, ReactNativeNames.WriteArgsMethodName),
457
- arguments
458
- )))));
450
+ MemberAccessExpression(
451
+ ObjectCreationExpression(ReactTypes.ReactContext, IdentifierName(ReactNativeNames.ReactContextLocalName)),
452
+ contextCallbackMethod),
453
+ arguments
454
+ )));
459
455
  }
460
456
 
461
457
  private string GetMethodReturnTypeFromStyle(ReactMethod.MethodReturnStyle returnStyle)
@@ -38,20 +38,28 @@ namespace Microsoft.ReactNative.Managed.CodeGen
38
38
  return InvocationStatement(SyntaxFactory.IdentifierName(methodName), arguments);
39
39
  }
40
40
 
41
- internal static ExpressionSyntax MemberAccessExpression(SyntaxToken instance, SyntaxToken method)
41
+ internal static ExpressionSyntax MemberAccessExpression(ExpressionSyntax instance, SyntaxToken member)
42
+ {
43
+ return SyntaxFactory.MemberAccessExpression(
44
+ SyntaxKind.SimpleMemberAccessExpression,
45
+ instance,
46
+ SyntaxFactory.IdentifierName(member));
47
+ }
48
+
49
+ internal static ExpressionSyntax MemberAccessExpression(SyntaxToken instance, SyntaxToken member)
42
50
  {
43
51
  return SyntaxFactory.MemberAccessExpression(
44
52
  SyntaxKind.SimpleMemberAccessExpression,
45
53
  SyntaxFactory.IdentifierName(instance),
46
- SyntaxFactory.IdentifierName(method));
54
+ SyntaxFactory.IdentifierName(member));
47
55
  }
48
56
 
49
- internal static ExpressionSyntax MemberAccessExpression(ISymbol type, SyntaxToken method)
57
+ internal static ExpressionSyntax MemberAccessExpression(ISymbol type, SyntaxToken member)
50
58
  {
51
59
  return SyntaxFactory.MemberAccessExpression(
52
60
  SyntaxKind.SimpleMemberAccessExpression,
53
61
  type.ToTypeSyntax(),
54
- SyntaxFactory.IdentifierName(method));
62
+ SyntaxFactory.IdentifierName(member));
55
63
  }
56
64
 
57
65
  internal static StatementSyntax LocalDeclarationStatement(ISymbol type, SyntaxToken variableName, ExpressionSyntax initializer)
@@ -331,6 +331,7 @@ $requirements = @(
331
331
  Tags = @('buildLab');
332
332
  Valid = (Test-Path "${env:ProgramFiles(x86)}\Windows Kits\10\Windows Performance Toolkit\wpr.exe");
333
333
  Install = { choco install -y windows-adk };
334
+ Optional = $true
334
335
  },
335
336
  @{
336
337
  Id=[CheckId]::RNWClone;
@@ -79,17 +79,17 @@ struct IWebSocketResource {
79
79
  /// <summary>
80
80
  /// Creates an <c>IWebSocketResource</c> instance.
81
81
  /// </summary>
82
- /// <param name="url">
83
- /// WebSocket URL address the instance will connect to.
84
- /// The address's scheme can be either ws:// or wss://.
85
- /// </param>
86
- static std::shared_ptr<IWebSocketResource> Make(std::string &&url);
82
+ static std::shared_ptr<IWebSocketResource> Make();
87
83
 
88
84
  virtual ~IWebSocketResource() noexcept {}
89
85
 
90
86
  /// <summary>
91
87
  /// Establishes a continuous connection with the remote endpoint.
92
88
  /// </summary>
89
+ /// <param name="url">
90
+ /// WebSocket URL address the instance will connect to.
91
+ /// The address's scheme can be either ws:// or wss://.
92
+ /// </param>
93
93
  /// <param name="protocols">
94
94
  /// Currently unused
95
95
  /// </param>
@@ -97,7 +97,7 @@ struct IWebSocketResource {
97
97
  /// HTTP header fields passed by the remote endpoint, to be used in the
98
98
  /// handshake process.
99
99
  /// </param>
100
- virtual void Connect(const Protocols &protocols = {}, const Options &options = {}) noexcept = 0;
100
+ virtual void Connect(std::string &&url, const Protocols &protocols = {}, const Options &options = {}) noexcept = 0;
101
101
 
102
102
  /// <summary>
103
103
  /// Sends a ping frame to the remote endpoint.
@@ -164,8 +164,7 @@ winrt::fire_and_forget InspectorPackagerConnection::connectAsync() {
164
164
  co_await winrt::resume_background();
165
165
 
166
166
  std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> certExceptions;
167
- m_packagerWebSocketConnection =
168
- std::make_shared<Microsoft::React::WinRTWebSocketResource>(m_url, std::move(certExceptions));
167
+ m_packagerWebSocketConnection = std::make_shared<Microsoft::React::WinRTWebSocketResource>(std::move(certExceptions));
169
168
 
170
169
  m_packagerWebSocketConnection->SetOnError([](const Microsoft::React::IWebSocketResource::Error &err) {
171
170
  facebook::react::tracing::error(err.Message.c_str());
@@ -230,7 +229,7 @@ winrt::fire_and_forget InspectorPackagerConnection::connectAsync() {
230
229
 
231
230
  Microsoft::React::IWebSocketResource::Protocols protocols;
232
231
  Microsoft::React::IWebSocketResource::Options options;
233
- m_packagerWebSocketConnection->Connect(protocols, options);
232
+ m_packagerWebSocketConnection->Connect(std::string{m_url}, protocols, options);
234
233
 
235
234
  co_return;
236
235
  }
@@ -14,7 +14,9 @@
14
14
  #include <iomanip>
15
15
 
16
16
  using namespace facebook::xplat;
17
- using namespace folly;
17
+
18
+ using facebook::react::Instance;
19
+ using folly::dynamic;
18
20
 
19
21
  using Microsoft::Common::Unicode::Utf16ToUtf8;
20
22
  using Microsoft::Common::Unicode::Utf8ToUtf16;
@@ -24,17 +26,111 @@ using std::string;
24
26
  using std::weak_ptr;
25
27
 
26
28
  namespace {
29
+ using Microsoft::React::IWebSocketResource;
30
+ using Microsoft::React::WebSocketModule;
31
+
27
32
  constexpr char moduleName[] = "WebSocketModule";
33
+
34
+ static void SendEvent(weak_ptr<Instance> weakInstance, string &&eventName, dynamic &&args) {
35
+ if (auto instance = weakInstance.lock()) {
36
+ instance->callJSFunction("RCTDeviceEventEmitter", "emit", dynamic::array(std::move(eventName), std::move(args)));
37
+ }
38
+ }
39
+
40
+ static shared_ptr<IWebSocketResource>
41
+ GetOrCreateWebSocket(int64_t id, string &&url, weak_ptr<WebSocketModule::SharedState> weakState) {
42
+ auto state = weakState.lock();
43
+ if (!state) {
44
+ return nullptr;
45
+ }
46
+
47
+ auto itr = state->ResourceMap.find(id);
48
+ if (itr == state->ResourceMap.end()) {
49
+ if (!state->Module) {
50
+ return nullptr;
51
+ }
52
+ auto weakInstance = state->Module->getInstance();
53
+
54
+ shared_ptr<IWebSocketResource> ws;
55
+ try {
56
+ ws = state->ResourceFactory(std::move(url));
57
+ } catch (const winrt::hresult_error &e) {
58
+ std::stringstream ss;
59
+ ss << "[" << std::hex << std::showbase << std::setw(8) << static_cast<uint32_t>(e.code()) << "] "
60
+ << winrt::to_string(e.message());
61
+
62
+ SendEvent(weakInstance, "webSocketFailed", dynamic::object("id", id)("message", std::move(ss.str())));
63
+
64
+ return nullptr;
65
+ } catch (const std::exception &e) {
66
+ SendEvent(weakInstance, "webSocketFailed", dynamic::object("id", id)("message", e.what()));
67
+
68
+ return nullptr;
69
+ } catch (...) {
70
+ SendEvent(
71
+ weakInstance,
72
+ "webSocketFailed",
73
+ dynamic::object("id", id)("message", "Unidentified error creating IWebSocketResource"));
74
+
75
+ return nullptr;
76
+ }
77
+
78
+ ws->SetOnError([id, weakInstance](const IWebSocketResource::Error &err) {
79
+ auto strongInstance = weakInstance.lock();
80
+ if (!strongInstance)
81
+ return;
82
+
83
+ auto errorObj = dynamic::object("id", id)("message", err.Message);
84
+ SendEvent(weakInstance, "websocketFailed", std::move(errorObj));
85
+ });
86
+ ws->SetOnConnect([id, weakInstance]() {
87
+ auto strongInstance = weakInstance.lock();
88
+ if (!strongInstance)
89
+ return;
90
+
91
+ auto args = dynamic::object("id", id);
92
+ SendEvent(weakInstance, "websocketOpen", std::move(args));
93
+ });
94
+ ws->SetOnMessage([id, weakInstance](size_t length, const string &message, bool isBinary) {
95
+ auto strongInstance = weakInstance.lock();
96
+ if (!strongInstance)
97
+ return;
98
+
99
+ auto args = dynamic::object("id", id)("data", message)("type", isBinary ? "binary" : "text");
100
+ SendEvent(weakInstance, "websocketMessage", std::move(args));
101
+ });
102
+ ws->SetOnClose([id, weakInstance](IWebSocketResource::CloseCode code, const string &reason) {
103
+ auto strongInstance = weakInstance.lock();
104
+ if (!strongInstance)
105
+ return;
106
+
107
+ auto args = dynamic::object("id", id)("code", static_cast<uint16_t>(code))("reason", reason);
108
+ SendEvent(weakInstance, "websocketClosed", std::move(args));
109
+ });
110
+
111
+ state->ResourceMap.emplace(id, ws);
112
+ return ws;
113
+ }
114
+
115
+ return itr->second;
116
+ }
117
+
28
118
  } // anonymous namespace
29
119
 
30
120
  namespace Microsoft::React {
31
121
 
32
- WebSocketModule::WebSocketModule()
33
- : m_resourceFactory{[](string &&url) { return IWebSocketResource::Make(std::move(url)); }} {}
122
+ WebSocketModule::WebSocketModule() : m_sharedState{std::make_shared<SharedState>()} {
123
+ m_sharedState->ResourceFactory = [](string &&url) { return IWebSocketResource::Make(); };
124
+ m_sharedState->Module = this;
125
+ }
126
+
127
+ WebSocketModule::~WebSocketModule() noexcept /*override*/ {
128
+ m_sharedState->Module = nullptr;
129
+ }
34
130
 
35
131
  void WebSocketModule::SetResourceFactory(
36
132
  std::function<shared_ptr<IWebSocketResource>(const string &)> &&resourceFactory) {
37
- m_resourceFactory = std::move(resourceFactory);
133
+ m_sharedState->ResourceFactory = std::move(resourceFactory);
38
134
  }
39
135
 
40
136
  string WebSocketModule::getName() {
@@ -50,9 +146,9 @@ std::vector<facebook::xplat::module::CxxModule::Method> WebSocketModule::getMeth
50
146
  {
51
147
  return
52
148
  {
53
- Method(
149
+ {
54
150
  "connect",
55
- [this](dynamic args) // const string& url, dynamic protocols, dynamic options, int64_t id
151
+ [weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) // const string& url, dynamic protocols, dynamic options, int64_t id
56
152
  {
57
153
  IWebSocketResource::Protocols protocols;
58
154
  dynamic protocolsDynamic = jsArgAsDynamic(args, 1);
@@ -75,20 +171,21 @@ std::vector<facebook::xplat::module::CxxModule::Method> WebSocketModule::getMeth
75
171
  }
76
172
  }
77
173
 
78
- weak_ptr weakWs = this->GetOrCreateWebSocket(jsArgAsInt(args, 3), jsArgAsString(args, 0));
174
+ weak_ptr weakWs = GetOrCreateWebSocket(jsArgAsInt(args, 3), jsArgAsString(args, 0), weakState);
79
175
  if (auto sharedWs = weakWs.lock())
80
176
  {
81
- sharedWs->Connect(protocols, options);
177
+ sharedWs->Connect(jsArgAsString(args, 0), protocols, options);
82
178
  }
83
- }),
84
- Method(
179
+ }
180
+ },
181
+ {
85
182
  "close",
86
- [this](dynamic args) // [int64_t code, string reason,] int64_t id
183
+ [weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) // [int64_t code, string reason,] int64_t id
87
184
  {
88
185
  // See react-native\Libraries\WebSocket\WebSocket.js:_close
89
186
  if (args.size() == 3) // WebSocketModule.close(statusCode, closeReason, this._socketId);
90
187
  {
91
- weak_ptr weakWs = this->GetOrCreateWebSocket(jsArgAsInt(args, 2));
188
+ weak_ptr weakWs = GetOrCreateWebSocket(jsArgAsInt(args, 2), {}, weakState);
92
189
  if (auto sharedWs = weakWs.lock())
93
190
  {
94
191
  sharedWs->Close(static_cast<IWebSocketResource::CloseCode>(jsArgAsInt(args, 0)), jsArgAsString(args, 1));
@@ -96,7 +193,7 @@ std::vector<facebook::xplat::module::CxxModule::Method> WebSocketModule::getMeth
96
193
  }
97
194
  else if (args.size() == 1) // WebSocketModule.close(this._socketId);
98
195
  {
99
- weak_ptr weakWs = this->GetOrCreateWebSocket(jsArgAsInt(args, 0));
196
+ weak_ptr weakWs = GetOrCreateWebSocket(jsArgAsInt(args, 0), {}, weakState);
100
197
  if (auto sharedWs = weakWs.lock())
101
198
  {
102
199
  sharedWs->Close(IWebSocketResource::CloseCode::Normal, {});
@@ -104,137 +201,53 @@ std::vector<facebook::xplat::module::CxxModule::Method> WebSocketModule::getMeth
104
201
  }
105
202
  else
106
203
  {
107
- auto errorObj = dynamic::object("id", -1)("message", "Incorrect number of parameters");
108
- this->SendEvent("websocketFailed", std::move(errorObj));
204
+ auto state = weakState.lock();
205
+ if (state && state->Module) {
206
+ auto errorObj = dynamic::object("id", -1)("message", "Incorrect number of parameters");
207
+ SendEvent(state->Module->getInstance(), "websocketFailed", std::move(errorObj));
208
+ }
109
209
  }
110
- }),
111
- Method(
210
+ }
211
+ },
212
+ {
112
213
  "send",
113
- [this](dynamic args) // const string& message, int64_t id
214
+ [weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) // const string& message, int64_t id
114
215
  {
115
- weak_ptr weakWs = this->GetOrCreateWebSocket(jsArgAsInt(args, 1));
216
+ weak_ptr weakWs = GetOrCreateWebSocket(jsArgAsInt(args, 1), {}, weakState);
116
217
  if (auto sharedWs = weakWs.lock())
117
218
  {
118
219
  sharedWs->Send(jsArgAsString(args, 0));
119
220
  }
120
- }),
121
- Method(
221
+ }
222
+ },
223
+ {
122
224
  "sendBinary",
123
- [this](dynamic args) // const string& base64String, int64_t id
225
+ [weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) // const string& base64String, int64_t id
124
226
  {
125
- weak_ptr weakWs = this->GetOrCreateWebSocket(jsArgAsInt(args, 1));
227
+ weak_ptr weakWs = GetOrCreateWebSocket(jsArgAsInt(args, 1), {}, weakState);
126
228
  if (auto sharedWs = weakWs.lock())
127
229
  {
128
230
  sharedWs->SendBinary(jsArgAsString(args, 0));
129
231
  }
130
- }),
131
- Method(
232
+ }
233
+ },
234
+ {
132
235
  "ping",
133
- [this](dynamic args) // int64_t id
236
+ [weakState = weak_ptr<SharedState>(m_sharedState)](dynamic args) // int64_t id
134
237
  {
135
- weak_ptr weakWs = this->GetOrCreateWebSocket(jsArgAsInt(args, 0));
238
+ weak_ptr weakWs = GetOrCreateWebSocket(jsArgAsInt(args, 0), {}, weakState);
136
239
  if (auto sharedWs = weakWs.lock())
137
240
  {
138
241
  sharedWs->Ping();
139
242
  }
140
- })
243
+ }
244
+ }
141
245
  };
142
246
  } // getMethods
143
247
  // clang-format on
144
248
 
145
- #pragma region private members
146
-
147
- void WebSocketModule::SendEvent(string &&eventName, dynamic &&args) {
148
- auto weakInstance = this->getInstance();
149
- if (auto instance = weakInstance.lock()) {
150
- instance->callJSFunction("RCTDeviceEventEmitter", "emit", dynamic::array(std::move(eventName), std::move(args)));
151
- }
152
- }
153
-
154
- // clang-format off
155
- shared_ptr<IWebSocketResource> WebSocketModule::GetOrCreateWebSocket(int64_t id, string&& url)
156
- {
157
- auto itr = m_webSockets.find(id);
158
- if (itr == m_webSockets.end())
159
- {
160
- shared_ptr<IWebSocketResource> ws;
161
- try
162
- {
163
- ws = m_resourceFactory(std::move(url));
164
- }
165
- catch (const winrt::hresult_error& e)
166
- {
167
- std::wstringstream ss;
168
- ss << L"[" << std::hex << std::showbase << std::setw(8) << static_cast<uint32_t>(e.code()) << L"] " << e.message().c_str();
169
- string message{winrt::to_string(ss.str()).c_str()};
170
-
171
- SendEvent("webSocketFailed", dynamic::object("id", id)("message", std::move(message)));
172
-
173
- return nullptr;
174
- }
175
- catch (const std::exception& e)
176
- {
177
- SendEvent("webSocketFailed", dynamic::object("id", id)("message", e.what()));
178
-
179
- return nullptr;
180
- }
181
- catch (...)
182
- {
183
- SendEvent("webSocketFailed", dynamic::object("id", id)("message", "Unidentified error creating IWebSocketResource"));
184
-
185
- return nullptr;
186
- }
187
-
188
- auto weakInstance = this->getInstance();
189
- ws->SetOnError([this, id, weakInstance](const IWebSocketResource::Error& err)
190
- {
191
- auto strongInstance = weakInstance.lock();
192
- if (!strongInstance)
193
- return;
194
-
195
- auto errorObj = dynamic::object("id", id)("message", err.Message);
196
- this->SendEvent("websocketFailed", std::move(errorObj));
197
- });
198
- ws->SetOnConnect([this, id, weakInstance]()
199
- {
200
- auto strongInstance = weakInstance.lock();
201
- if (!strongInstance)
202
- return;
203
-
204
- auto args = dynamic::object("id", id);
205
- this->SendEvent("websocketOpen", std::move(args));
206
- });
207
- ws->SetOnMessage([this, id, weakInstance](size_t length, const string& message, bool isBinary)
208
- {
209
- auto strongInstance = weakInstance.lock();
210
- if (!strongInstance)
211
- return;
212
-
213
- auto args = dynamic::object("id", id)("data", message)("type", isBinary ? "binary" : "text");
214
- this->SendEvent("websocketMessage", std::move(args));
215
- });
216
- ws->SetOnClose([this, id, weakInstance](IWebSocketResource::CloseCode code, const string& reason)
217
- {
218
- auto strongInstance = weakInstance.lock();
219
- if (!strongInstance)
220
- return;
221
-
222
- auto args = dynamic::object("id", id)("code", static_cast<uint16_t>(code))("reason", reason);
223
- this->SendEvent("websocketClosed", std::move(args));
224
- });
225
-
226
- m_webSockets.emplace(id, ws);
227
- return ws;
228
- }
229
-
230
- return itr->second;
231
- }
232
- // clang-format on
233
-
234
- #pragma endregion private members
235
-
236
249
  /*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateWebSocketModule() noexcept {
237
- return make_unique<WebSocketModule>();
250
+ return std::make_unique<WebSocketModule>();
238
251
  }
239
252
 
240
253
  } // namespace Microsoft::React
@@ -18,6 +18,26 @@ class WebSocketModule : public facebook::xplat::module::CxxModule {
18
18
 
19
19
  WebSocketModule();
20
20
 
21
+ ~WebSocketModule() noexcept override;
22
+
23
+ struct SharedState {
24
+ /// <summary>
25
+ /// Keeps <c>IWebSocketResource</c> instances identified by <c>id</c>.
26
+ /// As defined in WebSocket.js.
27
+ /// </summary>
28
+ std::map<int64_t, std::shared_ptr<IWebSocketResource>> ResourceMap{};
29
+
30
+ /// <summary>
31
+ /// Generates IWebSocketResource instances, defaulting to IWebSocketResource::Make.
32
+ /// </summary>
33
+ std::function<std::shared_ptr<IWebSocketResource>(std::string &&)> ResourceFactory;
34
+
35
+ /// <summary>
36
+ /// Keeps a raw reference to the module object to lazily retrieve the React Instance as needed.
37
+ /// </summary>
38
+ CxxModule *Module{nullptr};
39
+ };
40
+
21
41
  #pragma region CxxModule overrides
22
42
 
23
43
  /// <summary>
@@ -41,16 +61,6 @@ class WebSocketModule : public facebook::xplat::module::CxxModule {
41
61
  void SetResourceFactory(std::function<std::shared_ptr<IWebSocketResource>(const std::string &)> &&resourceFactory);
42
62
 
43
63
  private:
44
- /// <summary>
45
- /// Notifies an event to the current React Instance.
46
- /// </summary>
47
- void SendEvent(std::string &&eventName, folly::dynamic &&parameters);
48
-
49
- /// <summary>
50
- /// Creates or retrieves a raw <c>IWebSocketResource</c> pointer.
51
- /// </summary>
52
- std::shared_ptr<IWebSocketResource> GetOrCreateWebSocket(std::int64_t id, std::string &&url = {});
53
-
54
64
  /// <summary>
55
65
  /// Keeps <c>IWebSocketResource</c> instances identified by <c>id</c>.
56
66
  /// As defined in WebSocket.js.
@@ -58,9 +68,9 @@ class WebSocketModule : public facebook::xplat::module::CxxModule {
58
68
  std::map<int64_t, std::shared_ptr<IWebSocketResource>> m_webSockets;
59
69
 
60
70
  /// <summary>
61
- /// Generates IWebSocketResource instances, defaulting to IWebSocketResource::Make.
71
+ /// Keeps members that can be accessed threads other than this module's owner accessible.
62
72
  /// </summary>
63
- std::function<std::shared_ptr<IWebSocketResource>(std::string &&)> m_resourceFactory;
73
+ std::shared_ptr<SharedState> m_sharedState;
64
74
  };
65
75
 
66
76
  } // namespace Microsoft::React
@@ -90,29 +90,21 @@ namespace Microsoft::React {
90
90
  // private
91
91
  WinRTWebSocketResource::WinRTWebSocketResource(
92
92
  IMessageWebSocket &&socket,
93
- Uri &&uri,
94
93
  vector<ChainValidationResult> &&certExceptions)
95
- : WinRTWebSocketResource(
96
- std::move(socket),
97
- DataWriter{socket.OutputStream()},
98
- std::move(uri),
99
- std::move(certExceptions)) {}
94
+ : WinRTWebSocketResource(std::move(socket), DataWriter{socket.OutputStream()}, std::move(certExceptions)) {}
100
95
 
101
96
  WinRTWebSocketResource::WinRTWebSocketResource(
102
97
  IMessageWebSocket &&socket,
103
98
  IDataWriter &&writer,
104
- Uri &&uri,
105
99
  vector<ChainValidationResult> &&certExceptions)
106
- : m_uri{std::move(uri)}, m_socket{std::move(socket)}, m_writer{std::move(writer)} {
107
- m_socket.MessageReceived({this, &WinRTWebSocketResource::OnMessageReceived});
108
-
100
+ : m_socket{std::move(socket)}, m_writer{std::move(writer)} {
109
101
  for (const auto &certException : certExceptions) {
110
102
  m_socket.Control().IgnorableServerCertificateErrors().Append(certException);
111
103
  }
112
104
  }
113
105
 
114
- WinRTWebSocketResource::WinRTWebSocketResource(const string &urlString, vector<ChainValidationResult> &&certExceptions)
115
- : WinRTWebSocketResource(MessageWebSocket{}, Uri{winrt::to_hstring(urlString)}, std::move(certExceptions)) {}
106
+ WinRTWebSocketResource::WinRTWebSocketResource(vector<ChainValidationResult> &&certExceptions)
107
+ : WinRTWebSocketResource(MessageWebSocket{}, std::move(certExceptions)) {}
116
108
 
117
109
  WinRTWebSocketResource::~WinRTWebSocketResource() noexcept /*override*/
118
110
  {
@@ -123,13 +115,14 @@ WinRTWebSocketResource::~WinRTWebSocketResource() noexcept /*override*/
123
115
 
124
116
  #pragma region Private members
125
117
 
126
- IAsyncAction WinRTWebSocketResource::PerformConnect() noexcept {
118
+ IAsyncAction WinRTWebSocketResource::PerformConnect(Uri &&uri) noexcept {
127
119
  auto self = shared_from_this();
120
+ auto coUri = std::move(uri);
128
121
 
129
122
  co_await resume_background();
130
123
 
131
124
  try {
132
- auto async = self->m_socket.ConnectAsync(self->m_uri);
125
+ auto async = self->m_socket.ConnectAsync(coUri);
133
126
 
134
127
  co_await lessthrow_await_adapter<IAsyncAction>{async};
135
128
 
@@ -293,36 +286,6 @@ fire_and_forget WinRTWebSocketResource::PerformClose() noexcept {
293
286
  m_closePerformed.Set();
294
287
  }
295
288
 
296
- void WinRTWebSocketResource::OnMessageReceived(
297
- IWebSocket const &sender,
298
- IMessageWebSocketMessageReceivedEventArgs const &args) {
299
- try {
300
- string response;
301
- IDataReader reader = args.GetDataReader();
302
- auto len = reader.UnconsumedBufferLength();
303
- if (args.MessageType() == SocketMessageType::Utf8) {
304
- reader.UnicodeEncoding(UnicodeEncoding::Utf8);
305
- vector<uint8_t> data(len);
306
- reader.ReadBytes(data);
307
-
308
- response = string(CheckedReinterpretCast<char *>(data.data()), data.size());
309
- } else {
310
- auto buffer = reader.ReadBuffer(len);
311
- winrt::hstring data = CryptographicBuffer::EncodeToBase64String(buffer);
312
-
313
- response = winrt::to_string(std::wstring_view(data));
314
- }
315
-
316
- if (m_readHandler) {
317
- m_readHandler(response.length(), response, args.MessageType() == SocketMessageType::Binary);
318
- }
319
- } catch (hresult_error const &e) {
320
- if (m_errorHandler) {
321
- m_errorHandler({HResultToString(e), ErrorType::Receive});
322
- }
323
- }
324
- }
325
-
326
289
  void WinRTWebSocketResource::Synchronize() noexcept {
327
290
  // Ensure sequence of other operations
328
291
  if (m_connectRequested) {
@@ -334,7 +297,36 @@ void WinRTWebSocketResource::Synchronize() noexcept {
334
297
 
335
298
  #pragma region IWebSocketResource
336
299
 
337
- void WinRTWebSocketResource::Connect(const Protocols &protocols, const Options &options) noexcept {
300
+ void WinRTWebSocketResource::Connect(string &&url, const Protocols &protocols, const Options &options) noexcept {
301
+ m_socket.MessageReceived(
302
+ [self = shared_from_this()](IWebSocket const &sender, IMessageWebSocketMessageReceivedEventArgs const &args) {
303
+ try {
304
+ string response;
305
+ IDataReader reader = args.GetDataReader();
306
+ auto len = reader.UnconsumedBufferLength();
307
+ if (args.MessageType() == SocketMessageType::Utf8) {
308
+ reader.UnicodeEncoding(UnicodeEncoding::Utf8);
309
+ vector<uint8_t> data(len);
310
+ reader.ReadBytes(data);
311
+
312
+ response = string(CheckedReinterpretCast<char *>(data.data()), data.size());
313
+ } else {
314
+ auto buffer = reader.ReadBuffer(len);
315
+ winrt::hstring data = CryptographicBuffer::EncodeToBase64String(buffer);
316
+
317
+ response = winrt::to_string(std::wstring_view(data));
318
+ }
319
+
320
+ if (self->m_readHandler) {
321
+ self->m_readHandler(response.length(), response, args.MessageType() == SocketMessageType::Binary);
322
+ }
323
+ } catch (hresult_error const &e) {
324
+ if (self->m_errorHandler) {
325
+ self->m_errorHandler({HResultToString(e), ErrorType::Receive});
326
+ }
327
+ }
328
+ });
329
+
338
330
  m_readyState = ReadyState::Connecting;
339
331
 
340
332
  for (const auto &header : options) {
@@ -348,7 +340,24 @@ void WinRTWebSocketResource::Connect(const Protocols &protocols, const Options &
348
340
  }
349
341
 
350
342
  m_connectRequested = true;
351
- PerformConnect();
343
+
344
+ Uri uri{nullptr};
345
+ try {
346
+ uri = Uri{winrt::to_hstring(url)};
347
+ } catch (hresult_error const &e) {
348
+ if (m_errorHandler) {
349
+ m_errorHandler({HResultToString(e), ErrorType::Connection});
350
+ }
351
+
352
+ // Abort - Mark connection as concluded.
353
+ SetEvent(m_connectPerformed.get());
354
+ m_connectPerformedPromise.set_value();
355
+ m_connectRequested = false;
356
+
357
+ return;
358
+ }
359
+
360
+ PerformConnect(std::move(uri));
352
361
  }
353
362
 
354
363
  void WinRTWebSocketResource::Ping() noexcept {
@@ -17,7 +17,6 @@
17
17
  namespace Microsoft::React {
18
18
 
19
19
  class WinRTWebSocketResource : public IWebSocketResource, public std::enable_shared_from_this<WinRTWebSocketResource> {
20
- winrt::Windows::Foundation::Uri m_uri;
21
20
  winrt::Windows::Networking::Sockets::IMessageWebSocket m_socket;
22
21
  // TODO: Use or remove.
23
22
  winrt::Windows::Networking::Sockets::IMessageWebSocket::MessageReceived_revoker m_revoker;
@@ -45,28 +44,22 @@ class WinRTWebSocketResource : public IWebSocketResource, public std::enable_sha
45
44
 
46
45
  WinRTWebSocketResource(
47
46
  winrt::Windows::Networking::Sockets::IMessageWebSocket &&socket,
48
- winrt::Windows::Foundation::Uri &&uri,
49
47
  std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> &&certExceptions);
50
48
 
51
- winrt::Windows::Foundation::IAsyncAction PerformConnect() noexcept;
49
+ winrt::Windows::Foundation::IAsyncAction PerformConnect(winrt::Windows::Foundation::Uri &&uri) noexcept;
52
50
  winrt::fire_and_forget PerformPing() noexcept;
53
51
  winrt::fire_and_forget PerformWrite(std::string &&message, bool isBinary) noexcept;
54
52
  winrt::fire_and_forget PerformClose() noexcept;
55
53
 
56
- void OnMessageReceived(
57
- winrt::Windows::Networking::Sockets::IWebSocket const &sender,
58
- winrt::Windows::Networking::Sockets::IMessageWebSocketMessageReceivedEventArgs const &args);
59
54
  void Synchronize() noexcept;
60
55
 
61
56
  public:
62
57
  WinRTWebSocketResource(
63
58
  winrt::Windows::Networking::Sockets::IMessageWebSocket &&socket,
64
59
  winrt::Windows::Storage::Streams::IDataWriter &&writer,
65
- winrt::Windows::Foundation::Uri &&uri,
66
60
  std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> &&certExceptions);
67
61
 
68
62
  WinRTWebSocketResource(
69
- const std::string &urlString,
70
63
  std::vector<winrt::Windows::Security::Cryptography::Certificates::ChainValidationResult> &&certExceptions);
71
64
 
72
65
  ~WinRTWebSocketResource() noexcept override;
@@ -76,7 +69,7 @@ class WinRTWebSocketResource : public IWebSocketResource, public std::enable_sha
76
69
  /// <summary>
77
70
  /// <see cref="IWebSocketResource::Connect" />
78
71
  /// </summary>
79
- void Connect(const Protocols &protocols, const Options &options) noexcept override;
72
+ void Connect(std::string &&url, const Protocols &protocols, const Options &options) noexcept override;
80
73
 
81
74
  /// <summary>
82
75
  /// <see cref="IWebSocketResource::Ping" />
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-windows",
3
- "version": "0.65.8",
3
+ "version": "0.65.12",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",