React Socket
Summary: React ws implementations Reviewed By: antonk52 Differential Revision: D39053839 fbshipit-source-id: 7e68770c7bc4e0a0307679713a8b210bba2bbd0b
This commit is contained in:
committed by
Facebook GitHub Bot
parent
c2440b6660
commit
446bb042d0
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <folly/dynamic.h>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include "../../../../xplat/Flipper/FlipperScheduler.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperTransportTypes.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
class FlipperConnectionManager;
|
||||||
|
class ConnectionContextStore;
|
||||||
|
class FlipperReactBaseSocket {
|
||||||
|
public:
|
||||||
|
enum Status {
|
||||||
|
Unconnected,
|
||||||
|
Connecting,
|
||||||
|
Initializing,
|
||||||
|
Open,
|
||||||
|
ServerNotFound,
|
||||||
|
Failed,
|
||||||
|
Closed
|
||||||
|
};
|
||||||
|
FlipperReactBaseSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler)
|
||||||
|
: endpoint_(std::move(endpoint)),
|
||||||
|
payload_(std::move(payload)),
|
||||||
|
scheduler_(scheduler),
|
||||||
|
connectionContextStore_(nullptr) {}
|
||||||
|
FlipperReactBaseSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler,
|
||||||
|
ConnectionContextStore* connectionContextStore)
|
||||||
|
: endpoint_(std::move(endpoint)),
|
||||||
|
payload_(std::move(payload)),
|
||||||
|
scheduler_(scheduler),
|
||||||
|
connectionContextStore_(connectionContextStore) {}
|
||||||
|
|
||||||
|
FlipperReactBaseSocket(const FlipperReactBaseSocket&) = delete;
|
||||||
|
FlipperReactBaseSocket& operator=(const FlipperReactBaseSocket&) = delete;
|
||||||
|
|
||||||
|
virtual ~FlipperReactBaseSocket() {}
|
||||||
|
|
||||||
|
Status status() const {
|
||||||
|
return status_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setEventHandler(SocketEventHandler eventHandler) {
|
||||||
|
eventHandler_ = std::move(eventHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMessageHandler(SocketMessageHandler messageHandler) {
|
||||||
|
messageHandler_ = std::move(messageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool connect(FlipperConnectionManager* manager) = 0;
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
|
||||||
|
virtual void send(
|
||||||
|
const folly::dynamic& message,
|
||||||
|
SocketSendHandler completion) = 0;
|
||||||
|
virtual void send(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendHandler completion) = 0;
|
||||||
|
virtual void sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FlipperConnectionEndpoint endpoint_;
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload_;
|
||||||
|
Scheduler* scheduler_;
|
||||||
|
ConnectionContextStore* connectionContextStore_;
|
||||||
|
|
||||||
|
SocketEventHandler eventHandler_;
|
||||||
|
SocketMessageHandler messageHandler_;
|
||||||
|
std::atomic<Status> status_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FlipperReactSocket.h"
|
||||||
|
#include <folly/json.h>
|
||||||
|
#include <cctype>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include "../../../../xplat/Flipper/ConnectionContextStore.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperTransportTypes.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperURLSerializer.h"
|
||||||
|
#include "../../../../xplat/Flipper/Log.h"
|
||||||
|
#include "FlipperReactSocketClient.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
FlipperReactSocket::FlipperReactSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler)
|
||||||
|
: FlipperReactSocket(
|
||||||
|
std::move(endpoint),
|
||||||
|
std::move(payload),
|
||||||
|
scheduler,
|
||||||
|
nullptr) {}
|
||||||
|
|
||||||
|
FlipperReactSocket::FlipperReactSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler,
|
||||||
|
ConnectionContextStore* connectionContextStore) {
|
||||||
|
if (endpoint.secure) {
|
||||||
|
socket_ = std::make_unique<FlipperReactSocketClient>(
|
||||||
|
endpoint, std::move(payload), scheduler, connectionContextStore);
|
||||||
|
} else {
|
||||||
|
socket_ = std::make_unique<FlipperReactSocketClient>(
|
||||||
|
endpoint, std::move(payload), scheduler, connectionContextStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlipperReactSocket::~FlipperReactSocket() {}
|
||||||
|
|
||||||
|
void FlipperReactSocket::setEventHandler(SocketEventHandler eventHandler) {
|
||||||
|
socket_->setEventHandler(eventHandler);
|
||||||
|
}
|
||||||
|
void FlipperReactSocket::setMessageHandler(
|
||||||
|
SocketMessageHandler messageHandler) {
|
||||||
|
socket_->setMessageHandler(messageHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlipperReactSocket::connect(FlipperConnectionManager* manager) {
|
||||||
|
return socket_->connect(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocket::disconnect() {
|
||||||
|
socket_->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocket::send(
|
||||||
|
const folly::dynamic& message,
|
||||||
|
SocketSendHandler completion) {
|
||||||
|
socket_->send(message, completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocket::send(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendHandler completion) {
|
||||||
|
socket_->send(message, completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Only ever used for insecure connections to receive the device_id from a
|
||||||
|
signCertificate request. If the intended usage ever changes, then a better
|
||||||
|
approach needs to be put in place.
|
||||||
|
*/
|
||||||
|
void FlipperReactSocket::sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) {
|
||||||
|
socket_->sendExpectResponse(message, completion);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <folly/dynamic.h>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include "../../../../xplat/Flipper/FlipperSocket.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperSocketProvider.h"
|
||||||
|
#include "FlipperReactBaseSocket.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
class FlipperConnectionManager;
|
||||||
|
class ConnectionContextStore;
|
||||||
|
class FlipperReactSocket : public FlipperSocket {
|
||||||
|
public:
|
||||||
|
FlipperReactSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler);
|
||||||
|
FlipperReactSocket(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler,
|
||||||
|
ConnectionContextStore* connectionContextStore);
|
||||||
|
|
||||||
|
virtual ~FlipperReactSocket();
|
||||||
|
|
||||||
|
virtual void setEventHandler(SocketEventHandler eventHandler) override;
|
||||||
|
virtual void setMessageHandler(SocketMessageHandler messageHandler) override;
|
||||||
|
|
||||||
|
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||||
|
virtual void disconnect() override;
|
||||||
|
|
||||||
|
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||||
|
override;
|
||||||
|
virtual void send(const std::string& message, SocketSendHandler completion)
|
||||||
|
override;
|
||||||
|
virtual void sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unique_ptr<FlipperReactBaseSocket> socket_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FlipperWebSocketProvider : public FlipperSocketProvider {
|
||||||
|
public:
|
||||||
|
FlipperWebSocketProvider() {}
|
||||||
|
virtual std::unique_ptr<FlipperSocket> create(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler) override {
|
||||||
|
return std::make_unique<FlipperReactSocket>(
|
||||||
|
std::move(endpoint), std::move(payload), scheduler);
|
||||||
|
}
|
||||||
|
virtual std::unique_ptr<FlipperSocket> create(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler,
|
||||||
|
ConnectionContextStore* connectionContextStore) override {
|
||||||
|
return std::make_unique<FlipperReactSocket>(
|
||||||
|
std::move(endpoint),
|
||||||
|
std::move(payload),
|
||||||
|
scheduler,
|
||||||
|
connectionContextStore);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FlipperReactSocketClient.h"
|
||||||
|
|
||||||
|
#include <folly/json.h>
|
||||||
|
#include <winrt/Windows.Foundation.Collections.h>
|
||||||
|
#include <winrt/Windows.Security.Cryptography.Certificates.h>
|
||||||
|
#include <winrt/Windows.Storage.Streams.h>
|
||||||
|
#include <cctype>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include "../../../../xplat/Flipper/ConnectionContextStore.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperTransportTypes.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperURLSerializer.h"
|
||||||
|
#include "../../../../xplat/Flipper/Log.h"
|
||||||
|
|
||||||
|
using namespace winrt::Windows::Foundation;
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
static constexpr char* CERTIFICATE_FRIENDLY_NAME = "FlipperClientCertificate";
|
||||||
|
|
||||||
|
FlipperReactSocketClient::FlipperReactSocketClient(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler)
|
||||||
|
: FlipperReactSocketClient(
|
||||||
|
std::move(endpoint),
|
||||||
|
std::move(payload),
|
||||||
|
scheduler,
|
||||||
|
nullptr) {}
|
||||||
|
|
||||||
|
FlipperReactSocketClient::FlipperReactSocketClient(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler,
|
||||||
|
ConnectionContextStore* connectionContextStore)
|
||||||
|
: FlipperReactBaseSocket(
|
||||||
|
std::move(endpoint),
|
||||||
|
std::move(payload),
|
||||||
|
scheduler,
|
||||||
|
connectionContextStore) {
|
||||||
|
status_ = Status::Unconnected;
|
||||||
|
}
|
||||||
|
|
||||||
|
FlipperReactSocketClient::~FlipperReactSocketClient() {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::Certificate
|
||||||
|
FlipperReactSocketClient::findClientCertificateFromStore() {
|
||||||
|
using namespace winrt::Windows::Foundation::Collections;
|
||||||
|
using namespace winrt::Windows::Security::Cryptography::Certificates;
|
||||||
|
|
||||||
|
CertificateQuery query;
|
||||||
|
query.FriendlyName(winrt::to_hstring(CERTIFICATE_FRIENDLY_NAME));
|
||||||
|
|
||||||
|
try {
|
||||||
|
IVectorView<Certificate> certificates =
|
||||||
|
CertificateStores::FindAllAsync(query).get();
|
||||||
|
if (certificates.Size() > 0) {
|
||||||
|
Certificate certificate = certificates.GetAt(0);
|
||||||
|
return certificate;
|
||||||
|
}
|
||||||
|
} catch (winrt::hresult_error const& ex) {
|
||||||
|
/* winrt::hresult_error can be thrown whilst trying to find certificates,
|
||||||
|
* ignore. */
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::exception("Unable to find client certificate");
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::Certificate
|
||||||
|
FlipperReactSocketClient::installClientCertificate() {
|
||||||
|
using namespace winrt::Windows::Foundation;
|
||||||
|
using namespace winrt::Windows::Storage;
|
||||||
|
using namespace winrt::Windows::Security::Cryptography;
|
||||||
|
using namespace winrt::Windows::Security::Cryptography::Certificates;
|
||||||
|
|
||||||
|
auto clientCertificateInfo = connectionContextStore_->getCertificate();
|
||||||
|
if (clientCertificateInfo.first.empty() ||
|
||||||
|
clientCertificateInfo.second.empty()) {
|
||||||
|
throw std::exception("Unable to generate PKCS12");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
StorageFile clientCertificateFile =
|
||||||
|
StorageFile::GetFileFromPathAsync(
|
||||||
|
winrt::to_hstring(clientCertificateInfo.first))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
auto buffer = FileIO::ReadBufferAsync(clientCertificateFile).get();
|
||||||
|
winrt::hstring clientCertificateData =
|
||||||
|
CryptographicBuffer::EncodeToBase64String(buffer);
|
||||||
|
auto password = winrt::to_hstring(clientCertificateInfo.second);
|
||||||
|
|
||||||
|
Certificates::CertificateEnrollmentManager::ImportPfxDataAsync(
|
||||||
|
clientCertificateData,
|
||||||
|
password,
|
||||||
|
ExportOption::Exportable,
|
||||||
|
KeyProtectionLevel::NoConsent,
|
||||||
|
InstallOptions::DeleteExpired,
|
||||||
|
winrt::to_hstring(CERTIFICATE_FRIENDLY_NAME))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return findClientCertificateFromStore();
|
||||||
|
} catch (winrt::hresult_error const& ex) {
|
||||||
|
/* winrt::hresult_error can be thrown whilst trying to install the
|
||||||
|
* certificate, ignore. */
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::exception("Unable to install client certificate");
|
||||||
|
}
|
||||||
|
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::Certificate
|
||||||
|
FlipperReactSocketClient::getClientCertificate() {
|
||||||
|
using namespace winrt::Windows::Security::Cryptography::Certificates;
|
||||||
|
try {
|
||||||
|
return findClientCertificateFromStore();
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
/* Client certificate may not be in the certificate store,
|
||||||
|
if so, try to install it. Ignore exception. */
|
||||||
|
}
|
||||||
|
|
||||||
|
return installClientCertificate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlipperReactSocketClient::connect(FlipperConnectionManager* manager) {
|
||||||
|
if (status_ != Status::Unconnected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_ = Status::Connecting;
|
||||||
|
|
||||||
|
std::string connectionURL = endpoint_.secure ? "wss://" : "ws://";
|
||||||
|
connectionURL += endpoint_.host.c_str();
|
||||||
|
connectionURL += ":";
|
||||||
|
connectionURL += std::to_string(endpoint_.port);
|
||||||
|
|
||||||
|
auto serializer = URLSerializer{};
|
||||||
|
payload_->serialize(serializer);
|
||||||
|
auto payload = serializer.serialize();
|
||||||
|
|
||||||
|
if (payload.size()) {
|
||||||
|
connectionURL += "/?";
|
||||||
|
connectionURL += payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto uri = winrt::to_hstring(connectionURL);
|
||||||
|
|
||||||
|
socket_.Control().MessageType(
|
||||||
|
winrt::Windows::Networking::Sockets::SocketMessageType::Utf8);
|
||||||
|
|
||||||
|
if (endpoint_.secure) {
|
||||||
|
socket_.Control().ClientCertificate(getClientCertificate());
|
||||||
|
socket_.Control().IgnorableServerCertificateErrors().Append(
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::
|
||||||
|
ChainValidationResult::Untrusted);
|
||||||
|
socket_.Control().IgnorableServerCertificateErrors().Append(
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::
|
||||||
|
ChainValidationResult::InvalidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
messageReceivedEventToken_ = socket_.MessageReceived(
|
||||||
|
{this, &FlipperReactSocketClient::OnWebSocketMessageReceived});
|
||||||
|
closedEventToken_ =
|
||||||
|
socket_.Closed({this, &FlipperReactSocketClient::OnWebSocketClosed});
|
||||||
|
|
||||||
|
try {
|
||||||
|
this->socket_.ConnectAsync(winrt::Windows::Foundation::Uri(uri))
|
||||||
|
.wait_for(std::chrono::seconds(10));
|
||||||
|
|
||||||
|
status_ = Status::Initializing;
|
||||||
|
scheduler_->schedule(
|
||||||
|
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::OPEN); });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (winrt::hresult_error const& ex) {
|
||||||
|
winrt::Windows::Web::WebErrorStatus webErrorStatus{
|
||||||
|
winrt::Windows::Networking::Sockets::WebSocketError::GetStatus(
|
||||||
|
ex.to_abi())};
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocketClient::disconnect() {
|
||||||
|
status_ = Status::Closed;
|
||||||
|
scheduler_->schedule(
|
||||||
|
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||||
|
// socket_.Close();
|
||||||
|
socket_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocketClient::send(
|
||||||
|
const folly::dynamic& message,
|
||||||
|
SocketSendHandler completion) {
|
||||||
|
std::string json = folly::toJson(message);
|
||||||
|
send(json, std::move(completion));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocketClient::send(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendHandler completion) {
|
||||||
|
using namespace winrt::Windows::Storage::Streams;
|
||||||
|
auto payload = winrt::to_hstring(message);
|
||||||
|
try {
|
||||||
|
DataWriter dataWriter{socket_.OutputStream()};
|
||||||
|
dataWriter.WriteString(payload);
|
||||||
|
dataWriter.StoreAsync().get();
|
||||||
|
dataWriter.DetachStream();
|
||||||
|
|
||||||
|
completion();
|
||||||
|
} catch (winrt::hresult_error const& ex) {
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Only ever used for insecure connections to receive the device_id from a
|
||||||
|
signCertificate request. If the intended usage ever changes, then a better
|
||||||
|
approach needs to be put in place.
|
||||||
|
*/
|
||||||
|
void FlipperReactSocketClient::sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) {
|
||||||
|
using namespace winrt::Windows::Storage::Streams;
|
||||||
|
|
||||||
|
overrideHandler_ =
|
||||||
|
std::make_unique<SocketSendExpectResponseHandler>(completion);
|
||||||
|
|
||||||
|
auto payload = winrt::to_hstring(message);
|
||||||
|
try {
|
||||||
|
DataWriter dataWriter{socket_.OutputStream()};
|
||||||
|
dataWriter.WriteString(payload);
|
||||||
|
dataWriter.StoreAsync().get();
|
||||||
|
dataWriter.DetachStream();
|
||||||
|
} catch (winrt::hresult_error const& ex) {
|
||||||
|
overrideHandler_ = nullptr;
|
||||||
|
completion("", true);
|
||||||
|
} catch (const std::exception& ex) {
|
||||||
|
overrideHandler_ = nullptr;
|
||||||
|
completion(ex.what(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocketClient::OnWebSocketMessageReceived(
|
||||||
|
winrt::Windows::Networking::Sockets::MessageWebSocket const& /* sender */,
|
||||||
|
winrt::Windows::Networking::Sockets::
|
||||||
|
MessageWebSocketMessageReceivedEventArgs const& args) {
|
||||||
|
using namespace winrt::Windows::Storage::Streams;
|
||||||
|
try {
|
||||||
|
DataReader dataReader{args.GetDataReader()};
|
||||||
|
dataReader.UnicodeEncoding(
|
||||||
|
winrt::Windows::Storage::Streams::UnicodeEncoding::Utf8);
|
||||||
|
auto message = dataReader.ReadString(dataReader.UnconsumedBufferLength());
|
||||||
|
|
||||||
|
const std::string payload = winrt::to_string(message);
|
||||||
|
|
||||||
|
if (overrideHandler_ != nullptr) {
|
||||||
|
scheduler_->schedule([payload, messageHandler = *overrideHandler_]() {
|
||||||
|
messageHandler(payload, false);
|
||||||
|
});
|
||||||
|
overrideHandler_ = nullptr;
|
||||||
|
} else if (messageHandler_) {
|
||||||
|
scheduler_->schedule([payload, messageHandler = messageHandler_]() {
|
||||||
|
messageHandler(payload);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (winrt::hresult_error const& ex) {
|
||||||
|
// winrt::Windows::Web::WebErrorStatus webErrorStatus{
|
||||||
|
// winrt::Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi())};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlipperReactSocketClient::OnWebSocketClosed(
|
||||||
|
winrt::Windows::Networking::Sockets::IWebSocket const& /* sender */,
|
||||||
|
winrt::Windows::Networking::Sockets::WebSocketClosedEventArgs const& args) {
|
||||||
|
if (status_ == Status::Closed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
status_ = Status::Closed;
|
||||||
|
scheduler_->schedule(
|
||||||
|
[eventHandler = eventHandler_]() { eventHandler(SocketEvent::CLOSE); });
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <folly/dynamic.h>
|
||||||
|
#include <winrt/Windows.Foundation.h>
|
||||||
|
#include <winrt/Windows.Networking.Sockets.h>
|
||||||
|
#include <future>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include "../../../../xplat/Flipper/FlipperSocket.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperSocketProvider.h"
|
||||||
|
#include "../../../../xplat/Flipper/FlipperTransportTypes.h"
|
||||||
|
#include "FlipperReactBaseSocket.h"
|
||||||
|
|
||||||
|
namespace facebook {
|
||||||
|
namespace flipper {
|
||||||
|
|
||||||
|
class FlipperConnectionManager;
|
||||||
|
class ConnectionContextStore;
|
||||||
|
class FlipperReactSocketClient : public FlipperReactBaseSocket {
|
||||||
|
public:
|
||||||
|
FlipperReactSocketClient(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler);
|
||||||
|
FlipperReactSocketClient(
|
||||||
|
FlipperConnectionEndpoint endpoint,
|
||||||
|
std::unique_ptr<FlipperSocketBasePayload> payload,
|
||||||
|
Scheduler* scheduler,
|
||||||
|
ConnectionContextStore* connectionContextStore);
|
||||||
|
|
||||||
|
FlipperReactSocketClient(const FlipperReactSocketClient&) = delete;
|
||||||
|
FlipperReactSocketClient& operator=(const FlipperReactSocketClient&) = delete;
|
||||||
|
|
||||||
|
virtual ~FlipperReactSocketClient();
|
||||||
|
|
||||||
|
virtual bool connect(FlipperConnectionManager* manager) override;
|
||||||
|
virtual void disconnect() override;
|
||||||
|
|
||||||
|
virtual void send(const folly::dynamic& message, SocketSendHandler completion)
|
||||||
|
override;
|
||||||
|
virtual void send(const std::string& message, SocketSendHandler completion)
|
||||||
|
override;
|
||||||
|
virtual void sendExpectResponse(
|
||||||
|
const std::string& message,
|
||||||
|
SocketSendExpectResponseHandler completion) override;
|
||||||
|
|
||||||
|
void OnWebSocketMessageReceived(
|
||||||
|
winrt::Windows::Networking::Sockets::MessageWebSocket const& /* sender */,
|
||||||
|
winrt::Windows::Networking::Sockets::
|
||||||
|
MessageWebSocketMessageReceivedEventArgs const& args);
|
||||||
|
void OnWebSocketClosed(
|
||||||
|
winrt::Windows::Networking::Sockets::IWebSocket const& /* sender */,
|
||||||
|
winrt::Windows::Networking::Sockets::WebSocketClosedEventArgs const&
|
||||||
|
args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::promise<bool> connected_;
|
||||||
|
winrt::Windows::Networking::Sockets::MessageWebSocket socket_;
|
||||||
|
winrt::event_token messageReceivedEventToken_;
|
||||||
|
winrt::event_token closedEventToken_;
|
||||||
|
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::Certificate
|
||||||
|
findClientCertificateFromStore();
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::Certificate
|
||||||
|
installClientCertificate();
|
||||||
|
winrt::Windows::Security::Cryptography::Certificates::Certificate
|
||||||
|
getClientCertificate();
|
||||||
|
|
||||||
|
std::unique_ptr<SocketSendExpectResponseHandler> overrideHandler_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace flipper
|
||||||
|
} // namespace facebook
|
||||||
Reference in New Issue
Block a user