More C++ Client cleanup (#7551)

This commit is contained in:
BrennanConroy 2019-02-14 08:31:15 -08:00 committed by GitHub
parent 6ea3f27dbb
commit bca85b92fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 196 additions and 223 deletions

View File

@ -41,7 +41,7 @@ namespace signalr
SIGNALRCLIENT_API pplx::task<void> __cdecl stop(); SIGNALRCLIENT_API pplx::task<void> __cdecl stop();
SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const; SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const noexcept;
SIGNALRCLIENT_API utility::string_t __cdecl get_connection_id() const; SIGNALRCLIENT_API utility::string_t __cdecl get_connection_id() const;
private: private:

View File

@ -43,20 +43,11 @@ namespace signalr
SIGNALRCLIENT_API void __cdecl on(const utility::string_t& event_name, const method_invoked_handler& handler); SIGNALRCLIENT_API void __cdecl on(const utility::string_t& event_name, const method_invoked_handler& handler);
pplx::task<web::json::value> invoke(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array()) SIGNALRCLIENT_API pplx::task<web::json::value> invoke(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array());
{
return invoke_json(method_name, arguments);
}
pplx::task<void> send(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array()) SIGNALRCLIENT_API pplx::task<void> send(const utility::string_t& method_name, const web::json::value& arguments = web::json::value::array());
{
return invoke_void(method_name, arguments);
}
private: private:
std::shared_ptr<hub_connection_impl> m_pImpl; std::shared_ptr<hub_connection_impl> m_pImpl;
SIGNALRCLIENT_API pplx::task<web::json::value> __cdecl invoke_json(const utility::string_t& method_name, const web::json::value& arguments);
SIGNALRCLIENT_API pplx::task<void> __cdecl invoke_void(const utility::string_t& method_name, const web::json::value& arguments);
}; };
} }

View File

@ -4,10 +4,8 @@
#pragma once #pragma once
#include <stdexcept> #include <stdexcept>
#include "cpprest/details/basic_types.h"
#include "cpprest/json.h"
#include "cpprest/asyncrt_utils.h"
#include "signalr_exception.h" #include "signalr_exception.h"
#include "cpprest/details/basic_types.h"
namespace signalr namespace signalr
{ {

View File

@ -22,10 +22,10 @@ namespace signalr
SIGNALRCLIENT_API web::http::client::http_client_config __cdecl get_http_client_config() const; SIGNALRCLIENT_API web::http::client::http_client_config __cdecl get_http_client_config() const;
SIGNALRCLIENT_API void __cdecl set_http_client_config(const web::http::client::http_client_config& http_client_config); SIGNALRCLIENT_API void __cdecl set_http_client_config(const web::http::client::http_client_config& http_client_config);
SIGNALRCLIENT_API web::websockets::client::websocket_client_config __cdecl get_websocket_client_config() const; SIGNALRCLIENT_API web::websockets::client::websocket_client_config __cdecl get_websocket_client_config() const noexcept;
SIGNALRCLIENT_API void __cdecl set_websocket_client_config(const web::websockets::client::websocket_client_config& websocket_client_config); SIGNALRCLIENT_API void __cdecl set_websocket_client_config(const web::websockets::client::websocket_client_config& websocket_client_config);
SIGNALRCLIENT_API web::http::http_headers __cdecl get_http_headers() const; SIGNALRCLIENT_API web::http::http_headers __cdecl get_http_headers() const noexcept;
SIGNALRCLIENT_API void __cdecl set_http_headers(const web::http::http_headers& http_headers); SIGNALRCLIENT_API void __cdecl set_http_headers(const web::http::http_headers& http_headers);
private: private:
@ -33,4 +33,4 @@ namespace signalr
web::websockets::client::websocket_client_config m_websocket_client_config; web::websockets::client::websocket_client_config m_websocket_client_config;
web::http::http_headers m_http_headers; web::http::http_headers m_http_headers;
}; };
} }

View File

@ -16,13 +16,13 @@ namespace signalr
all = messages | events | state_changes | errors | info all = messages | events | state_changes | errors | info
}; };
inline trace_level operator|(trace_level lhs, trace_level rhs) inline trace_level operator|(trace_level lhs, trace_level rhs) noexcept
{ {
return static_cast<trace_level>(static_cast<int>(lhs) | static_cast<int>(rhs)); return static_cast<trace_level>(static_cast<int>(lhs) | static_cast<int>(rhs));
} }
inline trace_level operator&(trace_level lhs, trace_level rhs) inline trace_level operator&(trace_level lhs, trace_level rhs) noexcept
{ {
return static_cast<trace_level>(static_cast<int>(lhs) & static_cast<int>(rhs)); return static_cast<trace_level>(static_cast<int>(lhs) & static_cast<int>(rhs));
} }
} }

View File

@ -16,7 +16,7 @@ namespace signalr
: runtime_error(utility::conversions::to_utf8string(what)), m_status_code(status_code) : runtime_error(utility::conversions::to_utf8string(what)), m_status_code(status_code)
{} {}
unsigned short status_code() const unsigned short status_code() const noexcept
{ {
return m_status_code; return m_status_code;
} }
@ -24,4 +24,4 @@ namespace signalr
private: private:
unsigned short m_status_code; unsigned short m_status_code;
}; };
} }

View File

@ -168,7 +168,4 @@
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project> </Project>

View File

