react-native-windows 0.64.26 → 0.64.30

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.
@@ -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,133 +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;
249
+ /*extern*/ std::unique_ptr<facebook::xplat::module::CxxModule> CreateWebSocketModule() noexcept {
250
+ return std::make_unique<WebSocketModule>();
231
251
  }
232
- // clang-format on
233
-
234
- #pragma endregion private members
235
252
 
236
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
@@ -71,86 +71,6 @@ void initializeETW();
71
71
  void initializeJSHooks(facebook::jsi::Runtime &runtime, bool isProfiling);
72
72
  } // namespace facebook::react::tracing
73
73
 
74
- namespace {
75
-
76
- #if (defined(_MSC_VER) && !defined(WINRT))
77
-
78
- std::string GetJSBundleDirectory(
79
- const std::string &jsBundleBasePath,
80
- const std::string &jsBundleRelativePath) noexcept {
81
- // If there is a base path, use that to calculate the absolute path.
82
- if (jsBundleBasePath.length() > 0) {
83
- std::string jsBundleDirectory = jsBundleBasePath;
84
- if (jsBundleDirectory.back() != '\\')
85
- jsBundleDirectory += '\\';
86
-
87
- return jsBundleDirectory += jsBundleRelativePath;
88
- } else if (!PathIsRelativeA(jsBundleRelativePath.c_str())) {
89
- // If the given path is an absolute path, return it as-is
90
- return jsBundleRelativePath;
91
- }
92
- // Otherwise use the path of the executable file to construct the absolute
93
- // path.
94
- else {
95
- wchar_t modulePath[MAX_PATH];
96
-
97
- auto len = GetModuleFileNameW(nullptr, modulePath, _countof(modulePath));
98
-
99
- if (len == 0 || (len == _countof(modulePath) && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
100
- return jsBundleRelativePath;
101
-
102
- // remove the trailing filename as we are interested in only the path
103
- auto succeeded = PathRemoveFileSpecW(modulePath);
104
- if (!succeeded)
105
- return jsBundleRelativePath;
106
-
107
- std::string jsBundlePath = Microsoft::Common::Unicode::Utf16ToUtf8(modulePath, wcslen(modulePath));
108
- if (!jsBundlePath.empty() && jsBundlePath.back() != '\\')
109
- jsBundlePath += '\\';
110
-
111
- return jsBundlePath += jsBundleRelativePath;
112
- }
113
- }
114
-
115
- std::string GetJSBundleFilePath(const std::string &jsBundleBasePath, const std::string &jsBundleRelativePath) {
116
- auto jsBundleFilePath = GetJSBundleDirectory(jsBundleBasePath, jsBundleRelativePath);
117
-
118
- // Usually, the module name: "module name" + "." + "platform name", for
119
- // example "lpc.win32". If we can not find the the bundle.js file under the
120
- // normal folder, we are trying to find it under the folder without the dot
121
- // (e.g. "lpcwin32"). VSO:1997035 remove this code after we have better name
122
- // convension
123
- if (PathFileExistsA((jsBundleFilePath + "\\bundle.js").c_str())) {
124
- jsBundleFilePath += "\\bundle.js";
125
- } else {
126
- // remove the dot only if is belongs to the bundle file name.
127
- size_t lastDotPosition = jsBundleFilePath.find_last_of('.');
128
- size_t bundleFilePosition = jsBundleFilePath.find_last_of('\\');
129
- if (lastDotPosition != std::string::npos &&
130
- (bundleFilePosition == std::string::npos || lastDotPosition > bundleFilePosition)) {
131
- jsBundleFilePath.erase(lastDotPosition, 1);
132
- }
133
-
134
- jsBundleFilePath += "\\bundle.js";
135
-
136
- // Back before we have base path plumbed through, we made win32 force a
137
- // seperate folder for each bundle by appending bundle.js Now that we have
138
- // base path, we can handle multiple SDXs with the same index name so we
139
- // should switch to using the same scheme as all the other platforms (and
140
- // the bundle server)
141
- // TODO: We should remove all the previous logic and use the same names as
142
- // the other platforms...
143
- if (!PathFileExistsA(jsBundleFilePath.c_str())) {
144
- jsBundleFilePath = GetJSBundleDirectory(jsBundleBasePath, jsBundleRelativePath) + ".bundle";
145
- }
146
- }
147
-
148
- return jsBundleFilePath;
149
- }
150
- #endif
151
-
152
- } // namespace
153
-
154
74
  using namespace facebook;
155
75
  using namespace Microsoft::JSI;
156
76
 
@@ -553,26 +473,22 @@ void InstanceImpl::loadBundleInternal(std::string &&jsBundleRelativePath, bool s
553
473
  synchronously);
554
474
  } else {
555
475
  #if (defined(_MSC_VER) && !defined(WINRT))
556
- auto fullBundleFilePath = GetJSBundleFilePath(m_jsBundleBasePath, jsBundleRelativePath);
557
-
558
- // If fullBundleFilePath exists, load User bundle.
559
- // Otherwise all bundles (User and Platform) are loaded through
560
- // platformBundles.
561
- if (PathFileExistsA(fullBundleFilePath.c_str())) {
562
- auto bundleString = FileMappingBigString::fromPath(fullBundleFilePath);
563
- m_innerInstance->loadScriptFromString(std::move(bundleString), std::move(fullBundleFilePath), synchronously);
564
- }
565
-
476
+ std::string bundlePath = (fs::path(m_devSettings->bundleRootPath) / jsBundleRelativePath).string();
477
+ auto bundleString = FileMappingBigString::fromPath(bundlePath);
566
478
  #else
567
- std::string bundlePath =
568
- (fs::path(m_devSettings->bundleRootPath) / (jsBundleRelativePath + ".bundle")).u8string();
569
-
479
+ std::string bundlePath = (fs::path(m_devSettings->bundleRootPath) / (jsBundleRelativePath + ".bundle")).string();
570
480
  auto bundleString = std::make_unique<::react::uwp::StorageFileBigString>(bundlePath);
571
- m_innerInstance->loadScriptFromString(std::move(bundleString), jsBundleRelativePath, synchronously);
572
481
  #endif
482
+ m_innerInstance->loadScriptFromString(std::move(bundleString), std::move(jsBundleRelativePath), synchronously);
573
483
  }
574
484
  } catch (const std::exception &e) {
575
485
  m_devSettings->errorCallback(e.what());
486
+ } catch (const winrt::hresult_error &hrerr) {
487
+ std::stringstream ss;
488
+ ss << "[" << std::hex << std::showbase << std::setw(8) << static_cast<uint32_t>(hrerr.code()) << "] "
489
+ << winrt::to_string(hrerr.message());
490
+
491
+ m_devSettings->errorCallback(std::move(ss.str()));
576
492
  }
577
493
  }
578
494
 
@@ -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 {