@ -83,7 +83,7 @@ namespace signalr
utility::string_t callback_manager::get_callback_id() utility::string_t callback_manager::get_callback_id()
{ {
auto callback_id = m_id++; const auto callback_id = m_id++;
utility::stringstream_t ss; utility::stringstream_t ss;
ss << callback_id; ss << callback_id;
return ss.str(); return ss.str();

View File

@ -35,7 +35,7 @@ namespace signalr
struct case_insensitive_hash : std::unary_function<utility::string_t, std::size_t> struct case_insensitive_hash : std::unary_function<utility::string_t, std::size_t>
{ {
std::size_t operator()(const utility::string_t& s) const std::size_t operator()(const utility::string_t& s) const noexcept
{ {
size_t hash = 0; size_t hash = 0;
std::hash<size_t> hasher; std::hash<size_t> hasher;
@ -47,4 +47,4 @@ namespace signalr
return hash; return hash;
} }
}; };
} }

View File

@ -46,7 +46,7 @@ namespace signalr
return m_pImpl->stop(); return m_pImpl->stop();
} }
connection_state connection::get_connection_state() const connection_state connection::get_connection_state() const noexcept
{ {
return m_pImpl->get_connection_state(); return m_pImpl->get_connection_state();
} }

View File

@ -4,7 +4,6 @@
#include "stdafx.h" #include "stdafx.h"
#include <thread> #include <thread>
#include <algorithm> #include <algorithm>
#include "cpprest/asyncrt_utils.h"
#include "constants.h" #include "constants.h"
#include "connection_impl.h" #include "connection_impl.h"
#include "request_sender.h" #include "request_sender.h"
@ -39,7 +38,7 @@ namespace signalr
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory) std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory)
: m_base_url(url), m_query_string(query_string), m_connection_state(connection_state::disconnected), m_logger(log_writer, trace_level), : m_base_url(url), m_query_string(query_string), m_connection_state(connection_state::disconnected), m_logger(log_writer, trace_level),
m_transport(nullptr), m_web_request_factory(std::move(web_request_factory)), m_transport_factory(std::move(transport_factory)), m_transport(nullptr), m_web_request_factory(std::move(web_request_factory)), m_transport_factory(std::move(transport_factory)),
m_message_received([](const utility::string_t&){}), m_disconnected([](){}) m_message_received([](const utility::string_t&) noexcept {}), m_disconnected([]() noexcept {})
{ } { }
connection_impl::~connection_impl() connection_impl::~connection_impl()
@ -87,28 +86,49 @@ namespace signalr
pplx::task_completion_event<void> start_tce; pplx::task_completion_event<void> start_tce;
auto connection = shared_from_this(); auto weak_connection = weak_from_this();
pplx::task_from_result() pplx::task_from_result()
.then([connection]() .then([weak_connection]()
{ {
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<negotiation_response>(_XPLATSTR("connection no longer exists"));
}
return request_sender::negotiate(*connection->m_web_request_factory, connection->m_base_url, return request_sender::negotiate(*connection->m_web_request_factory, connection->m_base_url,
connection->m_query_string, connection->m_signalr_client_config); connection->m_query_string, connection->m_signalr_client_config);
}, m_disconnect_cts.get_token()) }, m_disconnect_cts.get_token())
.then([connection](negotiation_response negotiation_response) .then([weak_connection](negotiation_response negotiation_response)
{ {
connection->m_connection_id = negotiation_response.connection_id; auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
}
connection->m_connection_id = std::move(negotiation_response.connection_id);
// TODO: check available transports // TODO: check available transports
return connection->start_transport(negotiation_response) return connection->start_transport()
.then([connection, negotiation_response](std::shared_ptr<transport> transport) .then([weak_connection](std::shared_ptr<transport> transport)
{ {
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
}
connection->m_transport = transport; connection->m_transport = transport;
return pplx::task_from_result();
}); });
}, m_disconnect_cts.get_token()) }, m_disconnect_cts.get_token())
.then([start_tce, connection](pplx::task<void> previous_task) .then([start_tce, weak_connection](pplx::task<void> previous_task)
{ {
auto connection = weak_connection.lock();
if (!connection)
{
return pplx::task_from_exception<void>(_XPLATSTR("connection no longer exists"));
}
try try
{ {
previous_task.get(); previous_task.get();
@ -144,20 +164,22 @@ namespace signalr
connection->m_start_completed_event.set(); connection->m_start_completed_event.set();
start_tce.set_exception(std::current_exception()); start_tce.set_exception(std::current_exception());
} }
return pplx::task_from_result();
}); });
return pplx::create_task(start_tce); return pplx::create_task(start_tce);
} }
pplx::task<std::shared_ptr<transport>> connection_impl::start_transport(negotiation_response negotiation_response) pplx::task<std::shared_ptr<transport>> connection_impl::start_transport()
{ {
auto connection = shared_from_this(); auto connection = shared_from_this();
pplx::task_completion_event<void> connect_request_tce; pplx::task_completion_event<void> connect_request_tce;
auto weak_connection = std::weak_ptr<connection_impl>(connection); auto weak_connection = std::weak_ptr<connection_impl>(connection);
auto& disconnect_cts = m_disconnect_cts; const auto& disconnect_cts = m_disconnect_cts;
auto& logger = m_logger; const auto& logger = m_logger;
auto process_response_callback = auto process_response_callback =
[weak_connection, disconnect_cts, logger](const utility::string_t& response) mutable [weak_connection, disconnect_cts, logger](const utility::string_t& response) mutable
@ -169,7 +191,7 @@ namespace signalr
if (disconnect_cts.get_token().is_canceled()) if (disconnect_cts.get_token().is_canceled())
{ {
logger.log(trace_level::info, logger.log(trace_level::info,
utility::string_t(_XPLATSTR("ignoring stray message received after connection was restarted. message: ")) utility::string_t{ _XPLATSTR("ignoring stray message received after connection was restarted. message: " })
.append(response)); .append(response));
return; return;
} }
@ -192,7 +214,7 @@ namespace signalr
if (disconnect_cts.get_token().is_canceled()) if (disconnect_cts.get_token().is_canceled())
{ {
logger.log(trace_level::info, logger.log(trace_level::info,
utility::string_t(_XPLATSTR("ignoring stray error received after connection was restarted. error: ")) utility::string_t{ _XPLATSTR("ignoring stray error received after connection was restarted. error: " })
.append(utility::conversions::to_string_t(e.what()))); .append(utility::conversions::to_string_t(e.what())));
return; return;
@ -206,7 +228,7 @@ namespace signalr
transport_type::websockets, connection->m_logger, connection->m_signalr_client_config, transport_type::websockets, connection->m_logger, connection->m_signalr_client_config,
process_response_callback, error_callback); process_response_callback, error_callback);
pplx::create_task([negotiation_response, connect_request_tce, disconnect_cts, weak_connection]() pplx::create_task([connect_request_tce, disconnect_cts, weak_connection]()
{ {
// TODO? std::this_thread::sleep_for(std::chrono::milliseconds(negotiation_response.transport_connect_timeout)); // TODO? std::this_thread::sleep_for(std::chrono::milliseconds(negotiation_response.transport_connect_timeout));
std::this_thread::sleep_for(std::chrono::milliseconds(5000)); std::this_thread::sleep_for(std::chrono::milliseconds(5000));
@ -290,11 +312,11 @@ namespace signalr
// we won't crash. // we won't crash.
auto transport = m_transport; auto transport = m_transport;
auto connection_state = get_connection_state(); const auto connection_state = get_connection_state();
if (connection_state != signalr::connection_state::connected || !transport) if (connection_state != signalr::connection_state::connected || !transport)
{ {
return pplx::task_from_exception<void>(signalr_exception( return pplx::task_from_exception<void>(signalr_exception(
utility::string_t{_XPLATSTR("cannot send data when the connection is not in the connected state. current connection state: " }) utility::string_t(_XPLATSTR("cannot send data when the connection is not in the connected state. current connection state: "))
.append(translate_connection_state(connection_state)))); .append(translate_connection_state(connection_state))));
} }
@ -368,7 +390,7 @@ namespace signalr
std::lock_guard<std::mutex> lock(m_stop_lock); std::lock_guard<std::mutex> lock(m_stop_lock);
m_logger.log(trace_level::info, _XPLATSTR("acquired lock in shutdown()")); m_logger.log(trace_level::info, _XPLATSTR("acquired lock in shutdown()"));
auto current_state = get_connection_state(); const auto current_state = get_connection_state();
if (current_state == connection_state::disconnected) if (current_state == connection_state::disconnected)
{ {
return pplx::task_from_result(); return pplx::task_from_result();
@ -381,7 +403,7 @@ namespace signalr
// affect the other invocation which is using it. // affect the other invocation which is using it.
auto cts = pplx::cancellation_token_source(); auto cts = pplx::cancellation_token_source();
cts.cancel(); cts.cancel();
return pplx::create_task([](){}, cts.get_token()); return pplx::create_task([]() noexcept {}, cts.get_token());
} }
// we request a cancellation of the ongoing start (if any) and wait until it is canceled // we request a cancellation of the ongoing start (if any) and wait until it is canceled
@ -408,7 +430,7 @@ namespace signalr
return m_transport->disconnect(); return m_transport->disconnect();
} }
connection_state connection_impl::get_connection_state() const connection_state connection_impl::get_connection_state() const noexcept
{ {
return m_connection_state.load(); return m_connection_state.load();
} }
@ -429,13 +451,6 @@ namespace signalr
m_message_received = message_received; m_message_received = message_received;
} }
void connection_impl::set_connection_data(const utility::string_t& connection_data)
{
_ASSERTE(get_connection_state() == connection_state::disconnected);
m_connection_data = connection_data;
}
void connection_impl::set_client_config(const signalr_client_config& config) void connection_impl::set_client_config(const signalr_client_config& config)
{ {
ensure_disconnected(_XPLATSTR("cannot set client config when the connection is not in the disconnected state. ")); ensure_disconnected(_XPLATSTR("cannot set client config when the connection is not in the disconnected state. "));
@ -450,7 +465,7 @@ namespace signalr
void connection_impl::ensure_disconnected(const utility::string_t& error_message) void connection_impl::ensure_disconnected(const utility::string_t& error_message)
{ {
auto state = get_connection_state(); const auto state = get_connection_state();
if (state != connection_state::disconnected) if (state != connection_state::disconnected)
{ {
throw signalr_exception( throw signalr_exception(

View File

@ -41,15 +41,13 @@ namespace signalr
pplx::task<void> send(const utility::string_t &data); pplx::task<void> send(const utility::string_t &data);
pplx::task<void> stop(); pplx::task<void> stop();
connection_state get_connection_state() const; connection_state get_connection_state() const noexcept;
utility::string_t get_connection_id() const; utility::string_t get_connection_id() const;
void set_message_received(const std::function<void(const utility::string_t&)>& message_received); void set_message_received(const std::function<void(const utility::string_t&)>& message_received);
void set_disconnected(const std::function<void()>& disconnected); void set_disconnected(const std::function<void()>& disconnected);
void set_client_config(const signalr_client_config& config); void set_client_config(const signalr_client_config& config);
void set_connection_data(const utility::string_t& connection_data);
private: private:
web::uri m_base_url; web::uri m_base_url;
utility::string_t m_query_string; utility::string_t m_query_string;
@ -74,7 +72,7 @@ namespace signalr
connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer, connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr<log_writer>& log_writer,
std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory); std::unique_ptr<web_request_factory> web_request_factory, std::unique_ptr<transport_factory> transport_factory);
pplx::task<std::shared_ptr<transport>> start_transport(negotiation_response negotiation_response); pplx::task<std::shared_ptr<transport>> start_transport();
pplx::task<void> send_connect_request(const std::shared_ptr<transport>& transport, pplx::task<void> send_connect_request(const std::shared_ptr<transport>& transport,
const pplx::task_completion_event<void>& connect_request_tce); const pplx::task_completion_event<void>& connect_request_tce);

View File

@ -8,7 +8,7 @@ namespace signalr
{ {
namespace namespace
{ {
static web::websockets::client::websocket_client_config create_client_config(const signalr_client_config& signalr_client_config) static web::websockets::client::websocket_client_config create_client_config(const signalr_client_config& signalr_client_config) noexcept
{ {
auto websocket_client_config = signalr_client_config.get_websocket_client_config(); auto websocket_client_config = signalr_client_config.get_websocket_client_config();
websocket_client_config.headers() = signalr_client_config.get_http_headers(); websocket_client_config.headers() = signalr_client_config.get_http_headers();
@ -17,7 +17,7 @@ namespace signalr
} }
} }
default_websocket_client::default_websocket_client(const signalr_client_config& signalr_client_config) default_websocket_client::default_websocket_client(const signalr_client_config& signalr_client_config) noexcept
: m_underlying_client(create_client_config(signalr_client_config)) : m_underlying_client(create_client_config(signalr_client_config))
{ } { }
@ -47,4 +47,4 @@ namespace signalr
{ {
return m_underlying_client.close(); return m_underlying_client.close();
} }
} }

View File

@ -12,7 +12,7 @@ namespace signalr
class default_websocket_client : public websocket_client class default_websocket_client : public websocket_client
{ {
public: public:
explicit default_websocket_client(const signalr_client_config& signalr_client_config = signalr_client_config{}); explicit default_websocket_client(const signalr_client_config& signalr_client_config = signalr_client_config{}) noexcept;
pplx::task<void> connect(const web::uri &url) override; pplx::task<void> connect(const web::uri &url) override;
@ -25,4 +25,4 @@ namespace signalr
private: private:
web::websockets::client::websocket_client m_underlying_client; web::websockets::client::websocket_client m_underlying_client;
}; };
} }

View File

@ -19,7 +19,7 @@ namespace signalr
static const unsigned int timeout_infinite = 0xFFFFFFFF; static const unsigned int timeout_infinite = 0xFFFFFFFF;
event() event() noexcept
: m_signaled(false) : m_signaled(false)
{ {
} }
@ -42,13 +42,13 @@ namespace signalr
std::unique_lock<std::mutex> lock(m_lock); std::unique_lock<std::mutex> lock(m_lock);
if (timeout == event::timeout_infinite) if (timeout == event::timeout_infinite)
{ {
m_condition.wait(lock, [this]() { return m_signaled; }); m_condition.wait(lock, [this]() noexcept { return m_signaled; });
return 0; return 0;
} }
else else
{ {
std::chrono::milliseconds period(timeout); const std::chrono::milliseconds period(timeout);
auto status = m_condition.wait_for(lock, period, [this]() { return m_signaled; }); const auto status = m_condition.wait_for(lock, period, [this]() noexcept { return m_signaled; });
assert(status == m_signaled); assert(status == m_signaled);
// Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite // Return 0 if the wait completed as a result of signaling the event. Otherwise, return timeout_infinite
return status ? 0 : event::timeout_infinite; return status ? 0 : event::timeout_infinite;

View File

@ -37,24 +37,24 @@ namespace signalr
return m_pImpl->on(event_name, handler); return m_pImpl->on(event_name, handler);
} }
pplx::task<web::json::value> hub_connection::invoke_json(const utility::string_t& method_name, const web::json::value& arguments) pplx::task<web::json::value> hub_connection::invoke(const utility::string_t& method_name, const web::json::value& arguments)
{ {
if (!m_pImpl) if (!m_pImpl)
{ {
throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_connection instance")); throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_connection instance"));
} }
return m_pImpl->invoke_json(method_name, arguments); return m_pImpl->invoke(method_name, arguments);
} }
pplx::task<void> hub_connection::invoke_void(const utility::string_t& method_name, const web::json::value& arguments) pplx::task<void> hub_connection::send(const utility::string_t& method_name, const web::json::value& arguments)
{ {
if (!m_pImpl) if (!m_pImpl)
{ {
throw signalr_exception(_XPLATSTR("invoke() cannot be called on uninitialized hub_connection instance")); throw signalr_exception(_XPLATSTR("send() cannot be called on uninitialized hub_connection instance"));
} }
return m_pImpl->invoke_void(method_name, arguments); return m_pImpl->send(method_name, arguments);
} }
connection_state hub_connection::get_connection_state() const connection_state hub_connection::get_connection_state() const

View File

@ -45,7 +45,7 @@ namespace signalr
: m_connection(connection_impl::create(url, query_string, trace_level, log_writer, : m_connection(connection_impl::create(url, query_string, trace_level, log_writer,
std::move(web_request_factory), std::move(transport_factory))),m_logger(log_writer, trace_level), std::move(web_request_factory), std::move(transport_factory))),m_logger(log_writer, trace_level),
m_callback_manager(json::value::parse(_XPLATSTR("{ \"error\" : \"connection went out of scope before invocation result was received\"}"))), m_callback_manager(json::value::parse(_XPLATSTR("{ \"error\" : \"connection went out of scope before invocation result was received\"}"))),
m_disconnected([]() {}) m_disconnected([]() noexcept {}), m_handshakeReceived(false)
{ } { }
void hub_connection_impl::initialize() void hub_connection_impl::initialize()
@ -108,9 +108,9 @@ namespace signalr
m_handshakeTask = pplx::task_completion_event<void>(); m_handshakeTask = pplx::task_completion_event<void>();
m_handshakeReceived = false; m_handshakeReceived = false;
auto weak_connection = m_connection->weak_from_this(); auto weak_connection = weak_from_this();
return m_connection->start() return m_connection->start()
.then([weak_connection, this](pplx::task<void> startTask) .then([weak_connection](pplx::task<void> startTask)
{ {
startTask.get(); startTask.get();
auto connection = weak_connection.lock(); auto connection = weak_connection.lock();
@ -119,11 +119,17 @@ namespace signalr
// The connection has been destructed // The connection has been destructed
return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("the hub connection has been deconstructed"))); return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("the hub connection has been deconstructed")));
} }
return connection->send(_XPLATSTR("{\"protocol\":\"json\",\"version\":1}\x1e")) return connection->m_connection->send(_XPLATSTR("{\"protocol\":\"json\",\"version\":1}\x1e"))
.then([this](pplx::task<void> previous_task) .then([weak_connection](pplx::task<void> previous_task)
{ {
auto connection = weak_connection.lock();
if (!connection)
{
// The connection has been destructed
return pplx::task_from_exception<void>(signalr_exception(_XPLATSTR("the hub connection has been deconstructed")));
}
previous_task.get(); previous_task.get();
return pplx::task<void>(m_handshakeTask); return pplx::task<void>(connection->m_handshakeTask);
}) })
.then([weak_connection](pplx::task<void> previous_task) .then([weak_connection](pplx::task<void> previous_task)
{ {
@ -137,7 +143,7 @@ namespace signalr
auto connection = weak_connection.lock(); auto connection = weak_connection.lock();
if (connection) if (connection)
{ {
connection->stop(); connection->m_connection->stop();
} }
throw; throw;
} }
@ -267,7 +273,7 @@ namespace signalr
return true; return true;
} }
pplx::task<json::value> hub_connection_impl::invoke_json(const utility::string_t& method_name, const json::value& arguments) pplx::task<json::value> hub_connection_impl::invoke(const utility::string_t& method_name, const json::value& arguments)
{ {
_ASSERTE(arguments.is_array()); _ASSERTE(arguments.is_array());
@ -283,7 +289,7 @@ namespace signalr
return pplx::create_task(tce); return pplx::create_task(tce);
} }
pplx::task<void> hub_connection_impl::invoke_void(const utility::string_t& method_name, const json::value& arguments) pplx::task<void> hub_connection_impl::send(const utility::string_t& method_name, const json::value& arguments)
{ {
_ASSERTE(arguments.is_array()); _ASSERTE(arguments.is_array());
@ -337,7 +343,7 @@ namespace signalr
}); });
} }
connection_state hub_connection_impl::get_connection_state() const connection_state hub_connection_impl::get_connection_state() const noexcept
{ {
return m_connection->get_connection_state(); return m_connection->get_connection_state();
} }

View File

@ -33,13 +33,13 @@ namespace signalr
void on(const utility::string_t& event_name, const std::function<void(const json::value &)>& handler); void on(const utility::string_t& event_name, const std::function<void(const json::value &)>& handler);
pplx::task<json::value> invoke_json(const utility::string_t& method_name, const json::value& arguments); pplx::task<json::value> invoke(const utility::string_t& method_name, const json::value& arguments);
pplx::task<void> invoke_void(const utility::string_t& method_name, const json::value& arguments); pplx::task<void> send(const utility::string_t& method_name, const json::value& arguments);
pplx::task<void> start(); pplx::task<void> start();
pplx::task<void> stop(); pplx::task<void> stop();
connection_state get_connection_state() const; connection_state get_connection_state() const noexcept;
utility::string_t get_connection_id() const; utility::string_t get_connection_id() const;
void set_client_config(const signalr_client_config& config); void set_client_config(const signalr_client_config& config);

View File

@ -8,11 +8,11 @@
namespace signalr namespace signalr
{ {
logger::logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level) logger::logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level) noexcept
: m_log_writer(log_writer), m_trace_level(trace_level) : m_log_writer(log_writer), m_trace_level(trace_level)
{ } { }
void logger::log(trace_level level, const utility::string_t& entry) void logger::log(trace_level level, const utility::string_t& entry) const
{ {
if ((level & m_trace_level) != trace_level::none) if ((level & m_trace_level) != trace_level::none)
{ {
@ -54,4 +54,4 @@ namespace signalr
return _XPLATSTR("(unknown)"); return _XPLATSTR("(unknown)");
} }
} }
} }

View File

@ -12,9 +12,9 @@ namespace signalr
class logger class logger
{ {
public: public:
logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level); logger(const std::shared_ptr<log_writer>& log_writer, trace_level trace_level) noexcept;
void log(trace_level level, const utility::string_t& entry); void log(trace_level level, const utility::string_t& entry) const;
private: private:
std::shared_ptr<log_writer> m_log_writer; std::shared_ptr<log_writer> m_log_writer;
@ -22,4 +22,4 @@ namespace signalr
static utility::string_t translate_trace_level(trace_level trace_level); static utility::string_t translate_trace_level(trace_level trace_level);
}; };
} }

View File

@ -26,8 +26,8 @@ namespace signalr
negotiation_response_json[_XPLATSTR("availableTransports")], negotiation_response_json[_XPLATSTR("availableTransports")],
}; };
return response; return std::move(response);
}); });
} }
} }
} }

View File

@ -30,7 +30,7 @@ namespace signalr
m_http_client_config = http_client_config; m_http_client_config = http_client_config;
} }
web::websockets::client::websocket_client_config signalr_client_config::get_websocket_client_config() const web::websockets::client::websocket_client_config signalr_client_config::get_websocket_client_config() const noexcept
{ {
return m_websocket_client_config; return m_websocket_client_config;
} }
@ -40,7 +40,7 @@ namespace signalr
m_websocket_client_config = websocket_client_config; m_websocket_client_config = websocket_client_config;
} }
web::http::http_headers signalr_client_config::get_http_headers() const web::http::http_headers signalr_client_config::get_http_headers() const noexcept
{ {
return m_http_headers; return m_http_headers;
} }
@ -49,4 +49,4 @@ namespace signalr
{ {
m_http_headers = http_headers; m_http_headers = http_headers;
} }
} }

View File

@ -15,8 +15,8 @@ namespace signalr
_ASSERTE(transport == transport_type::websockets || transport == transport_type::long_polling); _ASSERTE(transport == transport_type::websockets || transport == transport_type::long_polling);
return transport == transport_type::websockets return transport == transport_type::websockets
? _XPLATSTR("webSockets") ? utility::string_t(_XPLATSTR("webSockets"))
: _XPLATSTR("longPolling"); : utility::string_t(_XPLATSTR("longPolling"));
} }
void append_transport(web::uri_builder &builder, transport_type transport) void append_transport(web::uri_builder &builder, transport_type transport)

View File

@ -36,7 +36,7 @@ namespace signalr
{} {}
} }
transport_type websocket_transport::get_transport_type() const transport_type websocket_transport::get_transport_type() const noexcept
{ {
return transport_type::websockets; return transport_type::websockets;
} }
@ -236,10 +236,10 @@ namespace signalr
std::shared_ptr<websocket_client> websocket_transport::safe_get_websocket_client() std::shared_ptr<websocket_client> websocket_transport::safe_get_websocket_client()
{ {
{ {
std::lock_guard<std::mutex> lock(m_websocket_client_lock); const std::lock_guard<std::mutex> lock(m_websocket_client_lock);
auto websocket_client = m_websocket_client; auto websocket_client = m_websocket_client;
return websocket_client; return websocket_client;
} }
} }
} }

View File

@ -31,7 +31,7 @@ namespace signalr
pplx::task<void> disconnect() override; pplx::task<void> disconnect() override;
transport_type get_transport_type() const override; transport_type get_transport_type() const noexcept override;
private: private:
websocket_transport(const std::function<std::shared_ptr<websocket_client>()>& websocket_client_factory, websocket_transport(const std::function<std::shared_ptr<websocket_client>()>& websocket_client_factory,
@ -52,4 +52,4 @@ namespace signalr
std::shared_ptr<websocket_client> safe_get_websocket_client(); std::shared_ptr<websocket_client> safe_get_websocket_client();
}; };
} }

View File

@ -170,7 +170,4 @@
<Filter>Resource Files</Filter> <Filter>Resource Files</Filter>
</ResourceCompile> </ResourceCompile>
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
</Project> </Project>

View File

@ -64,7 +64,7 @@ TEST(connection_impl_start, connection_state_is_connecting_when_connection_is_be
auto connection = create_connection(websocket_client, writer, trace_level::errors); auto connection = create_connection(websocket_client, writer, trace_level::errors);
connection->start() auto startTask = connection->start()
// this test is not set up to connect successfully so we have to observe exceptions otherwise // this test is not set up to connect successfully so we have to observe exceptions otherwise
// other tests may fail due to an unobserved exception from the outstanding start task // other tests may fail due to an unobserved exception from the outstanding start task
.then([](pplx::task<void> start_task) .then([](pplx::task<void> start_task)
@ -78,6 +78,7 @@ TEST(connection_impl_start, connection_state_is_connecting_when_connection_is_be
}); });
ASSERT_EQ(connection->get_connection_state(), connection_state::connecting); ASSERT_EQ(connection->get_connection_state(), connection_state::connecting);
startTask.get();
} }
TEST(connection_impl_start, connection_state_is_connected_when_connection_established_succesfully) TEST(connection_impl_start, connection_state_is_connected_when_connection_established_succesfully)

View File

@ -223,7 +223,7 @@ TEST(stop, stop_cancels_pending_callbacks)
auto hub_connection = create_hub_connection(websocket_client); auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get(); hub_connection->start().get();
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array()); auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
hub_connection->stop(); hub_connection->stop();
try try
@ -262,7 +262,7 @@ TEST(stop, pending_callbacks_finished_if_hub_connections_goes_out_of_scope)
{ {
auto hub_connection = create_hub_connection(websocket_client); auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get(); hub_connection->start().get();
t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array()); t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
} }
try try
@ -309,7 +309,7 @@ TEST(hub_invocation, hub_connection_invokes_users_code_on_hub_invocations)
ASSERT_EQ(_XPLATSTR("[\"message\",1]"), *payload); ASSERT_EQ(_XPLATSTR("[\"message\",1]"), *payload);
} }
TEST(invoke, invoke_creates_correct_payload) TEST(send, creates_correct_payload)
{ {
utility::string_t payload; utility::string_t payload;
bool handshakeReceived = false; bool handshakeReceived = false;
@ -321,7 +321,7 @@ TEST(invoke, invoke_creates_correct_payload)
if (handshakeReceived) if (handshakeReceived)
{ {
payload = m; payload = m;
return pplx::task_from_exception<void>(std::runtime_error("error")); return pplx::task_from_result();
} }
handshakeReceived = true; handshakeReceived = true;
return pplx::task_from_result(); return pplx::task_from_result();
@ -330,16 +330,74 @@ TEST(invoke, invoke_creates_correct_payload)
auto hub_connection = create_hub_connection(websocket_client); auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get(); hub_connection->start().get();
hub_connection->send(_XPLATSTR("method"), json::value::array()).get();
ASSERT_EQ(_XPLATSTR("{\"arguments\":[],\"target\":\"method\",\"type\":1}\x1e"), payload);
}
TEST(send, does_not_wait_for_server_response)
{
int call_number = -1;
pplx::task_completion_event<void> waitForSend;
auto websocket_client = create_test_websocket_client(
/* receive function */ [waitForSend, call_number]() mutable
{
std::string responses[]
{
"{ }\x1e",
"{}"
};
call_number = std::min(call_number + 1, 1);
if (call_number == 1)
{
pplx::task<void>(waitForSend).get();
}
return pplx::task_from_result(responses[call_number]);
});
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
// wont block waiting for server response
hub_connection->send(_XPLATSTR("method"), json::value::array()).get();
waitForSend.set();
}
TEST(invoke, creates_correct_payload)
{
utility::string_t payload;
bool handshakeReceived = false;
auto websocket_client = create_test_websocket_client(
/* receive function */ []() { return pplx::task_from_result(std::string("{ }\x1e")); },
/* send function */[&payload, &handshakeReceived](const utility::string_t& m)
{
if (handshakeReceived)
{
payload = m;
return pplx::task_from_exception<void>(std::runtime_error("error"));
}
handshakeReceived = true;
return pplx::task_from_result();
});
auto hub_connection = create_hub_connection(websocket_client);
hub_connection->start().get();
try try
{ {
hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()).get(); hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
} }
catch (...) catch (...)
{ {
// the send is not setup to succeed because it's not needed in this test // the invoke is not setup to succeed because it's not needed in this test
} }
ASSERT_EQ(_XPLATSTR("{\"arguments\":[],\"target\":\"method\",\"type\":1}\x1e"), payload); ASSERT_EQ(_XPLATSTR("{\"arguments\":[],\"invocationId\":\"0\",\"target\":\"method\",\"type\":1}\x1e"), payload);
} }
TEST(invoke, callback_not_called_if_send_throws) TEST(invoke, callback_not_called_if_send_throws)
@ -362,7 +420,7 @@ TEST(invoke, callback_not_called_if_send_throws)
try try
{ {
hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()).get(); hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
ASSERT_TRUE(false); // exception expected but not thrown ASSERT_TRUE(false); // exception expected but not thrown
} }
catch (const std::runtime_error& e) catch (const std::runtime_error& e)
@ -376,7 +434,7 @@ TEST(invoke, callback_not_called_if_send_throws)
hub_connection->stop().get(); hub_connection->stop().get();
} }
TEST(invoke_json, invoke_returns_value_returned_from_the_server) TEST(invoke, invoke_returns_value_returned_from_the_server)
{ {
auto callback_registered_event = std::make_shared<event>(); auto callback_registered_event = std::make_shared<event>();
@ -404,7 +462,7 @@ TEST(invoke_json, invoke_returns_value_returned_from_the_server)
auto result = hub_connection->start() auto result = hub_connection->start()
.then([hub_connection, callback_registered_event]() .then([hub_connection, callback_registered_event]()
{ {
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array()); auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set(); callback_registered_event->set();
return t; return t;
}).get(); }).get();
@ -412,7 +470,7 @@ TEST(invoke_json, invoke_returns_value_returned_from_the_server)
ASSERT_EQ(_XPLATSTR("\"abc\""), result.serialize()); ASSERT_EQ(_XPLATSTR("\"abc\""), result.serialize());
} }
TEST(invoke_json, invoke_propagates_errors_from_server_as_exceptions) TEST(invoke, invoke_propagates_hub_errors_from_server_as_hub_exceptions)
{ {
auto callback_registered_event = std::make_shared<event>(); auto callback_registered_event = std::make_shared<event>();
@ -442,50 +500,7 @@ TEST(invoke_json, invoke_propagates_errors_from_server_as_exceptions)
hub_connection->start() hub_connection->start()
.then([hub_connection, callback_registered_event]() .then([hub_connection, callback_registered_event]()
{ {
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array()); auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
ASSERT_TRUE(false); // exception expected but not thrown
}
catch (const std::runtime_error& e)
{
ASSERT_STREQ("\"Ooops\"", e.what());
}
}
TEST(invoke_json, invoke_propagates_hub_errors_from_server_as_hub_exceptions)
{
auto callback_registered_event = std::make_shared<event>();
int call_number = -1;
auto websocket_client = create_test_websocket_client(
/* receive function */ [call_number, callback_registered_event]()
mutable {
std::string responses[]
{
"{ }\x1e",
"{ \"type\": 3, \"invocationId\": \"0\", \"error\": \"Ooops\" }\x1e"
};
call_number = std::min(call_number + 1, 1);
if (call_number > 0)
{
callback_registered_event->wait();
}
return pplx::task_from_result(responses[call_number]);
});
auto hub_connection = create_hub_connection(websocket_client);
try
{
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_json(_XPLATSTR("method"), json::value::array());
callback_registered_event->set(); callback_registered_event->set();
return t; return t;
}).get(); }).get();
@ -498,7 +513,7 @@ TEST(invoke_json, invoke_propagates_hub_errors_from_server_as_hub_exceptions)
} }
} }
TEST(invoke_void, invoke_unblocks_task_when_server_completes_call) TEST(invoke, unblocks_task_when_server_completes_call)
{ {
auto callback_registered_event = std::make_shared<event>(); auto callback_registered_event = std::make_shared<event>();
@ -509,7 +524,7 @@ TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
std::string responses[] std::string responses[]
{ {
"{ }\x1e", "{ }\x1e",
"{\"I\":\"0\"}\x1e" "{ \"type\": 3, \"invocationId\": \"0\" }\x1e"
}; };
call_number = std::min(call_number + 1, 1); call_number = std::min(call_number + 1, 1);
@ -526,7 +541,7 @@ TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
hub_connection->start() hub_connection->start()
.then([hub_connection, callback_registered_event]() .then([hub_connection, callback_registered_event]()
{ {
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()); auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set(); callback_registered_event->set();
return t; return t;
}).get(); }).get();
@ -535,7 +550,7 @@ TEST(invoke_void, invoke_unblocks_task_when_server_completes_call)
ASSERT_TRUE(true); ASSERT_TRUE(true);
} }
TEST(invoke_void, invoke_logs_if_callback_for_given_id_not_found) TEST(receive, logs_if_callback_for_given_id_not_found)
{ {
auto message_received_event = std::make_shared<event>(); auto message_received_event = std::make_shared<event>();
auto handshake_sent = std::make_shared<event>(); auto handshake_sent = std::make_shared<event>();
@ -547,7 +562,7 @@ TEST(invoke_void, invoke_logs_if_callback_for_given_id_not_found)
std::string responses[] std::string responses[]
{ {
"{ }\x1e", "{ }\x1e",
"{ \"type\": 3, \"invocationId\": \"0\", \"error\": \"Ooops\" }\x1e" "{ \"type\": 3, \"invocationId\": \"0\" }\x1e"
"{}" "{}"
}; };
@ -582,7 +597,7 @@ TEST(invoke_void, invoke_logs_if_callback_for_given_id_not_found)
} }
// TODO Flaky until hub_connection.start waits for handshake response // TODO Flaky until hub_connection.start waits for handshake response
TEST(invoke_void, DISABLED_invoke_propagates_errors_from_server_as_exceptions) TEST(invoke, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
{ {
auto callback_registered_event = std::make_shared<event>(); auto callback_registered_event = std::make_shared<event>();
@ -613,7 +628,7 @@ TEST(invoke_void, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
hub_connection->start() hub_connection->start()
.then([hub_connection, callback_registered_event]() .then([hub_connection, callback_registered_event]()
{ {
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()); auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set(); callback_registered_event->set();
return t; return t;
}).get(); }).get();
@ -626,51 +641,6 @@ TEST(invoke_void, DISABLED_invoke_propagates_errors_from_server_as_exceptions)
} }
} }
// TODO Flaky until hub_connection.start waits for handshake response
TEST(invoke_void, DISABLED_invoke_propagates_hub_errors_from_server_as_hub_exceptions)
{
auto callback_registered_event = std::make_shared<event>();
int call_number = -1;
auto websocket_client = create_test_websocket_client(
/* receive function */ [call_number, callback_registered_event]()
mutable {
std::string responses[]
{
"{ }\x1e",
"{ \"type\": 3, \"invocationId\": \"0\", \"error\": \"Ooops\" }\x1e"
"{}"
};
call_number = std::min(call_number + 1, 2);
if (call_number > 0)
{
callback_registered_event->wait();
}
return pplx::task_from_result(responses[call_number]);
});
auto hub_connection = create_hub_connection(websocket_client);
try
{
hub_connection->start()
.then([hub_connection, callback_registered_event]()
{
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array());
callback_registered_event->set();
return t;
}).get();
ASSERT_TRUE(false); // exception expected but not thrown
}
catch (const hub_exception& e)
{
ASSERT_STREQ("\"Ooops\"", e.what());
}
}
// TODO Flaky until hub_connection.start waits for handshake response // TODO Flaky until hub_connection.start waits for handshake response
TEST(invoke_void, DISABLED_invoke_creates_runtime_error) TEST(invoke_void, DISABLED_invoke_creates_runtime_error)
{ {
@ -702,7 +672,7 @@ TEST(invoke_void, DISABLED_invoke_creates_runtime_error)
hub_connection->start() hub_connection->start()
.then([hub_connection, callback_registered_event]() .then([hub_connection, callback_registered_event]()
{ {
auto t = hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()); auto t = hub_connection->invoke(_XPLATSTR("method"), json::value::array());
callback_registered_event->set(); callback_registered_event->set();
return t; return t;
}).get(); }).get();
@ -783,13 +753,13 @@ TEST(on, cannot_register_handler_if_connection_not_in_disconnected_state)
} }
} }
TEST(invoke_json, invoke_throws_when_the_underlying_connection_is_not_valid) TEST(invoke, invoke_throws_when_the_underlying_connection_is_not_valid)
{ {
auto hub_connection = create_hub_connection(); auto hub_connection = create_hub_connection();
try try
{ {
hub_connection->invoke_json(_XPLATSTR("method"), json::value::array()).get(); hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
ASSERT_TRUE(true); // exception expected but not thrown ASSERT_TRUE(true); // exception expected but not thrown
} }
catch (const signalr_exception& e) catch (const signalr_exception& e)
@ -798,13 +768,13 @@ TEST(invoke_json, invoke_throws_when_the_underlying_connection_is_not_valid)
} }
} }
TEST(invoke_void, send_throws_when_the_underlying_connection_is_not_valid) TEST(invoke, send_throws_when_the_underlying_connection_is_not_valid)
{ {
auto hub_connection = create_hub_connection(); auto hub_connection = create_hub_connection();
try try
{ {
hub_connection->invoke_void(_XPLATSTR("method"), json::value::array()).get(); hub_connection->invoke(_XPLATSTR("method"), json::value::array()).get();
ASSERT_TRUE(true); // exception expected but not thrown ASSERT_TRUE(true); // exception expected but not thrown
} }
catch (const signalr_exception& e) catch (const signalr_exception& e)