From 5ab013529d00e84600e9914249023ce32d346dbd Mon Sep 17 00:00:00 2001 From: Brennan Conroy Date: Wed, 30 Nov 2022 13:24:43 -0800 Subject: [PATCH 1/3] wip --- .../signalrclient/hub_connection_builder.h | 12 +- src/signalrclient/hub_connection_builder.cpp | 25 +- test/signalrclienttests/connection_tests.cpp | 2 +- .../hub_connection_tests.cpp | 258 +++++++++--------- 4 files changed, 153 insertions(+), 144 deletions(-) diff --git a/include/signalrclient/hub_connection_builder.h b/include/signalrclient/hub_connection_builder.h index a898a9af..12b3378d 100644 --- a/include/signalrclient/hub_connection_builder.h +++ b/include/signalrclient/hub_connection_builder.h @@ -12,7 +12,7 @@ namespace signalr { - class hub_connection_builder + class hub_connection_builder final { public: SIGNALRCLIENT_API static hub_connection_builder create(const std::string& url); @@ -27,19 +27,17 @@ namespace signalr SIGNALRCLIENT_API hub_connection_builder& operator=(const hub_connection_builder&); - SIGNALRCLIENT_API hub_connection_builder& with_logging(std::shared_ptr logger, trace_level logLevel); + SIGNALRCLIENT_API hub_connection_builder& with_logging(std::shared_ptr logger, trace_level log_level); - SIGNALRCLIENT_API hub_connection_builder& with_websocket_factory(std::function(const signalr_client_config&)> factory); + SIGNALRCLIENT_API hub_connection_builder& with_websocket_factory(std::function(const signalr_client_config&)> websocket_factory); SIGNALRCLIENT_API hub_connection_builder& with_http_client_factory(std::function(const signalr_client_config&)> http_client_factory); SIGNALRCLIENT_API hub_connection_builder& skip_negotiation(bool skip = true); -#ifdef USE_MSGPACK SIGNALRCLIENT_API hub_connection_builder& with_messagepack_hub_protocol(); -#endif - SIGNALRCLIENT_API hub_connection build(); + SIGNALRCLIENT_API std::unique_ptr build(); private: hub_connection_builder(const std::string& url); @@ -50,5 +48,7 @@ namespace signalr std::function(const signalr_client_config&)> m_http_client_factory; bool m_skip_negotiation = false; bool m_use_messagepack = false; + + bool m_built = false; }; } diff --git a/src/signalrclient/hub_connection_builder.cpp b/src/signalrclient/hub_connection_builder.cpp index fca637f2..7f7d6e25 100644 --- a/src/signalrclient/hub_connection_builder.cpp +++ b/src/signalrclient/hub_connection_builder.cpp @@ -51,17 +51,17 @@ namespace signalr hub_connection_builder::~hub_connection_builder() {} - hub_connection_builder& hub_connection_builder::with_logging(std::shared_ptr logger, trace_level logLevel) + hub_connection_builder& hub_connection_builder::with_logging(std::shared_ptr logger, trace_level log_level) { m_logger = logger; - m_log_level = logLevel; + m_log_level = log_level; return *this; } - hub_connection_builder& hub_connection_builder::with_websocket_factory(std::function(const signalr_client_config&)> factory) + hub_connection_builder& hub_connection_builder::with_websocket_factory(std::function(const signalr_client_config&)> websocket_factory) { - m_websocket_factory = factory; + m_websocket_factory = websocket_factory; return *this; } @@ -80,15 +80,17 @@ namespace signalr return *this; } -#ifdef USE_MSGPACK hub_connection_builder& hub_connection_builder::with_messagepack_hub_protocol() { +#ifdef USE_MSGPACK m_use_messagepack = true; return *this; - } +#else + throw std::runtime_error("library was not built with messagepack support. Define USE_MSGPACK when building."); #endif + } - hub_connection hub_connection_builder::build() + std::unique_ptr hub_connection_builder::build() { #ifndef USE_CPPRESTSDK if (m_http_client_factory == nullptr) @@ -115,6 +117,13 @@ namespace signalr hub_protocol = std::unique_ptr(new json_hub_protocol()); } - return hub_connection(m_url, std::move(hub_protocol), m_log_level, m_logger, m_http_client_factory, m_websocket_factory, m_skip_negotiation); + if (m_built) + { + throw std::runtime_error("calling build() more than once is not supported."); + } + + m_built = true; + + return std::unique_ptr(new hub_connection(m_url, std::move(hub_protocol), m_log_level, m_logger, m_http_client_factory, m_websocket_factory, m_skip_negotiation)); } } \ No newline at end of file diff --git a/test/signalrclienttests/connection_tests.cpp b/test/signalrclienttests/connection_tests.cpp index 16c06d89..0aced444 100644 --- a/test/signalrclienttests/connection_tests.cpp +++ b/test/signalrclienttests/connection_tests.cpp @@ -1519,7 +1519,7 @@ TEST(connection_impl_stop, dtor_stops_the_connection) // The connection_impl will be destroyed when the last reference to shared_ptr holding is released. This can happen // on a different thread in which case the dtor will be invoked on a different thread so we need to wait for this // to happen and if it does not the test will fail - for (int wait_time_ms = 5; wait_time_ms < 6000 && memory_writer->get_log_entries().size() < 6; wait_time_ms <<= 1) + for (int wait_time_ms = 5; wait_time_ms < 6000 && memory_writer->get_log_entries().size() < 12; wait_time_ms <<= 1) { std::this_thread::sleep_for(std::chrono::milliseconds(wait_time_ms)); } diff --git a/test/signalrclienttests/hub_connection_tests.cpp b/test/signalrclienttests/hub_connection_tests.cpp index 8188ffa3..9b44a6cf 100644 --- a/test/signalrclienttests/hub_connection_tests.cpp +++ b/test/signalrclienttests/hub_connection_tests.cpp @@ -15,7 +15,7 @@ using namespace signalr; -hub_connection create_hub_connection(std::shared_ptr websocket_client = create_test_websocket_client(), +std::unique_ptr create_hub_connection(std::shared_ptr websocket_client = create_test_websocket_client(), std::shared_ptr log_writer = std::make_shared(), trace_level trace_level = trace_level::verbose) { return hub_connection_builder::create(create_uri()) @@ -57,7 +57,7 @@ void invoke_common_numeric_handling_logic(TValue original_value, std::function(); - hub_connection.start([&connect_mre](std::exception_ptr exception) + hub_connection->start([&connect_mre](std::exception_ptr exception) { connect_mre.set(exception); }); @@ -73,7 +73,7 @@ void invoke_common_numeric_handling_logic(TValue original_value, std::function arr{ signalr::value((double)original_value) }; - hub_connection.invoke("method", arr, [&callback_mre](const signalr::value& message, std::exception_ptr exception) + hub_connection->invoke("method", arr, [&callback_mre](const signalr::value& message, std::exception_ptr exception) { if (exception) { @@ -124,7 +124,7 @@ TEST(url, negotiate_appended_to_url) .build(); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -146,7 +146,7 @@ TEST(start, starts_connection) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -157,7 +157,7 @@ TEST(start, starts_connection) mre.get(); - ASSERT_EQ(connection_state::connected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); } TEST(start, start_sends_handshake) @@ -168,7 +168,7 @@ TEST(start, start_sends_handshake) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -181,7 +181,7 @@ TEST(start, start_sends_handshake) ASSERT_EQ("{\"protocol\":\"json\",\"version\":1}\x1e", *message); - ASSERT_EQ(connection_state::connected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); } TEST(start, start_waits_for_handshake_response) @@ -191,7 +191,7 @@ TEST(start, start_waits_for_handshake_response) auto mre = manual_reset_event(); auto done = false; - hub_connection.start([&mre, &done](std::exception_ptr exception) + hub_connection->start([&mre, &done](std::exception_ptr exception) { done = true; mre.set(exception); @@ -203,7 +203,7 @@ TEST(start, start_waits_for_handshake_response) websocket_client->receive_message("{}\x1e"); mre.get(); - ASSERT_EQ(connection_state::connected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); } TEST(start, start_fails_for_handshake_response_with_error) @@ -211,13 +211,13 @@ TEST(start, start_fails_for_handshake_response_with_error) auto websocket_client = create_test_websocket_client(); auto hub_connection = create_hub_connection(websocket_client); std::exception_ptr exception; - hub_connection.set_disconnected([&exception](std::exception_ptr ex) + hub_connection->set_disconnected([&exception](std::exception_ptr ex) { exception = ex; }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -236,7 +236,7 @@ TEST(start, start_fails_for_handshake_response_with_error) ASSERT_STREQ("Received an error during handshake: bad things", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); try { @@ -255,7 +255,7 @@ TEST(start, start_fails_if_non_handshake_message_received) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -274,7 +274,7 @@ TEST(start, start_fails_if_non_handshake_message_received) ASSERT_STREQ("Received unexpected message while waiting for the handshake response.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(start, on_not_called_if_multiple_messages_received_before_handshake) @@ -283,13 +283,13 @@ TEST(start, on_not_called_if_multiple_messages_received_before_handshake) auto hub_connection = create_hub_connection(websocket_client); bool on_called = false; - hub_connection.on("Target", [&on_called](signalr::value) + hub_connection->on("Target", [&on_called](signalr::value) { on_called = true; }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -308,7 +308,7 @@ TEST(start, on_not_called_if_multiple_messages_received_before_handshake) ASSERT_STREQ("Received unexpected message while waiting for the handshake response.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); ASSERT_FALSE(on_called); } @@ -319,7 +319,7 @@ TEST(start, start_fails_for_incomplete_handshake_response) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -338,7 +338,7 @@ TEST(start, start_fails_for_incomplete_handshake_response) ASSERT_STREQ("connection closed while handshake was in progress.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(start, start_fails_for_invalid_json_handshake_response) @@ -347,7 +347,7 @@ TEST(start, start_fails_for_invalid_json_handshake_response) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -366,7 +366,7 @@ TEST(start, start_fails_for_invalid_json_handshake_response) ASSERT_STREQ("connection closed while handshake was in progress.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(start, start_fails_if_stop_called_before_handshake_response) @@ -375,7 +375,7 @@ TEST(start, start_fails_if_stop_called_before_handshake_response) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -383,7 +383,7 @@ TEST(start, start_fails_if_stop_called_before_handshake_response) ASSERT_FALSE(websocket_client->receive_loop_started.wait(5000)); ASSERT_FALSE(websocket_client->handshake_sent.wait(5000)); - hub_connection.stop([](std::exception_ptr) {}); + hub_connection->stop([](std::exception_ptr) {}); try { @@ -395,7 +395,7 @@ TEST(start, start_fails_if_stop_called_before_handshake_response) ASSERT_STREQ("connection closed while handshake was in progress.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(start, start_fails_if_handshake_times_out) @@ -404,10 +404,10 @@ TEST(start, start_fails_if_handshake_times_out) auto hub_connection = create_hub_connection(websocket_client); auto config = signalr_client_config(); config.set_handshake_timeout(std::chrono::seconds(1)); - hub_connection.set_client_config(config); + hub_connection->set_client_config(config); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -425,7 +425,7 @@ TEST(start, start_fails_if_handshake_times_out) ASSERT_STREQ("timed out waiting for the server to respond to the handshake message.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(start, propogates_exception_from_negotiate) @@ -447,7 +447,7 @@ TEST(start, propogates_exception_from_negotiate) .build(); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -462,7 +462,7 @@ TEST(start, propogates_exception_from_negotiate) ASSERT_STREQ("custom exception", e.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } // regression test: helps ensure internal state is in a working state for connecting again after connection failures @@ -495,13 +495,13 @@ TEST(start, propogates_exception_from_negotiate_and_can_start_again) .build(); std::atomic disconnected { false }; - hub_connection.set_disconnected([&disconnected](std::exception_ptr ex) + hub_connection->set_disconnected([&disconnected](std::exception_ptr ex) { disconnected.store(true); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -518,7 +518,7 @@ TEST(start, propogates_exception_from_negotiate_and_can_start_again) ASSERT_FALSE(disconnected.load()); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -533,7 +533,7 @@ TEST(start, propogates_exception_from_negotiate_and_can_start_again) ASSERT_STREQ("custom exception 2", e.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); ASSERT_FALSE(disconnected.load()); } @@ -543,7 +543,7 @@ TEST(stop, stop_stops_connection) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -554,14 +554,14 @@ TEST(stop, stop_stops_connection) mre.get(); - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); mre.get(); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(stop, does_nothing_on_disconnected_connection) @@ -571,16 +571,16 @@ TEST(stop, does_nothing_on_disconnected_connection) auto mre = manual_reset_event(); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); mre.get(); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } // Makes sure the destructor of hub_connection is safe after moving the object @@ -603,13 +603,13 @@ TEST(stop, second_stop_waits_for_first_stop) }); auto hub_connection = create_hub_connection(websocket_client); bool connection_closed = false; - hub_connection.set_disconnected([&connection_closed](std::exception_ptr) + hub_connection->set_disconnected([&connection_closed](std::exception_ptr) { connection_closed = true; }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -620,14 +620,14 @@ TEST(stop, second_stop_waits_for_first_stop) mre.get(); - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); bool second_stop_called = false; auto second_mre = manual_reset_event(); - hub_connection.stop([&second_stop_called, &second_mre](std::exception_ptr exception) + hub_connection->stop([&second_stop_called, &second_mre](std::exception_ptr exception) { second_stop_called = true; second_mre.set(exception); @@ -643,7 +643,7 @@ TEST(stop, second_stop_waits_for_first_stop) second_mre.get(); ASSERT_TRUE(second_stop_called); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(stop, blocking_stop_callback_does_not_prevent_start) @@ -653,7 +653,7 @@ TEST(stop, blocking_stop_callback_does_not_prevent_start) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -665,7 +665,7 @@ TEST(stop, blocking_stop_callback_does_not_prevent_start) mre.get(); auto blocking_mre = manual_reset_event(); - hub_connection.stop([&mre, &blocking_mre](std::exception_ptr exception) + hub_connection->stop([&mre, &blocking_mre](std::exception_ptr exception) { mre.set(exception); blocking_mre.get(); @@ -673,9 +673,9 @@ TEST(stop, blocking_stop_callback_does_not_prevent_start) }); mre.get(); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -685,7 +685,7 @@ TEST(stop, blocking_stop_callback_does_not_prevent_start) websocket_client->receive_message("{}\x1e"); mre.get(); - ASSERT_EQ(connection_state::connected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); blocking_mre.set(); mre.get(); @@ -697,10 +697,10 @@ TEST(stop, disconnected_callback_called_when_hub_connection_stops) auto hub_connection = create_hub_connection(websocket_client); auto disconnected_invoked = false; - hub_connection.set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked = true; }); + hub_connection->set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked = true; }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -711,7 +711,7 @@ TEST(stop, disconnected_callback_called_when_hub_connection_stops) mre.get(); - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -719,7 +719,7 @@ TEST(stop, disconnected_callback_called_when_hub_connection_stops) mre.get(); ASSERT_TRUE(disconnected_invoked); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(stop, disconnected_callback_called_when_transport_error_occurs) @@ -728,10 +728,10 @@ TEST(stop, disconnected_callback_called_when_transport_error_occurs) auto hub_connection = create_hub_connection(websocket_client); auto disconnected_invoked = manual_reset_event(); - hub_connection.set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked.set(); }); + hub_connection->set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked.set(); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -745,7 +745,7 @@ TEST(stop, disconnected_callback_called_when_transport_error_occurs) websocket_client->receive_message(std::make_exception_ptr(std::runtime_error("transport error"))); disconnected_invoked.get(); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(stop, transport_error_propogates_to_disconnected_callback) @@ -754,10 +754,10 @@ TEST(stop, transport_error_propogates_to_disconnected_callback) auto hub_connection = create_hub_connection(websocket_client); auto disconnected_invoked = manual_reset_event(); - hub_connection.set_disconnected([&disconnected_invoked](std::exception_ptr exception) { disconnected_invoked.set(exception); }); + hub_connection->set_disconnected([&disconnected_invoked](std::exception_ptr exception) { disconnected_invoked.set(exception); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -779,7 +779,7 @@ TEST(stop, transport_error_propogates_to_disconnected_callback) { ASSERT_STREQ("transport error", e.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(stop, connection_stopped_when_going_out_of_scope) @@ -791,7 +791,7 @@ TEST(stop, connection_stopped_when_going_out_of_scope) auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::verbose); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -827,7 +827,7 @@ TEST(stop, stop_cancels_pending_callbacks) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -839,12 +839,12 @@ TEST(stop, stop_cancels_pending_callbacks) mre.get(); auto invoke_mre = manual_reset_event(); - hub_connection.invoke("method", std::vector(), [&invoke_mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&invoke_mre](const signalr::value&, std::exception_ptr exception) { invoke_mre.set(exception); }); - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -871,7 +871,7 @@ TEST(stop, pending_callbacks_finished_if_hub_connections_goes_out_of_scope) { auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -882,7 +882,7 @@ TEST(stop, pending_callbacks_finished_if_hub_connections_goes_out_of_scope) mre.get(); - hub_connection.invoke("method", std::vector(), [&invoke_mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&invoke_mre](const signalr::value&, std::exception_ptr exception) { invoke_mre.set(exception); }); @@ -935,18 +935,18 @@ TEST(stop, stops_with_inprogress_negotiate) auto disconnected_called = false; // disconnected not called for connections that never started successfully - hub_connection.set_disconnected([&disconnected_called](std::exception_ptr ex) + hub_connection->set_disconnected([&disconnected_called](std::exception_ptr ex) { disconnected_called = true; }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); - hub_connection.stop([&stop_mre](std::exception_ptr exception) + hub_connection->stop([&stop_mre](std::exception_ptr exception) { stop_mre.set(exception); }); @@ -963,7 +963,7 @@ TEST(stop, stops_with_inprogress_negotiate) // avoid AV from accessing stop_mre in callback done_mre.get(); - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); ASSERT_FALSE(disconnected_called); } @@ -975,14 +975,14 @@ TEST(hub_invocation, hub_connection_invokes_users_code_on_hub_invocations) auto payload = std::make_shared>(); auto on_broadcast_event = std::make_shared(); - hub_connection.on("broadCAST", [on_broadcast_event, payload](const std::vector& message) + hub_connection->on("broadCAST", [on_broadcast_event, payload](const std::vector& message) { *payload = message; on_broadcast_event->cancel(); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1008,14 +1008,14 @@ TEST(hub_invocation, hub_connection_can_receive_handshake_and_message_in_same_pa auto payload = std::make_shared>(); auto on_broadcast_event = std::make_shared(); - hub_connection.on("broadCAST", [on_broadcast_event, payload](const std::vector& message) + hub_connection->on("broadCAST", [on_broadcast_event, payload](const std::vector& message) { *payload = message; on_broadcast_event->cancel(); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1041,7 +1041,7 @@ TEST(hub_invocation, hub_connection_can_receive_multiple_messages_in_same_payloa auto payload = std::make_shared>(); int count = 0; auto on_broadcast_event = std::make_shared(); - hub_connection.on("broadCAST", [&count, on_broadcast_event, payload](const std::vector& message) + hub_connection->on("broadCAST", [&count, on_broadcast_event, payload](const std::vector& message) { ++count; *payload = message; @@ -1052,7 +1052,7 @@ TEST(hub_invocation, hub_connection_can_receive_multiple_messages_in_same_payloa }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1080,13 +1080,13 @@ TEST(hub_invocation, hub_connection_closes_when_invocation_response_missing_argu auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::error); auto close_mre = manual_reset_event(); - hub_connection.set_disconnected([&close_mre](std::exception_ptr ex) + hub_connection->set_disconnected([&close_mre](std::exception_ptr ex) { close_mre.set(ex); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1124,13 +1124,13 @@ TEST(hub_invocation, hub_connection_closes_when_invocation_response_missing_targ auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::error); auto close_mre = manual_reset_event(); - hub_connection.set_disconnected([&close_mre](std::exception_ptr ex) + hub_connection->set_disconnected([&close_mre](std::exception_ptr ex) { close_mre.set(ex); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1180,7 +1180,7 @@ TEST(send, creates_correct_payload) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1191,7 +1191,7 @@ TEST(send, creates_correct_payload) mre.get(); - hub_connection.send("method", std::vector(), [&mre](std::exception_ptr exception) + hub_connection->send("method", std::vector(), [&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1208,7 +1208,7 @@ TEST(send, does_not_wait_for_server_response) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1220,7 +1220,7 @@ TEST(send, does_not_wait_for_server_response) mre.get(); // wont block waiting for server response - hub_connection.send("method", std::vector(), [&mre](std::exception_ptr exception) + hub_connection->send("method", std::vector(), [&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1247,7 +1247,7 @@ TEST(invoke, creates_correct_payload) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1258,7 +1258,7 @@ TEST(invoke, creates_correct_payload) mre.get(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1293,7 +1293,7 @@ TEST(invoke, callback_not_called_if_send_throws) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1304,7 +1304,7 @@ TEST(invoke, callback_not_called_if_send_throws) mre.get(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1322,7 +1322,7 @@ TEST(invoke, callback_not_called_if_send_throws) // stop completes all outstanding callbacks so if we did not remove a callback when `invoke` failed an // unobserved exception exception would be thrown. Note that this would happen on a different thread and would // crash the process - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1337,7 +1337,7 @@ TEST(invoke, invoke_returns_value_returned_from_the_server) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1349,7 +1349,7 @@ TEST(invoke, invoke_returns_value_returned_from_the_server) mre.get(); auto invoke_mre = manual_reset_event(); - hub_connection.invoke("method", std::vector(), [&invoke_mre](const signalr::value& message, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&invoke_mre](const signalr::value& message, std::exception_ptr exception) { if (exception) { @@ -1376,7 +1376,7 @@ TEST(invoke, invoke_propagates_errors_from_server_as_hub_exceptions) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1387,7 +1387,7 @@ TEST(invoke, invoke_propagates_errors_from_server_as_hub_exceptions) mre.get(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1413,7 +1413,7 @@ TEST(invoke, unblocks_task_when_server_completes_call) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1424,7 +1424,7 @@ TEST(invoke, unblocks_task_when_server_completes_call) mre.get(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1442,7 +1442,7 @@ TEST(receive, logs_if_callback_for_given_id_not_found) auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::info); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1471,13 +1471,13 @@ TEST(receive, closes_if_error_from_parsing) auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::info); auto disconnect_mre = manual_reset_event(); - hub_connection.set_disconnected([&disconnect_mre](std::exception_ptr ex) + hub_connection->set_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1500,7 +1500,7 @@ TEST(receive, closes_if_error_from_parsing) ASSERT_STREQ("* Line 1, Column 33\n Missing ',' or '}' in object declaration\n", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(invoke_void, invoke_creates_runtime_error) @@ -1510,7 +1510,7 @@ TEST(invoke_void, invoke_creates_runtime_error) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1521,7 +1521,7 @@ TEST(invoke_void, invoke_creates_runtime_error) mre.get(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1545,10 +1545,10 @@ TEST(connection_id, can_get_connection_id) auto websocket_client = create_test_websocket_client(); auto hub_connection = create_hub_connection(websocket_client); - ASSERT_EQ("", hub_connection.get_connection_id()); + ASSERT_EQ("", hub_connection->get_connection_id()); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1558,9 +1558,9 @@ TEST(connection_id, can_get_connection_id) websocket_client->receive_message("{ }\x1e"); mre.get(); - auto connection_id = hub_connection.get_connection_id(); + auto connection_id = hub_connection->get_connection_id(); - hub_connection.stop([&mre](std::exception_ptr exception) + hub_connection->stop([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1568,7 +1568,7 @@ TEST(connection_id, can_get_connection_id) mre.get(); ASSERT_EQ("f7707523-307d-4cba-9abf-3eef701241e8", connection_id); - ASSERT_EQ("f7707523-307d-4cba-9abf-3eef701241e8", hub_connection.get_connection_id()); + ASSERT_EQ("f7707523-307d-4cba-9abf-3eef701241e8", hub_connection->get_connection_id()); } TEST(on, event_name_must_not_be_empty_string) @@ -1576,7 +1576,7 @@ TEST(on, event_name_must_not_be_empty_string) auto hub_connection = create_hub_connection(); try { - hub_connection.on("", [](const std::vector&) {}); + hub_connection->on("", [](const std::vector&) {}); ASSERT_TRUE(false); // exception expected but not thrown } @@ -1589,11 +1589,11 @@ TEST(on, event_name_must_not_be_empty_string) TEST(on, cannot_register_multiple_handlers_for_event) { auto hub_connection = create_hub_connection(); - hub_connection.on("ping", [](const std::vector&) {}); + hub_connection->on("ping", [](const std::vector&) {}); try { - hub_connection.on("ping", [](const std::vector&) {}); + hub_connection->on("ping", [](const std::vector&) {}); ASSERT_TRUE(false); // exception expected but not thrown } catch (const signalr_exception& e) @@ -1610,7 +1610,7 @@ TEST(on, cannot_register_handler_if_connection_not_in_disconnected_state) auto hub_connection = create_hub_connection(websocket_client); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1621,7 +1621,7 @@ TEST(on, cannot_register_handler_if_connection_not_in_disconnected_state) mre.get(); - hub_connection.on("myfunc", [](const std::vector&) {}); + hub_connection->on("myfunc", [](const std::vector&) {}); ASSERT_TRUE(false); // exception expected but not thrown } @@ -1636,7 +1636,7 @@ TEST(invoke, invoke_throws_when_the_underlying_connection_is_not_valid) auto hub_connection = create_hub_connection(); auto mre = manual_reset_event(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1657,7 +1657,7 @@ TEST(invoke, send_throws_when_the_underlying_connection_is_not_valid) auto hub_connection = create_hub_connection(); auto mre = manual_reset_event(); - hub_connection.invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&mre](const signalr::value&, std::exception_ptr exception) { mre.set(exception); }); @@ -1770,12 +1770,12 @@ TEST(config, can_replace_scheduler) signalr_client_config config{}; auto scheduler = std::make_shared(); config.set_scheduler(scheduler); - hub_connection.set_client_config(config); + hub_connection->set_client_config(config); // do some "work" to verify scheduler is used auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -1787,7 +1787,7 @@ TEST(config, can_replace_scheduler) mre.get(); auto invoke_mre = manual_reset_event(); - hub_connection.invoke("method", std::vector(), [&invoke_mre](const signalr::value& message, std::exception_ptr exception) + hub_connection->invoke("method", std::vector(), [&invoke_mre](const signalr::value& message, std::exception_ptr exception) { if (exception) { @@ -1803,7 +1803,7 @@ TEST(config, can_replace_scheduler) invoke_mre.get(); - hub_connection.stop([&mre](std::exception_ptr ex) + hub_connection->stop([&mre](std::exception_ptr ex) { mre.set(); }); @@ -1996,10 +1996,10 @@ TEST(keepalive, sends_ping_messages) [](std::function callback) { callback(nullptr); }, false); auto hub_connection = create_hub_connection(websocket_client); - hub_connection.set_client_config(config); + hub_connection->set_client_config(config); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -2016,7 +2016,7 @@ TEST(keepalive, sends_ping_messages) ASSERT_EQ("{\"protocol\":\"json\",\"version\":1}\x1e", (*messages)[0]); ASSERT_EQ("{\"type\":6}\x1e", (*messages)[1]); ASSERT_EQ("{\"type\":6}\x1e", (*messages)[2]); - ASSERT_EQ(connection_state::connected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); } TEST(keepalive, server_timeout_on_no_ping_from_server) @@ -2026,18 +2026,18 @@ TEST(keepalive, server_timeout_on_no_ping_from_server) config.set_server_timeout(std::chrono::seconds(1)); auto websocket_client = create_test_websocket_client(); auto hub_connection = create_hub_connection(websocket_client); - hub_connection.set_client_config(config); + hub_connection->set_client_config(config); auto disconnected_called = false; auto disconnect_mre = manual_reset_event(); - hub_connection.set_disconnected([&disconnected_called, &disconnect_mre](std::exception_ptr ex) + hub_connection->set_disconnected([&disconnected_called, &disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -2057,7 +2057,7 @@ TEST(keepalive, server_timeout_on_no_ping_from_server) { ASSERT_STREQ("server timeout (1000 ms) elapsed without receiving a message from the server.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } TEST(keepalive, resets_server_timeout_timer_on_any_message_from_server) @@ -2067,16 +2067,16 @@ TEST(keepalive, resets_server_timeout_timer_on_any_message_from_server) config.set_server_timeout(std::chrono::seconds(1)); auto websocket_client = create_test_websocket_client(); auto hub_connection = create_hub_connection(websocket_client); - hub_connection.set_client_config(config); + hub_connection->set_client_config(config); auto disconnect_mre = manual_reset_event(); - hub_connection.set_disconnected([&disconnect_mre](std::exception_ptr ex) + hub_connection->set_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); auto mre = manual_reset_event(); - hub_connection.start([&mre](std::exception_ptr exception) + hub_connection->start([&mre](std::exception_ptr exception) { mre.set(exception); }); @@ -2090,7 +2090,7 @@ TEST(keepalive, resets_server_timeout_timer_on_any_message_from_server) std::this_thread::sleep_for(config.get_server_timeout() - std::chrono::milliseconds(500)); websocket_client->receive_message("{\"type\":6}\x1e"); std::this_thread::sleep_for(std::chrono::seconds(1)); - ASSERT_EQ(connection_state::connected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); try { @@ -2101,7 +2101,7 @@ TEST(keepalive, resets_server_timeout_timer_on_any_message_from_server) { ASSERT_STREQ("server timeout (1000 ms) elapsed without receiving a message from the server.", ex.what()); } - ASSERT_EQ(connection_state::disconnected, hub_connection.get_connection_state()); + ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } class unknown_message_type_hub_protocol : public hub_protocol From ff2a72d04bf42c08170c95491640dda3c220f366 Mon Sep 17 00:00:00 2001 From: Brennan Date: Fri, 2 Dec 2022 11:02:31 -0800 Subject: [PATCH 2/3] wip --- include/signalrclient/http_client.h | 55 +- include/signalrclient/hub_connection.h | 26 +- .../signalrclient/hub_connection_builder.h | 25 +- .../{trace_level.h => log_level.h} | 2 +- include/signalrclient/scheduler.h | 4 +- include/signalrclient/signalr_client_config.h | 30 +- include/signalrclient/signalr_value.h | 34 +- .../HubConnectionSample.cpp | 18 +- src/signalrclient/CMakeLists.txt | 1 + src/signalrclient/callback_manager.cpp | 2 +- src/signalrclient/callback_manager.h | 2 +- src/signalrclient/connection_impl.cpp | 158 +++-- src/signalrclient/connection_impl.h | 21 +- src/signalrclient/default_http_client.cpp | 18 +- .../default_websocket_client.cpp | 8 +- src/signalrclient/http_utilities.cpp | 64 ++ src/signalrclient/hub_connection.cpp | 20 +- src/signalrclient/hub_connection_builder.cpp | 37 +- src/signalrclient/hub_connection_impl.cpp | 96 +-- src/signalrclient/hub_connection_impl.h | 20 +- src/signalrclient/json_helpers.cpp | 14 +- src/signalrclient/logger.cpp | 30 +- src/signalrclient/logger.h | 18 +- .../messagepack_hub_protocol.cpp | 14 +- src/signalrclient/negotiate.cpp | 183 +++-- src/signalrclient/negotiate.h | 9 +- src/signalrclient/signalr_client_config.cpp | 51 +- .../signalr_default_scheduler.cpp | 18 +- src/signalrclient/signalr_default_scheduler.h | 17 +- src/signalrclient/signalr_value.cpp | 146 ++-- src/signalrclient/websocket_transport.cpp | 22 +- src/signalrclient/websocket_transport.h | 4 +- test/signalrclienttests/CMakeLists.txt | 1 + test/signalrclienttests/connection_tests.cpp | 651 +++++++++--------- .../hub_connection_tests.cpp | 270 ++++---- test/signalrclienttests/logger_tests.cpp | 16 +- test/signalrclienttests/negotiate_tests.cpp | 10 +- test/signalrclienttests/test_utils.cpp | 18 +- test/signalrclienttests/test_utils.h | 2 +- .../test_websocket_client.cpp | 4 +- .../test_websocket_client.h | 6 +- .../websocket_transport_tests.cpp | 40 +- 42 files changed, 1113 insertions(+), 1072 deletions(-) rename include/signalrclient/{trace_level.h => log_level.h} (92%) create mode 100644 src/signalrclient/http_utilities.cpp diff --git a/include/signalrclient/http_client.h b/include/signalrclient/http_client.h index 7e134265..9f0da04d 100644 --- a/include/signalrclient/http_client.h +++ b/include/signalrclient/http_client.h @@ -19,45 +19,68 @@ namespace signalr POST }; - class http_request + class http_request final { public: + http_method get_method() const; + + const std::map& get_headers() const; + + const std::string& get_content() const; + + std::chrono::seconds get_timeout() const; + private: + friend class negotiate; + + http_method m_method; + std::map m_headers; + std::string m_content; + std::chrono::seconds m_timeout; + http_request() - : method(http_method::GET), timeout(std::chrono::seconds(120)) + : m_method(http_method::GET), m_timeout(std::chrono::seconds(120)) { } - http_method method; - std::map headers; - std::string content; - std::chrono::seconds timeout; + void set_timeout(std::chrono::seconds timeout); + void set_content(const std::string& body); + void set_content(std::string&& body); + void set_headers(const std::map& headers); + void set_method(http_method method); }; - class http_response + class http_response final { public: http_response() {} - http_response(http_response&& rhs) noexcept : status_code(rhs.status_code), content(std::move(rhs.content)) {} - http_response(int code, const std::string& content) : status_code(code), content(content) {} - http_response(const http_response& rhs) : status_code(rhs.status_code), content(rhs.content) {} + http_response(http_response&& rhs) noexcept : m_status_code(rhs.m_status_code), m_content(std::move(rhs.m_content)) {} + http_response(int code, const std::string& content) : m_status_code(code), m_content(content) {} + http_response(int code, std::string&& content) : m_status_code(code), m_content(std::move(content)) {} + http_response(const http_response& rhs) : m_status_code(rhs.m_status_code), m_content(rhs.m_content) {} http_response& operator=(const http_response& rhs) { - status_code = rhs.status_code; - content = rhs.content; + m_status_code = rhs.m_status_code; + m_content = rhs.m_content; return *this; } http_response& operator=(http_response&& rhs) noexcept { - status_code = rhs.status_code; - content = std::move(rhs.content); + m_status_code = rhs.m_status_code; + m_content = std::move(rhs.m_content); return *this; } - int status_code = 0; - std::string content; + private: + friend class negotiate; + + int get_status_code() const; + const std::string& get_content() const; + + int m_status_code = 0; + std::string m_content; }; class http_client diff --git a/include/signalrclient/hub_connection.h b/include/signalrclient/hub_connection.h index c6a04ca2..e73f5aa0 100644 --- a/include/signalrclient/hub_connection.h +++ b/include/signalrclient/hub_connection.h @@ -8,7 +8,7 @@ #include #include #include "connection_state.h" -#include "trace_level.h" +#include "log_level.h" #include "log_writer.h" #include "signalr_client_config.h" #include "signalr_value.h" @@ -24,8 +24,6 @@ namespace signalr class hub_connection { public: - typedef std::function&)> method_invoked_handler; - SIGNALRCLIENT_API ~hub_connection(); hub_connection(const hub_connection&) = delete; @@ -36,17 +34,17 @@ namespace signalr SIGNALRCLIENT_API hub_connection& operator=(hub_connection&&) noexcept; - SIGNALRCLIENT_API void __cdecl start(std::function callback) noexcept; - SIGNALRCLIENT_API void __cdecl stop(std::function callback) noexcept; + SIGNALRCLIENT_API void start(std::function callback) noexcept; + SIGNALRCLIENT_API void stop(std::function callback) noexcept; - SIGNALRCLIENT_API connection_state __cdecl get_connection_state() const; - SIGNALRCLIENT_API std::string __cdecl get_connection_id() const; + SIGNALRCLIENT_API connection_state get_connection_state() const; + SIGNALRCLIENT_API const std::string& get_connection_id() const; - SIGNALRCLIENT_API void __cdecl set_disconnected(const std::function& disconnected_callback); + SIGNALRCLIENT_API void on_disconnected(std::function disconnected_callback); - SIGNALRCLIENT_API void __cdecl set_client_config(const signalr_client_config& config); + //SIGNALRCLIENT_API void __cdecl set_client_config(const signalr_client_config& config); - SIGNALRCLIENT_API void __cdecl on(const std::string& event_name, const method_invoked_handler& handler); + SIGNALRCLIENT_API void on(const std::string& event_name, std::function&)> handler); SIGNALRCLIENT_API void invoke(const std::string& method_name, const std::vector& arguments = std::vector(), std::function callback = [](const signalr::value&, std::exception_ptr) {}) noexcept; @@ -55,10 +53,10 @@ namespace signalr private: friend class hub_connection_builder; - explicit hub_connection(const std::string& url, std::unique_ptr&& hub_protocol, - trace_level trace_level = trace_level::info, std::shared_ptr log_writer = nullptr, - std::function(const signalr_client_config&)> http_client_factory = nullptr, - std::function(const signalr_client_config&)> websocket_factory = nullptr, + explicit hub_connection(const std::string& url, std::unique_ptr&& hub_protocol, signalr_client_config config, + log_level log_level = log_level::info, std::shared_ptr log_writer = nullptr, + std::function(const signalr_client_config&)> http_client_factory = nullptr, + std::function(const signalr_client_config&)> websocket_factory = nullptr, bool skip_negotiation = false); std::shared_ptr m_pImpl; diff --git a/include/signalrclient/hub_connection_builder.h b/include/signalrclient/hub_connection_builder.h index 12b3378d..ad3f9a14 100644 --- a/include/signalrclient/hub_connection_builder.h +++ b/include/signalrclient/hub_connection_builder.h @@ -15,37 +15,38 @@ namespace signalr class hub_connection_builder final { public: - SIGNALRCLIENT_API static hub_connection_builder create(const std::string& url); + SIGNALRCLIENT_API hub_connection_builder(std::string url); SIGNALRCLIENT_API ~hub_connection_builder(); - SIGNALRCLIENT_API hub_connection_builder(const hub_connection_builder&); + SIGNALRCLIENT_API hub_connection_builder(const hub_connection_builder&) = delete; SIGNALRCLIENT_API hub_connection_builder(hub_connection_builder&&) noexcept; SIGNALRCLIENT_API hub_connection_builder& operator=(hub_connection_builder&&) noexcept; - SIGNALRCLIENT_API hub_connection_builder& operator=(const hub_connection_builder&); + SIGNALRCLIENT_API hub_connection_builder& operator=(const hub_connection_builder&) = delete; - SIGNALRCLIENT_API hub_connection_builder& with_logging(std::shared_ptr logger, trace_level log_level); + SIGNALRCLIENT_API hub_connection_builder& configure_options(signalr_client_config config) noexcept; - SIGNALRCLIENT_API hub_connection_builder& with_websocket_factory(std::function(const signalr_client_config&)> websocket_factory); + SIGNALRCLIENT_API hub_connection_builder& with_logging(std::shared_ptr logger, log_level log_level) noexcept; - SIGNALRCLIENT_API hub_connection_builder& with_http_client_factory(std::function(const signalr_client_config&)> http_client_factory); + SIGNALRCLIENT_API hub_connection_builder& with_websocket_factory(std::function(const signalr_client_config&)> websocket_factory) noexcept; - SIGNALRCLIENT_API hub_connection_builder& skip_negotiation(bool skip = true); + SIGNALRCLIENT_API hub_connection_builder& with_http_client_factory(std::function(const signalr_client_config&)> http_client_factory) noexcept; + + SIGNALRCLIENT_API hub_connection_builder& skip_negotiation(bool skip = true) noexcept; SIGNALRCLIENT_API hub_connection_builder& with_messagepack_hub_protocol(); SIGNALRCLIENT_API std::unique_ptr build(); private: - hub_connection_builder(const std::string& url); - std::string m_url; + signalr_client_config m_config; std::shared_ptr m_logger; - trace_level m_log_level; - std::function(const signalr_client_config&)> m_websocket_factory; - std::function(const signalr_client_config&)> m_http_client_factory; + log_level m_log_level; + std::function(const signalr_client_config&)> m_websocket_factory; + std::function(const signalr_client_config&)> m_http_client_factory; bool m_skip_negotiation = false; bool m_use_messagepack = false; diff --git a/include/signalrclient/trace_level.h b/include/signalrclient/log_level.h similarity index 92% rename from include/signalrclient/trace_level.h rename to include/signalrclient/log_level.h index e45e32c4..e16ef5bc 100644 --- a/include/signalrclient/trace_level.h +++ b/include/signalrclient/log_level.h @@ -6,7 +6,7 @@ namespace signalr { - enum class trace_level : int + enum class log_level { verbose = 0, debug = 1, diff --git a/include/signalrclient/scheduler.h b/include/signalrclient/scheduler.h index 640ea9e9..7dd632a0 100644 --- a/include/signalrclient/scheduler.h +++ b/include/signalrclient/scheduler.h @@ -10,11 +10,9 @@ namespace signalr { - typedef std::function signalr_base_cb; - struct scheduler { - virtual void schedule(const signalr_base_cb& cb, std::chrono::milliseconds delay = std::chrono::milliseconds::zero()) = 0; + virtual void schedule(std::function cb, std::chrono::milliseconds delay = std::chrono::milliseconds::zero()) = 0; virtual ~scheduler() {} }; diff --git a/include/signalrclient/signalr_client_config.h b/include/signalrclient/signalr_client_config.h index 37c4f91c..4aae30a5 100644 --- a/include/signalrclient/signalr_client_config.h +++ b/include/signalrclient/signalr_client_config.h @@ -20,31 +20,15 @@ namespace signalr { - class signalr_client_config + class signalr_client_config final { public: -#ifdef USE_CPPRESTSDK - SIGNALRCLIENT_API void __cdecl set_proxy(const web::web_proxy &proxy); - // Please note that setting credentials does not work in all cases. - // For example, Basic Authentication fails under Win32. - // As a workaround, you can set the required authorization headers directly - // using signalr_client_config::set_http_headers - SIGNALRCLIENT_API void __cdecl set_credentials(const web::credentials &credentials); - - 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 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); -#endif - SIGNALRCLIENT_API signalr_client_config(); - SIGNALRCLIENT_API const std::map& __cdecl get_http_headers() const noexcept; - SIGNALRCLIENT_API std::map& __cdecl get_http_headers() noexcept; - SIGNALRCLIENT_API void __cdecl set_http_headers(const std::map& http_headers); - SIGNALRCLIENT_API void __cdecl set_scheduler(std::shared_ptr scheduler); - SIGNALRCLIENT_API const std::shared_ptr& __cdecl get_scheduler() const noexcept; + SIGNALRCLIENT_API const std::map& get_http_headers() const noexcept; + SIGNALRCLIENT_API void set_http_headers(std::map http_headers) noexcept; + SIGNALRCLIENT_API void set_scheduler(std::shared_ptr scheduler) noexcept; + SIGNALRCLIENT_API std::shared_ptr get_scheduler() const noexcept; SIGNALRCLIENT_API void set_handshake_timeout(std::chrono::milliseconds); SIGNALRCLIENT_API std::chrono::milliseconds get_handshake_timeout() const noexcept; SIGNALRCLIENT_API void set_server_timeout(std::chrono::milliseconds); @@ -53,10 +37,6 @@ namespace signalr SIGNALRCLIENT_API std::chrono::milliseconds get_keepalive_interval() const noexcept; private: -#ifdef USE_CPPRESTSDK - web::http::client::http_client_config m_http_client_config; - web::websockets::client::websocket_client_config m_websocket_client_config; -#endif std::map m_http_headers; std::shared_ptr m_scheduler; std::chrono::milliseconds m_handshake_timeout; diff --git a/include/signalrclient/signalr_value.h b/include/signalrclient/signalr_value.h index 376915d0..b0c736c9 100644 --- a/include/signalrclient/signalr_value.h +++ b/include/signalrclient/signalr_value.h @@ -12,26 +12,26 @@ namespace signalr { - /** - * An enum defining the types a signalr::value may be. - */ - enum class value_type - { - map, - array, - string, - float64, - null, - boolean, - binary - }; - /** * Represents a value to be provided to a SignalR method as a parameter, or returned as a return value. */ class value { public: + /** + * An enum defining the types a signalr::value may be. + */ + enum class type + { + map, + array, + string, + float64, + null, + boolean, + binary + }; + /** * Create an object representing a value_type::null value. */ @@ -45,7 +45,7 @@ namespace signalr /** * Create an object representing a default value for the given value_type. */ - SIGNALRCLIENT_API value(value_type t); + SIGNALRCLIENT_API value(type t); /** * Create an object representing a value_type::boolean with the given bool value. @@ -200,10 +200,10 @@ namespace signalr /** * Returns the signalr::type that represents the stored object. */ - SIGNALRCLIENT_API value_type type() const; + SIGNALRCLIENT_API type type() const; private: - value_type mType; + enum type mType; union storage { diff --git a/samples/HubConnectionSample/HubConnectionSample.cpp b/samples/HubConnectionSample/HubConnectionSample.cpp index 222ab459..9a4e8b2a 100644 --- a/samples/HubConnectionSample/HubConnectionSample.cpp +++ b/samples/HubConnectionSample/HubConnectionSample.cpp @@ -18,12 +18,12 @@ class logger : public signalr::log_writer } }; -void send_message(signalr::hub_connection& connection, const std::string& message) +void send_message(const std::unique_ptr& connection, const std::string& message) { std::vector args { std::string("c++"), message }; // if you get an internal compiler error uncomment the lambda below or install VS Update 4 - connection.invoke("SendMessage", args, [](const signalr::value& value, std::exception_ptr exception) + connection->invoke("SendMessage", args, [](const signalr::value& value, std::exception_ptr exception) { try { @@ -50,17 +50,17 @@ void send_message(signalr::hub_connection& connection, const std::string& messag void chat() { - signalr::hub_connection connection = signalr::hub_connection_builder::create("http://localhost:5000/default") - .with_logging(std::make_shared (), signalr::trace_level::verbose) + std::unique_ptr connection = signalr::hub_connection_builder("http://localhost:61633/default") + .with_logging(std::make_shared (), signalr::log_level::verbose) .build(); - connection.on("ReceiveMessage", [](const std::vector& m) + connection->on("ReceiveMessage", [](const std::vector& m) { std::cout << std::endl << m[0].as_string() << std::endl << "Enter your message: "; }); std::promise startTask; - connection.start([&connection, &startTask](std::exception_ptr exception) + connection->start([&connection, &startTask](std::exception_ptr exception) { if (exception) { @@ -79,12 +79,12 @@ void chat() startTask.get_future().get(); std::cout << "Enter your message:"; - while (connection.get_connection_state() == signalr::connection_state::connected) + while (connection->get_connection_state() == signalr::connection_state::connected) { std::string message; std::getline(std::cin, message); - if (message == ":q" || connection.get_connection_state() != signalr::connection_state::connected) + if (message == ":q" || connection->get_connection_state() != signalr::connection_state::connected) { break; } @@ -93,7 +93,7 @@ void chat() } std::promise stopTask; - connection.stop([&stopTask](std::exception_ptr exception) + connection->stop([&stopTask](std::exception_ptr exception) { try { diff --git a/src/signalrclient/CMakeLists.txt b/src/signalrclient/CMakeLists.txt index 5f81c791..e8e7bb1d 100644 --- a/src/signalrclient/CMakeLists.txt +++ b/src/signalrclient/CMakeLists.txt @@ -6,6 +6,7 @@ set (SOURCES default_http_client.cpp default_websocket_client.cpp handshake_protocol.cpp + http_utilities.cpp hub_connection.cpp hub_connection_builder.cpp hub_connection_impl.cpp diff --git a/src/signalrclient/callback_manager.cpp b/src/signalrclient/callback_manager.cpp index 1dc2876b..940b774a 100644 --- a/src/signalrclient/callback_manager.cpp +++ b/src/signalrclient/callback_manager.cpp @@ -20,7 +20,7 @@ namespace signalr } // note: callback must not throw except for the `on_progress` callback which will never be invoked from the dtor - std::string callback_manager::register_callback(const std::function& callback) + std::string callback_manager::register_callback(std::function callback) { auto callback_id = get_callback_id(); diff --git a/src/signalrclient/callback_manager.h b/src/signalrclient/callback_manager.h index 3879cfbd..8a490206 100644 --- a/src/signalrclient/callback_manager.h +++ b/src/signalrclient/callback_manager.h @@ -21,7 +21,7 @@ namespace signalr callback_manager(const callback_manager&) = delete; callback_manager& operator=(const callback_manager&) = delete; - std::string register_callback(const std::function& callback); + std::string register_callback(std::function callback); bool invoke_callback(const std::string& callback_id, const char* error, const signalr::value& arguments, bool remove_callback); bool remove_callback(const std::string& callback_id); void clear(const char* error); diff --git a/src/signalrclient/connection_impl.cpp b/src/signalrclient/connection_impl.cpp index 888f969f..cd5278bf 100644 --- a/src/signalrclient/connection_impl.cpp +++ b/src/signalrclient/connection_impl.cpp @@ -20,16 +20,16 @@ namespace signalr { - std::shared_ptr connection_impl::create(const std::string& url, trace_level trace_level, const std::shared_ptr& log_writer, - std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) + std::shared_ptr connection_impl::create(const std::string& url, log_level log_level, const std::shared_ptr& log_writer, + std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) { - return std::shared_ptr(new connection_impl(url, trace_level, + return std::shared_ptr(new connection_impl(url, log_level, log_writer ? log_writer : std::make_shared(), http_client_factory, websocket_factory, skip_negotiation)); } - connection_impl::connection_impl(const std::string& url, trace_level trace_level, const std::shared_ptr& log_writer, - std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) - : m_base_url(url), m_connection_state(connection_state::disconnected), m_logger(log_writer, trace_level), m_transport(nullptr), m_skip_negotiation(skip_negotiation), + connection_impl::connection_impl(const std::string& url, log_level log_level, const std::shared_ptr& log_writer, + std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) + : m_base_url(url), m_connection_state(connection_state::disconnected), m_logger(log_writer, log_level), m_transport(nullptr), m_skip_negotiation(skip_negotiation), m_message_received([](const std::string&) noexcept {}), m_disconnected([](std::exception_ptr) noexcept {}), m_disconnect_cts(std::make_shared()) { if (http_client_factory != nullptr) @@ -46,7 +46,7 @@ namespace signalr if (websocket_factory == nullptr) { #ifdef USE_CPPRESTSDK - websocket_factory = [](const signalr_client_config& signalr_client_config) { return std::make_shared(signalr_client_config); }; + websocket_factory = [](const signalr_client_config& signalr_client_config) { return std::unique_ptr(new default_websocket_client(signalr_client_config)); }; #endif } @@ -66,15 +66,15 @@ namespace signalr } catch (const std::exception& ex) { - if (m_logger.is_enabled(trace_level::warning)) + if (m_logger.is_enabled(log_level::warning)) { - m_logger.log(trace_level::warning, std::string("start completed event threw an exception in the destructor: ") + m_logger.log(log_level::warning, std::string("start completed event threw an exception in the destructor: ") .append(ex.what())); } } completion_event completion; auto logger = m_logger; - logger.log(signalr::trace_level::verbose, "calling shutdown() from the dtor"); + logger.log(signalr::log_level::verbose, "calling shutdown() from the dtor"); shutdown([completion, logger](std::exception_ptr exception) mutable { if (exception != nullptr) @@ -86,10 +86,10 @@ namespace signalr } catch (const std::exception& e) { - if (logger.is_enabled(trace_level::error)) + if (logger.is_enabled(log_level::error)) { logger.log( - trace_level::error, + log_level::error, std::string("shutdown threw an exception: ") .append(e.what())); } @@ -97,7 +97,7 @@ namespace signalr catch (...) { logger.log( - trace_level::error, + log_level::error, "shutdown threw an unknown exception."); } } @@ -134,11 +134,11 @@ namespace signalr { { std::lock_guard lock(m_stop_lock); - m_logger.log(trace_level::verbose, "acquired lock in start()"); + m_logger.log(log_level::verbose, "acquired lock in start()"); auto logger = m_logger; auto _ = callback_on_destruct([logger]() { - logger.log(trace_level::verbose, "released lock in start()"); + logger.log(log_level::verbose, "released lock in start()"); }); if (!change_state(connection_state::disconnected, connection_state::connecting)) @@ -217,14 +217,14 @@ namespace signalr { if (token->is_canceled()) { - connection->m_logger.log(trace_level::info, + connection->m_logger.log(log_level::info, "starting the connection has been canceled by stop()."); } else { - if (connection->m_logger.is_enabled(trace_level::error)) + if (connection->m_logger.is_enabled(log_level::error)) { - connection->m_logger.log(trace_level::error, + connection->m_logger.log(log_level::error, std::string("connection could not be started due to: ") .append(e.what())); } @@ -238,9 +238,9 @@ namespace signalr } catch (const std::exception& ex) { - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, std::string("start completed event threw an exception in start negotiate: ") + connection->m_logger.log(log_level::warning, std::string("start completed event threw an exception in start negotiate: ") .append(ex.what())); } } @@ -250,9 +250,9 @@ namespace signalr } catch (const std::exception& ex) { - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, std::string("disconnect event threw an exception in start negotiate: ") + connection->m_logger.log(log_level::warning, std::string("disconnect event threw an exception in start negotiate: ") .append(ex.what())); } } @@ -264,9 +264,9 @@ namespace signalr if (!connection->change_state(connection_state::connecting, connection_state::connected)) { - if (connection->m_logger.is_enabled(trace_level::error)) + if (connection->m_logger.is_enabled(log_level::error)) { - connection->m_logger.log(trace_level::error, + connection->m_logger.log(log_level::error, std::string("internal error - transition from an unexpected state. expected state: connecting, actual state: ") .append(translate_connection_state(connection->get_connection_state()))); } @@ -280,9 +280,9 @@ namespace signalr } catch (const std::exception& ex) { - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, std::string("start completed event threw an exception in start negotiate: ") + connection->m_logger.log(log_level::warning, std::string("start completed event threw an exception in start negotiate: ") .append(ex.what())); } } @@ -303,10 +303,14 @@ namespace signalr return start_transport(url, transport_started); } - start_negotiate_internal(url, 0, transport_started); + auto http_client = m_http_client_factory(m_signalr_client_config); + std::shared_ptr s(std::move(http_client)); + start_negotiate_internal(url, 0, transport_started, std::move(s)); } - void connection_impl::start_negotiate_internal(const std::string& url, int redirect_count, std::function transport, std::exception_ptr)> transport_started) + void connection_impl::start_negotiate_internal(const std::string& url, int redirect_count, + std::function transport, std::exception_ptr)> transport_started, + std::shared_ptr http_client) { if (m_disconnect_cts->is_canceled()) { @@ -322,9 +326,8 @@ namespace signalr std::weak_ptr weak_connection = shared_from_this(); const auto token = m_disconnect_cts; - auto http_client = m_http_client_factory(m_signalr_client_config); - negotiate::negotiate(http_client, url, m_signalr_client_config, - [transport_started, weak_connection, redirect_count, token, url](negotiation_response&& response, std::exception_ptr exception) + negotiate::send_negotiate(http_client.get(), url, m_signalr_client_config, + [transport_started, weak_connection, redirect_count, token, url, http_client](negotiation_response&& response, std::exception_ptr exception) { auto connection = weak_connection.lock(); if (!connection) @@ -341,9 +344,9 @@ namespace signalr } catch (const std::exception& e) { - if (connection->m_logger.is_enabled(trace_level::error)) + if (connection->m_logger.is_enabled(log_level::error)) { - connection->m_logger.log(trace_level::error, + connection->m_logger.log(log_level::error, std::string("connection could not be started due to: ") .append(e.what())); } @@ -362,10 +365,10 @@ namespace signalr { if (!response.accessToken.empty()) { - auto& headers = connection->m_signalr_client_config.get_http_headers(); - headers["Authorization"] = "Bearer " + response.accessToken; + //auto& headers = connection->m_signalr_client_config.get_http_headers(); + //headers["Authorization"] = "Bearer " + response.accessToken; } - connection->start_negotiate_internal(response.url, redirect_count + 1, transport_started); + connection->start_negotiate_internal(response.url, redirect_count + 1, transport_started, std::move(http_client)); return; } @@ -435,9 +438,9 @@ namespace signalr { if (disconnect_cts->is_canceled()) { - if (logger.is_enabled(trace_level::info)) + if (logger.is_enabled(log_level::info)) { - logger.log(trace_level::info, + logger.log(log_level::info, std::string{ "ignoring stray message received after connection was restarted. message: " } .append(message)); } @@ -465,9 +468,9 @@ namespace signalr // or for the one that was already stopped. If this is the latter we just ignore it. if (disconnect_cts->is_canceled()) { - if (logger.is_enabled(trace_level::info)) + if (logger.is_enabled(log_level::info)) { - logger.log(trace_level::info, + logger.log(log_level::info, std::string{ "ignoring stray error received after connection was restarted. error: " } .append(e.what())); } @@ -511,10 +514,10 @@ namespace signalr } catch (const std::exception& e) { - if (logger.is_enabled(trace_level::error)) + if (logger.is_enabled(log_level::error)) { logger.log( - trace_level::error, + log_level::error, std::string("transport could not connect due to: ") .append(e.what())); } @@ -526,10 +529,10 @@ namespace signalr void connection_impl::process_response(std::string&& response) { - if (m_logger.is_enabled(trace_level::debug)) + if (m_logger.is_enabled(log_level::debug)) { // TODO: log binary data better - m_logger.log(trace_level::debug, + m_logger.log(log_level::debug, std::string("processing message: ").append(response)); } @@ -544,17 +547,17 @@ namespace signalr } catch (const std::exception &e) { - if (m_logger.is_enabled(trace_level::error)) + if (m_logger.is_enabled(log_level::error)) { m_logger.log( - trace_level::error, + log_level::error, std::string("message_received callback threw an exception: ") .append(e.what())); } } catch (...) { - m_logger.log(trace_level::error, "message_received callback threw an unknown exception"); + m_logger.log(log_level::error, "message_received callback threw an unknown exception"); } } @@ -576,9 +579,9 @@ namespace signalr auto logger = m_logger; - if (logger.is_enabled(trace_level::info)) + if (logger.is_enabled(log_level::info)) { - logger.log(trace_level::info, std::string("sending data: ").append(data)); + logger.log(log_level::info, std::string("sending data: ").append(data)); } transport->send(data, transfer_format, [logger, callback](std::exception_ptr exception) @@ -593,10 +596,10 @@ namespace signalr } catch (const std::exception &e) { - if (logger.is_enabled(trace_level::error)) + if (logger.is_enabled(log_level::error)) { logger.log( - trace_level::error, + log_level::error, std::string("error sending data: ") .append(e.what())); } @@ -609,7 +612,7 @@ namespace signalr void connection_impl::stop(std::function callback, std::exception_ptr exception) noexcept { m_stop_error = exception; - m_logger.log(trace_level::info, "closing connection"); + m_logger.log(log_level::info, "closing connection"); shutdown(callback); } @@ -619,27 +622,27 @@ namespace signalr { { std::lock_guard lock(m_stop_lock); - m_logger.log(trace_level::verbose, "acquired lock in shutdown()"); + m_logger.log(log_level::verbose, "acquired lock in shutdown()"); auto logger = m_logger; auto _ = callback_on_destruct([logger]() { - logger.log(trace_level::verbose, "released lock in shutdown()"); + logger.log(log_level::verbose, "released lock in shutdown()"); }); const auto current_state = get_connection_state(); if (current_state == connection_state::disconnected) { // change log level if already disconnected and shutdown called from dtor, it's just noise - m_logger.log(is_dtor ? trace_level::verbose : trace_level::debug, "connection already disconnected"); + m_logger.log(is_dtor ? log_level::verbose : log_level::debug, "connection already disconnected"); try { m_disconnect_cts->cancel(); } catch (const std::exception& ex) { - if (m_logger.is_enabled(trace_level::warning)) + if (m_logger.is_enabled(log_level::warning)) { - m_logger.log(trace_level::warning, std::string("disconnect event threw an exception in shutdown: ") + m_logger.log(log_level::warning, std::string("disconnect event threw an exception in shutdown: ") .append(ex.what())); } } @@ -663,16 +666,16 @@ namespace signalr } catch (const std::exception& ex) { - if (m_logger.is_enabled(trace_level::warning)) + if (m_logger.is_enabled(log_level::warning)) { - m_logger.log(trace_level::warning, std::string("disconnect event threw an exception in shutdown: ") + m_logger.log(log_level::warning, std::string("disconnect event threw an exception in shutdown: ") .append(ex.what())); } } while (m_start_completed_event.wait(60000) != 0) { - m_logger.log(trace_level::error, + m_logger.log(log_level::error, "internal error - stopping the connection is still waiting for the start operation to finish which should have already finished or timed out"); } @@ -689,7 +692,7 @@ namespace signalr change_state(connection_state::disconnecting); } - m_logger.log(trace_level::debug, "stopping transport"); + m_logger.log(log_level::debug, "stopping transport"); m_transport->stop(callback); } @@ -701,16 +704,16 @@ namespace signalr // on a different thread at the same time. In this case we must not null out the transport if we are // not in the `disconnecting` state to not affect the 'start' invocation. std::lock_guard lock(m_stop_lock); - m_logger.log(trace_level::verbose, "acquired lock in stop_connection()"); + m_logger.log(log_level::verbose, "acquired lock in stop_connection()"); auto logger = m_logger; auto _ = callback_on_destruct([logger]() { - logger.log(trace_level::verbose, "released lock in stop_connection()"); + logger.log(log_level::verbose, "released lock in stop_connection()"); }); if (m_connection_state == connection_state::disconnected) { - m_logger.log(trace_level::info, "Stopping was ignored because the connection is already in the disconnected state."); + m_logger.log(log_level::info, "Stopping was ignored because the connection is already in the disconnected state."); return; } @@ -733,15 +736,15 @@ namespace signalr } catch (const std::exception & ex) { - if (m_logger.is_enabled(trace_level::error)) + if (m_logger.is_enabled(log_level::error)) { - m_logger.log(trace_level::error, std::string("connection closed with error: ").append(ex.what())); + m_logger.log(log_level::error, std::string("connection closed with error: ").append(ex.what())); } } } else { - m_logger.log(trace_level::info, "connection closed"); + m_logger.log(log_level::info, "connection closed"); } try @@ -750,10 +753,10 @@ namespace signalr } catch (const std::exception & e) { - if (m_logger.is_enabled(trace_level::error)) + if (m_logger.is_enabled(log_level::error)) { m_logger.log( - trace_level::error, + log_level::error, std::string("disconnected callback threw an exception: ") .append(e.what())); } @@ -761,7 +764,7 @@ namespace signalr catch (...) { m_logger.log( - trace_level::error, + log_level::error, "disconnected callback threw an unknown exception"); } } @@ -771,17 +774,12 @@ namespace signalr return m_connection_state.load(); } - std::string connection_impl::get_connection_id() const noexcept + const std::string& connection_impl::get_connection_id() const noexcept { - if (m_connection_state.load() == connection_state::connecting) - { - return ""; - } - return m_connection_id; } - void connection_impl::set_message_received(const std::function& message_received) + void connection_impl::set_message_received(std::function message_received) { ensure_disconnected("cannot set the callback when the connection is not in the disconnected state. "); m_message_received = message_received; @@ -793,7 +791,7 @@ namespace signalr m_signalr_client_config = config; } - void connection_impl::set_disconnected(const std::function& disconnected) + void connection_impl::on_disconnected(std::function disconnected) { ensure_disconnected("cannot set the disconnected callback when the connection is not in the disconnected state. "); m_disconnected = disconnected; @@ -833,10 +831,10 @@ namespace signalr void connection_impl::handle_connection_state_change(connection_state old_state, connection_state new_state) { - if (m_logger.is_enabled(trace_level::verbose)) + if (m_logger.is_enabled(log_level::verbose)) { m_logger.log( - trace_level::verbose, + log_level::verbose, translate_connection_state(old_state) .append(" -> ") .append(translate_connection_state(new_state))); diff --git a/src/signalrclient/connection_impl.h b/src/signalrclient/connection_impl.h index 355670f3..0ecbc4f8 100644 --- a/src/signalrclient/connection_impl.h +++ b/src/signalrclient/connection_impl.h @@ -7,7 +7,7 @@ #include #include #include "signalrclient/http_client.h" -#include "signalrclient/trace_level.h" +#include "signalrclient/log_level.h" #include "signalrclient/connection_state.h" #include "signalrclient/signalr_client_config.h" #include "transport_factory.h" @@ -27,8 +27,8 @@ namespace signalr class connection_impl : public std::enable_shared_from_this { public: - static std::shared_ptr create(const std::string& url, trace_level trace_level, const std::shared_ptr& log_writer, - std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation = false); + static std::shared_ptr create(const std::string& url, log_level log_level, const std::shared_ptr& log_writer, + std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation = false); connection_impl(const connection_impl&) = delete; @@ -41,10 +41,10 @@ namespace signalr void stop(std::function callback, std::exception_ptr exception) noexcept; connection_state get_connection_state() const noexcept; - std::string get_connection_id() const noexcept; + const std::string& get_connection_id() const noexcept; - void set_message_received(const std::function& message_received); - void set_disconnected(const std::function& disconnected); + void set_message_received(std::function message_received); + void on_disconnected(std::function disconnected); void set_client_config(const signalr_client_config& config); private: @@ -66,16 +66,17 @@ namespace signalr cancellation_token_source m_start_completed_event; std::string m_connection_id; std::string m_connection_token; - std::function(const signalr_client_config&)> m_http_client_factory; + std::function(const signalr_client_config&)> m_http_client_factory; - connection_impl(const std::string& url, trace_level trace_level, const std::shared_ptr& log_writer, - std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation); + connection_impl(const std::string& url, log_level log_level, const std::shared_ptr& log_writer, + std::function(const signalr_client_config&)> http_client_factory, std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation); void start_transport(const std::string& url, std::function, std::exception_ptr)> callback); void send_connect_request(const std::shared_ptr& transport, const std::string& url, std::function callback); void start_negotiate(const std::string& url, std::function callback); - void start_negotiate_internal(const std::string& url, int redirect_count, std::function transport, std::exception_ptr)> callback); + void start_negotiate_internal(const std::string& url, int redirect_count, + std::function transport, std::exception_ptr)> callback, std::shared_ptr http_client); void process_response(std::string&& response); diff --git a/src/signalrclient/default_http_client.cpp b/src/signalrclient/default_http_client.cpp index 49591ffa..21ccfb78 100644 --- a/src/signalrclient/default_http_client.cpp +++ b/src/signalrclient/default_http_client.cpp @@ -22,11 +22,11 @@ namespace signalr std::function callback, cancellation_token token) { web::http::method method; - if (request.method == http_method::GET) + if (request.get_method() == http_method::GET) { method = U("GET"); } - else if (request.method == http_method::POST) + else if (request.get_method() == http_method::POST) { method = U("POST"); } @@ -38,11 +38,11 @@ namespace signalr web::http::http_request http_request; http_request.set_method(method); - http_request.set_body(request.content); - if (request.headers.size() > 0) + http_request.set_body(request.get_content()); + if (request.get_headers().size() > 0) { web::http::http_headers headers; - for (auto& header : request.headers) + for (auto& header : request.get_headers()) { headers.add(utility::conversions::to_string_t(header.first), utility::conversions::to_string_t(header.second)); } @@ -62,7 +62,7 @@ namespace signalr std::shared_ptr context; pplx::cancellation_token_source cts; - auto milliseconds = std::chrono::milliseconds(request.timeout); + auto milliseconds = std::chrono::milliseconds(request.get_timeout()); if (milliseconds.count() != 0) { context = std::make_shared(); @@ -86,7 +86,7 @@ namespace signalr cts.cancel(); }); - web::http::client::http_client client(utility::conversions::to_string_t(url), m_config.get_http_client_config()); + web::http::client::http_client client(utility::conversions::to_string_t(url)); client.request(http_request, cts.get_token()) .then([context, callback](pplx::task response_task) { @@ -97,9 +97,7 @@ namespace signalr http_response.extract_utf8string() .then([callback, status_code](std::string response_body) { - signalr::http_response response; - response.content = response_body; - response.status_code = status_code; + signalr::http_response response = signalr::http_response(status_code, std::move(response_body)); callback(std::move(response), nullptr); }); } diff --git a/src/signalrclient/default_websocket_client.cpp b/src/signalrclient/default_websocket_client.cpp index 9c24a87e..9ce4f773 100644 --- a/src/signalrclient/default_websocket_client.cpp +++ b/src/signalrclient/default_websocket_client.cpp @@ -14,14 +14,14 @@ namespace signalr { 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_headers = websocket_client_config.headers(); + web::websockets::client::websocket_client_config websocket_config; + auto& websocket_headers = websocket_config.headers(); for (auto& header : signalr_client_config.get_http_headers()) { websocket_headers.add(utility::conversions::to_string_t(header.first), utility::conversions::to_string_t(header.second)); } - return websocket_client_config; + return websocket_config; } } @@ -106,8 +106,8 @@ namespace signalr response.body().read_to_end(b).get(); auto t = b.create_ostream().streambuf().in_avail(); std::string msg(t, ' '); + static_assert(sizeof(char) == sizeof(uint8_t), "char isn't the expected size"); b.create_istream().streambuf().getn(reinterpret_cast(&msg[0]), t); - callback(msg, nullptr); } else diff --git a/src/signalrclient/http_utilities.cpp b/src/signalrclient/http_utilities.cpp new file mode 100644 index 00000000..009a1d43 --- /dev/null +++ b/src/signalrclient/http_utilities.cpp @@ -0,0 +1,64 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +#include "stdafx.h" +#include "signalrclient/http_client.h" + +namespace signalr +{ + http_method http_request::get_method() const + { + return m_method; + } + + const std::map& http_request::get_headers() const + { + return m_headers; + } + + const std::string& http_request::get_content() const + { + return m_content; + } + + std::chrono::seconds http_request::get_timeout() const + { + return m_timeout; + } + + void http_request::set_timeout(std::chrono::seconds timeout) + { + m_timeout = timeout; + } + + void http_request::set_content(const std::string& body) + { + m_content = body; + } + + void http_request::set_content(std::string&& body) + { + m_content = body; + } + + void http_request::set_headers(const std::map& headers) + { + m_headers = headers; + } + + void http_request::set_method(http_method method) + { + m_method = method; + } + + int http_response::get_status_code() const + { + return m_status_code; + } + + const std::string& http_response::get_content() const + { + return m_content; + } +} \ No newline at end of file diff --git a/src/signalrclient/hub_connection.cpp b/src/signalrclient/hub_connection.cpp index d63f6be3..e6bd2bf5 100644 --- a/src/signalrclient/hub_connection.cpp +++ b/src/signalrclient/hub_connection.cpp @@ -12,10 +12,10 @@ namespace signalr { - hub_connection::hub_connection(const std::string& url, std::unique_ptr&& hub_protocol, - trace_level trace_level, std::shared_ptr log_writer, std::function(const signalr_client_config&)> http_client_factory, - std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) - : m_pImpl(hub_connection_impl::create(url, std::move(hub_protocol), trace_level, log_writer, http_client_factory, websocket_factory, skip_negotiation)) + hub_connection::hub_connection(const std::string& url, std::unique_ptr&& hub_protocol, signalr_client_config config, + log_level log_level, std::shared_ptr log_writer, std::function(const signalr_client_config&)> http_client_factory, + std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) + : m_pImpl(hub_connection_impl::create(url, std::move(hub_protocol), config, log_level, log_writer, http_client_factory, websocket_factory, skip_negotiation)) {} hub_connection::hub_connection(hub_connection&& rhs) noexcept @@ -64,7 +64,7 @@ namespace signalr m_pImpl->stop(callback); } - void hub_connection::on(const std::string& event_name, const method_invoked_handler& handler) + void hub_connection::on(const std::string& event_name, std::function&)> handler) { if (!m_pImpl) { @@ -106,7 +106,7 @@ namespace signalr return m_pImpl->get_connection_state(); } - std::string hub_connection::get_connection_id() const + const std::string& hub_connection::get_connection_id() const { if (!m_pImpl) { @@ -116,17 +116,17 @@ namespace signalr return m_pImpl->get_connection_id(); } - void hub_connection::set_disconnected(const std::function& disconnected_callback) + void hub_connection::on_disconnected(std::function disconnected_callback) { if (!m_pImpl) { throw signalr_exception("set_disconnected() cannot be called on destructed hub_connection instance"); } - m_pImpl->set_disconnected(disconnected_callback); + m_pImpl->on_disconnected(disconnected_callback); } - void hub_connection::set_client_config(const signalr_client_config& config) + /*void hub_connection::set_client_config(const signalr_client_config& config) { if (!m_pImpl) { @@ -134,5 +134,5 @@ namespace signalr } m_pImpl->set_client_config(config); - } + }*/ } diff --git a/src/signalrclient/hub_connection_builder.cpp b/src/signalrclient/hub_connection_builder.cpp index 7f7d6e25..c5a76b7e 100644 --- a/src/signalrclient/hub_connection_builder.cpp +++ b/src/signalrclient/hub_connection_builder.cpp @@ -10,18 +10,8 @@ namespace signalr { - hub_connection_builder hub_connection_builder::create(const std::string& url) - { - return hub_connection_builder(url); - } - - hub_connection_builder::hub_connection_builder(const std::string& url) - : m_url(url), m_logger(nullptr), m_log_level(trace_level::info) - { - } - - hub_connection_builder::hub_connection_builder(const hub_connection_builder& rhs) - : m_url(rhs.m_url), m_logger(rhs.m_logger), m_log_level(rhs.m_log_level) + hub_connection_builder::hub_connection_builder(std::string url) + : m_url(std::move(url)), m_logger(nullptr), m_log_level(log_level::info) { } @@ -39,19 +29,16 @@ namespace signalr return *this; } - hub_connection_builder& hub_connection_builder::operator=(const hub_connection_builder& rhs) - { - m_url = rhs.m_url; - m_logger = rhs.m_logger; - m_log_level = rhs.m_log_level; + hub_connection_builder::~hub_connection_builder() + {} + hub_connection_builder& hub_connection_builder::configure_options(signalr_client_config config) noexcept + { + m_config = config; return *this; } - hub_connection_builder::~hub_connection_builder() - {} - - hub_connection_builder& hub_connection_builder::with_logging(std::shared_ptr logger, trace_level log_level) + hub_connection_builder& hub_connection_builder::with_logging(std::shared_ptr logger, log_level log_level) noexcept { m_logger = logger; m_log_level = log_level; @@ -59,21 +46,21 @@ namespace signalr return *this; } - hub_connection_builder& hub_connection_builder::with_websocket_factory(std::function(const signalr_client_config&)> websocket_factory) + hub_connection_builder& hub_connection_builder::with_websocket_factory(std::function(const signalr_client_config&)> websocket_factory) noexcept { m_websocket_factory = websocket_factory; return *this; } - hub_connection_builder& hub_connection_builder::with_http_client_factory(std::function(const signalr_client_config&)> http_client_factory) + hub_connection_builder& hub_connection_builder::with_http_client_factory(std::function(const signalr_client_config&)> http_client_factory) noexcept { m_http_client_factory = http_client_factory; return *this; } - hub_connection_builder& hub_connection_builder::skip_negotiation(const bool skip) + hub_connection_builder& hub_connection_builder::skip_negotiation(const bool skip) noexcept { m_skip_negotiation = skip; @@ -124,6 +111,6 @@ namespace signalr m_built = true; - return std::unique_ptr(new hub_connection(m_url, std::move(hub_protocol), m_log_level, m_logger, m_http_client_factory, m_websocket_factory, m_skip_negotiation)); + return std::unique_ptr(new hub_connection(m_url, std::move(hub_protocol), m_config, m_log_level, m_logger, m_http_client_factory, m_websocket_factory, m_skip_negotiation)); } } \ No newline at end of file diff --git a/src/signalrclient/hub_connection_impl.cpp b/src/signalrclient/hub_connection_impl.cpp index 935eba66..1ac8dcf3 100644 --- a/src/signalrclient/hub_connection_impl.cpp +++ b/src/signalrclient/hub_connection_impl.cpp @@ -19,29 +19,30 @@ namespace signalr namespace { static std::function create_hub_invocation_callback(const logger& logger, - const std::function& set_result, - const std::function& set_exception); + std::function set_result, + std::function set_exception); } - std::shared_ptr hub_connection_impl::create(const std::string& url, std::unique_ptr&& hub_protocol, - trace_level trace_level, const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, - std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) + std::shared_ptr hub_connection_impl::create(const std::string& url, std::unique_ptr&& hub_protocol, signalr_client_config config, + log_level log_level, const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, + std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) { auto connection = std::shared_ptr(new hub_connection_impl(url, std::move(hub_protocol), - trace_level, log_writer, http_client_factory, websocket_factory, skip_negotiation)); + config, log_level, log_writer, http_client_factory, websocket_factory, skip_negotiation)); connection->initialize(); return connection; } - hub_connection_impl::hub_connection_impl(const std::string& url, std::unique_ptr&& hub_protocol, trace_level trace_level, - const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, - std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) - : m_connection(connection_impl::create(url, trace_level, log_writer, http_client_factory, websocket_factory, skip_negotiation)) - , m_logger(log_writer, trace_level), + hub_connection_impl::hub_connection_impl(const std::string& url, std::unique_ptr&& hub_protocol, signalr_client_config config, log_level log_level, + const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, + std::function(const signalr_client_config&)> websocket_factory, const bool skip_negotiation) + : m_connection(connection_impl::create(url, log_level, log_writer, http_client_factory, websocket_factory, skip_negotiation)) + , m_logger(log_writer, log_level), m_callback_manager("connection went out of scope before invocation result was received"), - m_handshakeReceived(false), m_disconnected([](std::exception_ptr) noexcept {}), m_protocol(std::move(hub_protocol)) + m_handshakeReceived(false), m_disconnected([](std::exception_ptr) noexcept {}), m_signalr_client_config(config), + m_protocol(std::move(hub_protocol)) { hub_message ping_msg(signalr::message_type::ping); m_cached_ping = m_protocol->write_message(&ping_msg); @@ -49,6 +50,8 @@ namespace signalr void hub_connection_impl::initialize() { + m_connection->set_client_config(m_signalr_client_config); + // weak_ptr prevents a circular dependency leading to memory leak and other problems std::weak_ptr weak_hub_connection = shared_from_this(); @@ -61,7 +64,7 @@ namespace signalr } }); - m_connection->set_disconnected([weak_hub_connection](std::exception_ptr exception) + m_connection->on_disconnected([weak_hub_connection](std::exception_ptr exception) { auto connection = weak_hub_connection.lock(); if (connection) @@ -74,9 +77,9 @@ namespace signalr } catch (const std::exception& ex) { - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, std::string("disconnect event threw an exception during connection closure: ") + connection->m_logger.log(log_level::warning, std::string("disconnect event threw an exception during connection closure: ") .append(ex.what())); } } @@ -88,7 +91,7 @@ namespace signalr }); } - void hub_connection_impl::on(const std::string& event_name, const std::function&)>& handler) + void hub_connection_impl::on(const std::string& event_name, std::function&)> handler) { if (event_name.length() == 0) { @@ -270,7 +273,7 @@ namespace signalr // don't log if already disconnected and stop called from dtor, it's just noise if (!is_dtor) { - m_logger.log(trace_level::debug, "stop ignored because the connection is already disconnected."); + m_logger.log(log_level::debug, "stop ignored because the connection is already disconnected."); } callback(nullptr); return; @@ -283,7 +286,7 @@ namespace signalr if (m_stop_callbacks.size() > 1) { - m_logger.log(trace_level::info, "Stop is already in progress, waiting for it to finish."); + m_logger.log(log_level::info, "Stop is already in progress, waiting for it to finish."); // we already registered the callback // so we can just return now as the in-progress stop will trigger the callback when it completes return; @@ -332,9 +335,9 @@ namespace signalr if (found != obj.end()) { auto& error = found->second.as_string(); - if (m_logger.is_enabled(trace_level::error)) + if (m_logger.is_enabled(log_level::error)) { - m_logger.log(trace_level::error, std::string("handshake error: ") + m_logger.log(log_level::error, std::string("handshake error: ") .append(error)); } m_handshakeTask->set(std::make_exception_ptr(signalr_exception(std::string("Received an error during handshake: ").append(error)))); @@ -383,7 +386,10 @@ namespace signalr } else { - m_logger.log(trace_level::info, "handler not found"); + if (m_logger.is_enabled(log_level::info)) + { + m_logger.log(log_level::info, std::string("handler not found for '").append(invocation->target).append("'")); + } } break; } @@ -403,9 +409,9 @@ namespace signalr // Sent to server only, should not be received by client throw std::runtime_error("Received unexpected message type 'CancelInvocation'."); case message_type::ping: - if (m_logger.is_enabled(trace_level::debug)) + if (m_logger.is_enabled(log_level::debug)) { - m_logger.log(trace_level::debug, "ping message received."); + m_logger.log(log_level::debug, "ping message received."); } break; case message_type::close: @@ -419,9 +425,9 @@ namespace signalr } catch (const std::exception &e) { - if (m_logger.is_enabled(trace_level::error)) + if (m_logger.is_enabled(log_level::error)) { - m_logger.log(trace_level::error, std::string("error occurred when parsing response: ") + m_logger.log(log_level::error, std::string("error occurred when parsing response: ") .append(e.what()) .append(". response: ") .append(response)); @@ -444,9 +450,9 @@ namespace signalr // worry about object lifetime if (!m_callback_manager.invoke_callback(completion->invocation_id, error, completion->result, true)) { - if (m_logger.is_enabled(trace_level::info)) + if (m_logger.is_enabled(log_level::info)) { - m_logger.log(trace_level::info, std::string("no callback found for id: ").append(completion->invocation_id)); + m_logger.log(log_level::info, std::string("no callback found for id: ").append(completion->invocation_id)); } } @@ -507,9 +513,9 @@ namespace signalr catch (const std::exception& e) { m_callback_manager.remove_callback(callback_id); - if (m_logger.is_enabled(trace_level::warning)) + if (m_logger.is_enabled(log_level::warning)) { - m_logger.log(trace_level::warning, std::string("failed to send invocation: ").append(e.what())); + m_logger.log(log_level::warning, std::string("failed to send invocation: ").append(e.what())); } set_exception(std::current_exception()); } @@ -520,18 +526,18 @@ namespace signalr return m_connection->get_connection_state(); } - std::string hub_connection_impl::get_connection_id() const + const std::string& hub_connection_impl::get_connection_id() const { return m_connection->get_connection_id(); } - void hub_connection_impl::set_client_config(const signalr_client_config& config) + /*void hub_connection_impl::set_client_config(const signalr_client_config& config) { m_signalr_client_config = config; m_connection->set_client_config(config); - } + }*/ - void hub_connection_impl::set_disconnected(const std::function& disconnected) + void hub_connection_impl::on_disconnected(std::function disconnected) { m_disconnected = disconnected; } @@ -550,9 +556,9 @@ namespace signalr void hub_connection_impl::start_keepalive() { - if (m_logger.is_enabled(trace_level::debug)) + if (m_logger.is_enabled(log_level::debug)) { - m_logger.log(trace_level::debug, "starting keep alive timer."); + m_logger.log(log_level::debug, "starting keep alive timer."); } auto send_ping = [](std::shared_ptr connection) @@ -579,9 +585,9 @@ namespace signalr { if (exception) { - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, "failed to send ping!"); + connection->m_logger.log(log_level::warning, "failed to send ping!"); } } else @@ -593,9 +599,9 @@ namespace signalr } catch (const std::exception& e) { - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, std::string("failed to send ping: ").append(e.what())); + connection->m_logger.log(log_level::warning, std::string("failed to send ping: ").append(e.what())); } } }; @@ -629,9 +635,9 @@ namespace signalr auto error_msg = std::string("server timeout (") .append(std::to_string(connection->m_signalr_client_config.get_server_timeout().count())) .append(" ms) elapsed without receiving a message from the server."); - if (connection->m_logger.is_enabled(trace_level::warning)) + if (connection->m_logger.is_enabled(log_level::warning)) { - connection->m_logger.log(trace_level::warning, error_msg); + connection->m_logger.log(log_level::warning, error_msg); } connection->m_connection->stop([](std::exception_ptr) @@ -642,9 +648,9 @@ namespace signalr if (timeNowmSeconds > connection->m_nextActivationSendPing.load()) { - if (connection->m_logger.is_enabled(trace_level::debug)) + if (connection->m_logger.is_enabled(log_level::debug)) { - connection->m_logger.log(trace_level::debug, "sending ping to server."); + connection->m_logger.log(log_level::debug, "sending ping to server."); } send_ping(connection); } @@ -657,8 +663,8 @@ namespace signalr namespace { static std::function create_hub_invocation_callback(const logger& logger, - const std::function& set_result, - const std::function& set_exception) + std::function set_result, + std::function set_exception) { return [logger, set_result, set_exception](const char* error, const signalr::value& message) { diff --git a/src/signalrclient/hub_connection_impl.h b/src/signalrclient/hub_connection_impl.h index 6f4d68c1..cd8bfedf 100644 --- a/src/signalrclient/hub_connection_impl.h +++ b/src/signalrclient/hub_connection_impl.h @@ -26,14 +26,14 @@ namespace signalr class hub_connection_impl : public std::enable_shared_from_this { public: - static std::shared_ptr create(const std::string& url, std::unique_ptr&& hub_protocol, - trace_level trace_level, const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, - std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation = false); + static std::shared_ptr create(const std::string& url, std::unique_ptr&& hub_protocol, signalr_client_config config, + log_level log_level, const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, + std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation = false); hub_connection_impl(const hub_connection_impl&) = delete; hub_connection_impl& operator=(const hub_connection_impl&) = delete; - void on(const std::string& event_name, const std::function&)>& handler); + void on(const std::string& event_name, std::function&)> handler); void invoke(const std::string& method_name, const std::vector& arguments, std::function callback) noexcept; void send(const std::string& method_name, const std::vector& arguments, std::function callback) noexcept; @@ -42,15 +42,15 @@ namespace signalr void stop(std::function callback, bool is_dtor = false) noexcept; connection_state get_connection_state() const noexcept; - std::string get_connection_id() const; + const std::string& get_connection_id() const; - void set_client_config(const signalr_client_config& config); - void set_disconnected(const std::function& disconnected); + //void set_client_config(const signalr_client_config& config); + void on_disconnected(std::function disconnected); private: - hub_connection_impl(const std::string& url, std::unique_ptr&& hub_protocol, trace_level trace_level, - const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, - std::function(const signalr_client_config&)> websocket_factory, + hub_connection_impl(const std::string& url, std::unique_ptr&& hub_protocol, signalr_client_config config, log_level log_level, + const std::shared_ptr& log_writer, std::function(const signalr_client_config&)> http_client_factory, + std::function(const signalr_client_config&)> websocket_factory, bool skip_negotiation); std::shared_ptr m_connection; diff --git a/src/signalrclient/json_helpers.cpp b/src/signalrclient/json_helpers.cpp index ee3cfadd..b49e8fc4 100644 --- a/src/signalrclient/json_helpers.cpp +++ b/src/signalrclient/json_helpers.cpp @@ -113,9 +113,9 @@ namespace signalr { switch (v.type()) { - case signalr::value_type::boolean: + case signalr::value::type::boolean: return Json::Value(v.as_bool()); - case signalr::value_type::float64: + case signalr::value::type::float64: { auto value = v.as_double(); double intPart; @@ -152,9 +152,9 @@ namespace signalr } return Json::Value(v.as_double()); } - case signalr::value_type::string: + case signalr::value::type::string: return Json::Value(v.as_string()); - case signalr::value_type::array: + case signalr::value::type::array: { const auto& array = v.as_array(); Json::Value vec(Json::ValueType::arrayValue); @@ -164,7 +164,7 @@ namespace signalr } return vec; } - case signalr::value_type::map: + case signalr::value::type::map: { const auto& obj = v.as_map(); Json::Value object(Json::ValueType::objectValue); @@ -174,12 +174,12 @@ namespace signalr } return object; } - case signalr::value_type::binary: + case signalr::value::type::binary: { const auto& binary = v.as_binary(); return Json::Value(base64Encode(binary)); } - case signalr::value_type::null: + case signalr::value::type::null: default: return Json::Value(Json::ValueType::nullValue); } diff --git a/src/signalrclient/logger.cpp b/src/signalrclient/logger.cpp index e8a84420..6f46a315 100644 --- a/src/signalrclient/logger.cpp +++ b/src/signalrclient/logger.cpp @@ -18,18 +18,18 @@ namespace signalr #define GMTIME(r_tm, r_time_t) gmtime_r(r_time_t, r_tm) #endif - logger::logger(const std::shared_ptr& log_writer, trace_level trace_level) noexcept - : m_log_writer(log_writer), m_trace_level(trace_level) + logger::logger(const std::shared_ptr& log_writer, log_level log_level) noexcept + : m_log_writer(log_writer), m_log_level(log_level) { } - void logger::log(trace_level level, const std::string& entry) const + void logger::log(log_level level, const std::string& entry) const { log(level, entry.data(), entry.length()); } - void logger::log(trace_level level, const char* entry, size_t entry_count) const + void logger::log(log_level level, const char* entry, size_t entry_count) const { - if (level >= m_trace_level && m_log_writer) + if (level >= m_log_level && m_log_writer) { try { @@ -55,7 +55,7 @@ namespace signalr std::stringstream os; os << timeString; - write_trace_level(level, os); + write_log_level(level, os); os.write(entry, (std::streamsize)entry_count) << std::endl; m_log_writer->write(os.str()); @@ -72,29 +72,29 @@ namespace signalr } } - void logger::write_trace_level(trace_level trace_level, std::ostream& stream) + void logger::write_log_level(log_level log_level, std::ostream& stream) { - switch (trace_level) + switch (log_level) { - case signalr::trace_level::verbose: + case signalr::log_level::verbose: stream << " [verbose ] "; break; - case signalr::trace_level::debug: + case signalr::log_level::debug: stream << " [debug ] "; break; - case signalr::trace_level::info: + case signalr::log_level::info: stream << " [info ] "; break; - case signalr::trace_level::warning: + case signalr::log_level::warning: stream << " [warning ] "; break; - case signalr::trace_level::error: + case signalr::log_level::error: stream << " [error ] "; break; - case signalr::trace_level::critical: + case signalr::log_level::critical: stream << " [critical ] "; break; - case signalr::trace_level::none: + case signalr::log_level::none: stream << " [none ] "; break; default: diff --git a/src/signalrclient/logger.h b/src/signalrclient/logger.h index 2ffb2bc0..0ea31363 100644 --- a/src/signalrclient/logger.h +++ b/src/signalrclient/logger.h @@ -5,7 +5,7 @@ #pragma once #include -#include "signalrclient/trace_level.h" +#include "signalrclient/log_level.h" #include "signalrclient/log_writer.h" namespace signalr @@ -13,29 +13,29 @@ namespace signalr class logger { public: - logger(const std::shared_ptr& log_writer, trace_level trace_level) noexcept; + logger(const std::shared_ptr& log_writer, log_level log_level) noexcept; - void log(trace_level level, const char* entry, size_t entry_count) const; + void log(log_level level, const char* entry, size_t entry_count) const; // TODO: variadic 'const char*' overload to avoid std::string allocations - void log(trace_level level, const std::string& entry) const; + void log(log_level level, const std::string& entry) const; template - void log(trace_level level, const char (&entry)[N]) const + void log(log_level level, const char (&entry)[N]) const { // remove '\0' log(level, entry, N - 1); } - bool is_enabled(trace_level level) const + bool is_enabled(log_level level) const { - return level >= m_trace_level; + return level >= m_log_level; } private: std::shared_ptr m_log_writer; - trace_level m_trace_level; + log_level m_log_level; - static void write_trace_level(trace_level trace_level, std::ostream& stream); + static void write_log_level(log_level log_level, std::ostream& stream); }; } diff --git a/src/signalrclient/messagepack_hub_protocol.cpp b/src/signalrclient/messagepack_hub_protocol.cpp index 3f5e25a3..471c7ee2 100644 --- a/src/signalrclient/messagepack_hub_protocol.cpp +++ b/src/signalrclient/messagepack_hub_protocol.cpp @@ -79,7 +79,7 @@ namespace signalr { switch (v.type()) { - case signalr::value_type::boolean: + case signalr::value::type::boolean: { if (v.as_bool()) { @@ -91,7 +91,7 @@ namespace signalr } return; } - case signalr::value_type::float64: + case signalr::value::type::float64: { auto value = v.as_double(); double intPart; @@ -133,14 +133,14 @@ namespace signalr packer.pack_double(v.as_double()); return; } - case signalr::value_type::string: + case signalr::value::type::string: { auto length = v.as_string().length(); packer.pack_str(static_cast(length)); packer.pack_str_body(v.as_string().data(), static_cast(length)); return; } - case signalr::value_type::array: + case signalr::value::type::array: { const auto& array = v.as_array(); packer.pack_array(static_cast(array.size())); @@ -150,7 +150,7 @@ namespace signalr } return; } - case signalr::value_type::map: + case signalr::value::type::map: { const auto& obj = v.as_map(); packer.pack_map(static_cast(obj.size())); @@ -162,14 +162,14 @@ namespace signalr } return; } - case signalr::value_type::binary: + case signalr::value::type::binary: { const auto& bin = v.as_binary(); packer.pack_bin(static_cast(bin.size())); packer.pack_bin_body(reinterpret_cast(bin.data()), static_cast(bin.size())); return; } - case signalr::value_type::null: + case signalr::value::type::null: default: { packer.pack_nil(); diff --git a/src/signalrclient/negotiate.cpp b/src/signalrclient/negotiate.cpp index 1f3dffc0..8015c116 100644 --- a/src/signalrclient/negotiate.cpp +++ b/src/signalrclient/negotiate.cpp @@ -11,136 +11,131 @@ namespace signalr { - namespace negotiate + void negotiate::send_negotiate(http_client* client, const std::string& base_url, + const signalr_client_config& config, + std::function callback, cancellation_token token) noexcept { - const int negotiate_version = 1; + std::string negotiate_url; + try + { + negotiate_url = url_builder::build_negotiate(base_url); + negotiate_url = url_builder::add_query_string(negotiate_url, "negotiateVersion=" + std::to_string(negotiate::negotiate_version)); + } + catch (...) + { + callback({}, std::current_exception()); + return; + } - void negotiate(std::shared_ptr client, const std::string& base_url, - const signalr_client_config& config, - std::function callback, cancellation_token token) noexcept + // TODO: signalr_client_config + http_request request; + request.set_method(http_method::POST); + request.set_headers(config.get_http_headers()); + // TODO: timeout? + // request.timeout = ; + + client->send(negotiate_url, request, [callback, token](const http_response& http_response, std::exception_ptr exception) { - std::string negotiate_url; - try + if (exception != nullptr) { - negotiate_url = url_builder::build_negotiate(base_url); - negotiate_url = url_builder::add_query_string(negotiate_url, "negotiateVersion=" + std::to_string(negotiate_version)); + callback({}, exception); + return; } - catch (...) + + if (token.is_canceled()) { - callback({}, std::current_exception()); + callback({}, std::make_exception_ptr(canceled_exception())); return; } - // TODO: signalr_client_config - http_request request; - request.method = http_method::POST; - request.headers = config.get_http_headers(); -#ifdef USE_CPPRESTSDK - request.timeout = config.get_http_client_config().timeout(); -#endif + if (http_response.get_status_code() != 200) + { + callback({}, std::make_exception_ptr( + signalr_exception("negotiate failed with status code " + std::to_string(http_response.get_status_code())))); + return; + } - client->send(negotiate_url, request, [callback, token](const http_response& http_response, std::exception_ptr exception) + try { - if (exception != nullptr) + Json::Value negotiation_response_json; + auto reader = getJsonReader(); + std::string errors; + + auto& content = http_response.get_content(); + if (!reader->parse(content.c_str(), content.c_str() + content.size(), &negotiation_response_json, &errors)) { - callback({}, exception); - return; + throw signalr_exception(errors); } - if (token.is_canceled()) + negotiation_response response; + + if (negotiation_response_json.isMember("error")) { - callback({}, std::make_exception_ptr(canceled_exception())); + response.error = negotiation_response_json["error"].asString(); + callback(std::move(response), nullptr); return; } - if (http_response.status_code != 200) + int server_negotiate_version = 0; + if (negotiation_response_json.isMember("negotiateVersion")) { - callback({}, std::make_exception_ptr( - signalr_exception("negotiate failed with status code " + std::to_string(http_response.status_code)))); - return; + server_negotiate_version = negotiation_response_json["negotiateVersion"].asInt(); } - try + if (negotiation_response_json.isMember("connectionId")) { - Json::Value negotiation_response_json; - auto reader = getJsonReader(); - std::string errors; - - if (!reader->parse(http_response.content.c_str(), http_response.content.c_str() + http_response.content.size(), &negotiation_response_json, &errors)) - { - throw signalr_exception(errors); - } - - negotiation_response response; - - if (negotiation_response_json.isMember("error")) - { - response.error = negotiation_response_json["error"].asString(); - callback(std::move(response), nullptr); - return; - } - - int server_negotiate_version = 0; - if (negotiation_response_json.isMember("negotiateVersion")) - { - server_negotiate_version = negotiation_response_json["negotiateVersion"].asInt(); - } + response.connectionId = negotiation_response_json["connectionId"].asString(); + } - if (negotiation_response_json.isMember("connectionId")) - { - response.connectionId = negotiation_response_json["connectionId"].asString(); - } + if (negotiation_response_json.isMember("connectionToken")) + { + response.connectionToken = negotiation_response_json["connectionToken"].asString(); + } - if (negotiation_response_json.isMember("connectionToken")) - { - response.connectionToken = negotiation_response_json["connectionToken"].asString(); - } + if (server_negotiate_version <= 0) + { + response.connectionToken = response.connectionId; + } - if (server_negotiate_version <= 0) + if (negotiation_response_json.isMember("availableTransports")) + { + for (const auto& transportData : negotiation_response_json["availableTransports"]) { - response.connectionToken = response.connectionId; - } + available_transport transport; + transport.transport = transportData["transport"].asString(); - if (negotiation_response_json.isMember("availableTransports")) - { - for (const auto& transportData : negotiation_response_json["availableTransports"]) + for (const auto& format : transportData["transferFormats"]) { - available_transport transport; - transport.transport = transportData["transport"].asString(); - - for (const auto& format : transportData["transferFormats"]) - { - transport.transfer_formats.push_back(format.asString()); - } - - response.availableTransports.push_back(transport); + transport.transfer_formats.push_back(format.asString()); } - } - - if (negotiation_response_json.isMember("url")) - { - response.url = negotiation_response_json["url"].asString(); - if (negotiation_response_json.isMember("accessToken")) - { - response.accessToken = negotiation_response_json["accessToken"].asString(); - } + response.availableTransports.push_back(transport); } + } + + if (negotiation_response_json.isMember("url")) + { + response.url = negotiation_response_json["url"].asString(); - if (negotiation_response_json.isMember("ProtocolVersion")) + if (negotiation_response_json.isMember("accessToken")) { - callback({}, std::make_exception_ptr( - signalr_exception("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."))); - return; + response.accessToken = negotiation_response_json["accessToken"].asString(); } - - callback(std::move(response), nullptr); } - catch (...) + + if (negotiation_response_json.isMember("ProtocolVersion")) { - callback({}, std::current_exception()); + callback({}, std::make_exception_ptr( + signalr_exception("Detected a connection attempt to an ASP.NET SignalR Server. This client only supports connecting to an ASP.NET Core SignalR Server. See https://aka.ms/signalr-core-differences for details."))); + return; } - }, token); - } + + callback(std::move(response), nullptr); + } + catch (...) + { + callback({}, std::current_exception()); + } + }, token); } } diff --git a/src/signalrclient/negotiate.h b/src/signalrclient/negotiate.h index 00738399..f537f626 100644 --- a/src/signalrclient/negotiate.h +++ b/src/signalrclient/negotiate.h @@ -10,10 +10,13 @@ namespace signalr { - namespace negotiate + class negotiate { - void negotiate(std::shared_ptr client, const std::string& base_url, + public: + static void send_negotiate(http_client* client, const std::string& base_url, const signalr_client_config& signalr_client_config, std::function callback, cancellation_token token) noexcept; - } + private: + static const int negotiate_version = 1; + }; } diff --git a/src/signalrclient/signalr_client_config.cpp b/src/signalrclient/signalr_client_config.cpp index adbc3aec..2b80a010 100644 --- a/src/signalrclient/signalr_client_config.cpp +++ b/src/signalrclient/signalr_client_config.cpp @@ -8,46 +8,12 @@ namespace signalr { -#ifdef USE_CPPRESTSDK - void signalr_client_config::set_proxy(const web::web_proxy &proxy) - { - m_http_client_config.set_proxy(proxy); - m_websocket_client_config.set_proxy(proxy); - } - - void signalr_client_config::set_credentials(const web::credentials &credentials) - { - m_http_client_config.set_credentials(credentials); - m_websocket_client_config.set_credentials(credentials); - } - - web::http::client::http_client_config signalr_client_config::get_http_client_config() const - { - return m_http_client_config; - } - - void signalr_client_config::set_http_client_config(const web::http::client::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 noexcept - { - return m_websocket_client_config; - } - - void signalr_client_config::set_websocket_client_config(const web::websockets::client::websocket_client_config& websocket_client_config) - { - m_websocket_client_config = websocket_client_config; - } -#endif - signalr_client_config::signalr_client_config() - : m_handshake_timeout(std::chrono::seconds(15)) + : m_scheduler(std::make_shared()) + , m_handshake_timeout(std::chrono::seconds(15)) , m_server_timeout(std::chrono::seconds(30)) , m_keepalive_interval(std::chrono::seconds(15)) { - m_scheduler = std::make_shared(); } const std::map& signalr_client_config::get_http_headers() const noexcept @@ -55,17 +21,12 @@ namespace signalr return m_http_headers; } - std::map& signalr_client_config::get_http_headers() noexcept - { - return m_http_headers; - } - - void signalr_client_config::set_http_headers(const std::map& http_headers) + void signalr_client_config::set_http_headers(std::map http_headers) noexcept { - m_http_headers = http_headers; + m_http_headers = std::move(http_headers); } - void signalr_client_config::set_scheduler(std::shared_ptr scheduler) + void signalr_client_config::set_scheduler(std::shared_ptr scheduler) noexcept { if (!scheduler) { @@ -75,7 +36,7 @@ namespace signalr m_scheduler = std::move(scheduler); } - const std::shared_ptr& signalr_client_config::get_scheduler() const noexcept + std::shared_ptr signalr_client_config::get_scheduler() const noexcept { return m_scheduler; } diff --git a/src/signalrclient/signalr_default_scheduler.cpp b/src/signalrclient/signalr_default_scheduler.cpp index 26c4d97e..65465bf0 100644 --- a/src/signalrclient/signalr_default_scheduler.cpp +++ b/src/signalrclient/signalr_default_scheduler.cpp @@ -19,7 +19,7 @@ namespace signalr while (true) { { - signalr_base_cb cb; + std::function cb; { std::unique_lock lock(internals->m_callback_lock); auto& callback = internals->m_callback; @@ -69,7 +69,7 @@ namespace signalr }); } - void thread::add(signalr_base_cb cb) + void thread::add(std::function cb) { { assert(m_internals->m_closed == false); @@ -106,11 +106,17 @@ namespace signalr shutdown(); } - void signalr_default_scheduler::schedule(const signalr_base_cb& cb, std::chrono::milliseconds delay) + void signalr_default_scheduler::schedule(std::function cb, std::chrono::milliseconds delay) { { std::lock_guard lock(m_internals->m_callback_lock); assert(m_internals->m_closed == false); + if (!m_started) + { + // start threads on first scheduled work item, otherwise we might be creating the threads and then throwing them away immediately + // if the scheduler is replaced or if the config isn't used. + run(); + } m_internals->m_callbacks.push_back(std::make_pair(cb, std::chrono::steady_clock::now() + delay)); } // unlock @@ -123,6 +129,12 @@ namespace signalr void signalr_default_scheduler::run() { + if (m_started) + { + return; + } + + m_started = true; auto internals = m_internals; std::thread([=]() diff --git a/src/signalrclient/signalr_default_scheduler.h b/src/signalrclient/signalr_default_scheduler.h index d3dfd264..7fc5ea2b 100644 --- a/src/signalrclient/signalr_default_scheduler.h +++ b/src/signalrclient/signalr_default_scheduler.h @@ -19,7 +19,7 @@ namespace signalr thread(const thread&) = delete; thread& operator=(const thread&) = delete; - void add(signalr_base_cb); + void add(std::function); void start(); bool is_free() const; void shutdown(); @@ -29,7 +29,7 @@ namespace signalr #pragma warning( disable: 4625 5026 4626 5027 ) struct internals { - signalr_base_cb m_callback; + std::function m_callback; std::mutex m_callback_lock; std::condition_variable m_callback_cv; bool m_closed; @@ -43,24 +43,25 @@ namespace signalr struct signalr_default_scheduler : scheduler { - signalr_default_scheduler() : m_internals(std::make_shared()) - { - run(); - } + signalr_default_scheduler() : m_started(false), m_internals(std::make_shared()) + { } + signalr_default_scheduler(const signalr_default_scheduler&) = delete; signalr_default_scheduler& operator=(const signalr_default_scheduler&) = delete; - void schedule(const signalr_base_cb& cb, std::chrono::milliseconds delay = std::chrono::milliseconds::zero()); + void schedule(std::function cb, std::chrono::milliseconds delay = std::chrono::milliseconds::zero()); ~signalr_default_scheduler(); private: void run(); + bool m_started; + #pragma warning( push ) #pragma warning( disable: 4625 5026 4626 5027 ) struct internals { - std::vector>> m_callbacks; + std::vector, std::chrono::time_point>> m_callbacks; std::mutex m_callback_lock; std::condition_variable m_callback_cv; bool m_closed; diff --git a/src/signalrclient/signalr_value.cpp b/src/signalrclient/signalr_value.cpp index a6c0c99f..477542a0 100644 --- a/src/signalrclient/signalr_value.cpp +++ b/src/signalrclient/signalr_value.cpp @@ -9,117 +9,117 @@ namespace signalr { - std::string value_type_to_string(value_type v) + std::string value_type_to_string(enum value::type v) { switch (v) { - case signalr::value_type::map: + case signalr::value::type::map: return "map"; - case signalr::value_type::array: + case signalr::value::type::array: return "array"; - case signalr::value_type::string: + case signalr::value::type::string: return "string"; - case signalr::value_type::float64: + case signalr::value::type::float64: return "float64"; - case signalr::value_type::null: + case signalr::value::type::null: return "null"; - case signalr::value_type::boolean: + case signalr::value::type::boolean: return "boolean"; - case signalr::value_type::binary: + case signalr::value::type::binary: return "binary"; default: return std::to_string((int)v); } } - value::value() : mType(value_type::null) {} + value::value() : mType(value::type::null) {} - value::value(std::nullptr_t) : mType(value_type::null) {} + value::value(std::nullptr_t) : mType(value::type::null) {} - value::value(value_type t) : mType(t) + value::value(enum value::type t) : mType(t) { switch (mType) { - case value_type::array: + case type::array: new (&mStorage.array) std::vector(); break; - case value_type::string: + case type::string: new (&mStorage.string) std::string(); break; - case value_type::float64: + case type::float64: mStorage.number = 0; break; - case value_type::boolean: + case type::boolean: mStorage.boolean = false; break; - case value_type::map: + case type::map: new (&mStorage.map) std::map(); break; - case value_type::binary: + case type::binary: new (&mStorage.binary) std::vector(); break; - case value_type::null: + case type::null: default: break; } } - value::value(bool val) : mType(value_type::boolean) + value::value(bool val) : mType(type::boolean) { mStorage.boolean = val; } - value::value(double val) : mType(value_type::float64) + value::value(double val) : mType(type::float64) { mStorage.number = val; } - value::value(const std::string& val) : mType(value_type::string) + value::value(const std::string& val) : mType(type::string) { new (&mStorage.string) std::string(val); } - value::value(std::string&& val) : mType(value_type::string) + value::value(std::string&& val) : mType(type::string) { new (&mStorage.string) std::string(std::move(val)); } - value::value(const char* val) : mType(value_type::string) + value::value(const char* val) : mType(type::string) { new (&mStorage.string) std::string(val); } - value::value(const char* val, size_t length) : mType(value_type::string) + value::value(const char* val, size_t length) : mType(type::string) { new (&mStorage.string) std::string(val, length); } - value::value(const std::vector& val) : mType(value_type::array) + value::value(const std::vector& val) : mType(type::array) { new (&mStorage.array) std::vector(val); } - value::value(std::vector&& val) : mType(value_type::array) + value::value(std::vector&& val) : mType(type::array) { new (&mStorage.array) std::vector(std::move(val)); } - value::value(const std::map& map) : mType(value_type::map) + value::value(const std::map& map) : mType(type::map) { new (&mStorage.map) std::map(map); } - value::value(std::map&& map) : mType(value_type::map) + value::value(std::map&& map) : mType(type::map) { new (&mStorage.map) std::map(std::move(map)); } - value::value(const std::vector& bin) : mType(value_type::binary) + value::value(const std::vector& bin) : mType(type::binary) { new (&mStorage.binary) std::vector(bin); } - value::value(std::vector&& bin) : mType(value_type::binary) + value::value(std::vector&& bin) : mType(type::binary) { new (&mStorage.binary) std::vector(std::move(bin)); } @@ -129,25 +129,25 @@ namespace signalr mType = rhs.mType; switch (mType) { - case value_type::array: + case type::array: new (&mStorage.array) std::vector(rhs.mStorage.array); break; - case value_type::string: + case type::string: new (&mStorage.string) std::string(rhs.mStorage.string); break; - case value_type::float64: + case type::float64: mStorage.number = rhs.mStorage.number; break; - case value_type::boolean: + case type::boolean: mStorage.boolean = rhs.mStorage.boolean; break; - case value_type::map: + case type::map: new (&mStorage.map) std::map(rhs.mStorage.map); break; - case value_type::binary: + case type::binary: new (&mStorage.binary) std::vector(rhs.mStorage.binary); break; - case value_type::null: + case type::null: default: break; } @@ -158,25 +158,25 @@ namespace signalr mType = std::move(rhs.mType); switch (mType) { - case value_type::array: + case type::array: new (&mStorage.array) std::vector(std::move(rhs.mStorage.array)); break; - case value_type::string: + case type::string: new (&mStorage.string) std::string(std::move(rhs.mStorage.string)); break; - case value_type::float64: + case type::float64: mStorage.number = std::move(rhs.mStorage.number); break; - case value_type::boolean: + case type::boolean: mStorage.boolean = std::move(rhs.mStorage.boolean); break; - case value_type::map: + case type::map: new (&mStorage.map) std::map(std::move(rhs.mStorage.map)); break; - case value_type::binary: + case type::binary: new (&mStorage.binary) std::vector(std::move(rhs.mStorage.binary)); break; - case value_type::null: + case type::null: default: break; } @@ -191,21 +191,21 @@ namespace signalr { switch (mType) { - case value_type::array: + case type::array: mStorage.array.~vector(); break; - case value_type::string: + case type::string: mStorage.string.~basic_string(); break; - case value_type::map: + case type::map: mStorage.map.~map(); break; - case value_type::binary: + case type::binary: mStorage.binary.~vector(); break; - case value_type::null: - case value_type::float64: - case value_type::boolean: + case type::null: + case type::float64: + case type::boolean: default: break; } @@ -218,25 +218,25 @@ namespace signalr mType = rhs.mType; switch (mType) { - case value_type::array: + case type::array: new (&mStorage.array) std::vector(rhs.mStorage.array); break; - case value_type::string: + case type::string: new (&mStorage.string) std::string(rhs.mStorage.string); break; - case value_type::float64: + case type::float64: mStorage.number = rhs.mStorage.number; break; - case value_type::boolean: + case type::boolean: mStorage.boolean = rhs.mStorage.boolean; break; - case value_type::map: + case type::map: new (&mStorage.map) std::map(rhs.mStorage.map); break; - case value_type::binary: + case type::binary: new (&mStorage.binary) std::vector(rhs.mStorage.binary); break; - case value_type::null: + case type::null: default: break; } @@ -251,25 +251,25 @@ namespace signalr mType = std::move(rhs.mType); switch (mType) { - case value_type::array: + case type::array: new (&mStorage.array) std::vector(std::move(rhs.mStorage.array)); break; - case value_type::string: + case type::string: new (&mStorage.string) std::string(std::move(rhs.mStorage.string)); break; - case value_type::float64: + case type::float64: mStorage.number = std::move(rhs.mStorage.number); break; - case value_type::boolean: + case type::boolean: mStorage.boolean = std::move(rhs.mStorage.boolean); break; - case value_type::map: + case type::map: new (&mStorage.map) std::map(std::move(rhs.mStorage.map)); break; - case value_type::binary: + case type::binary: new (&mStorage.binary) std::vector(std::move(rhs.mStorage.binary)); break; - case value_type::null: + case type::null: default: break; } @@ -279,37 +279,37 @@ namespace signalr bool value::is_map() const { - return mType == signalr::value_type::map; + return mType == signalr::value::type::map; } bool value::is_double() const { - return mType == signalr::value_type::float64; + return mType == signalr::value::type::float64; } bool value::is_string() const { - return mType == signalr::value_type::string; + return mType == signalr::value::type::string; } bool value::is_null() const { - return mType == signalr::value_type::null; + return mType == signalr::value::type::null; } bool value::is_array() const { - return mType == signalr::value_type::array; + return mType == signalr::value::type::array; } bool value::is_bool() const { - return mType == signalr::value_type::boolean; + return mType == signalr::value::type::boolean; } bool value::is_binary() const { - return mType == signalr::value_type::binary; + return mType == signalr::value::type::binary; } double value::as_double() const @@ -372,7 +372,7 @@ namespace signalr return mStorage.binary; } - value_type value::type() const + enum value::type value::type() const { return mType; } diff --git a/src/signalrclient/websocket_transport.cpp b/src/signalrclient/websocket_transport.cpp index 9231671c..33123a89 100644 --- a/src/signalrclient/websocket_transport.cpp +++ b/src/signalrclient/websocket_transport.cpp @@ -15,14 +15,14 @@ namespace signalr { - std::shared_ptr websocket_transport::create(const std::function(const signalr_client_config&)>& websocket_client_factory, + std::shared_ptr websocket_transport::create(std::function(const signalr_client_config&)> websocket_client_factory, const signalr_client_config& signalr_client_config, const logger& logger) { return std::shared_ptr( new websocket_transport(websocket_client_factory, signalr_client_config, logger)); } - websocket_transport::websocket_transport(const std::function(const signalr_client_config&)>& websocket_client_factory, + websocket_transport::websocket_transport(std::function(const signalr_client_config&)> websocket_client_factory, const signalr_client_config& signalr_client_config, const logger& logger) : transport(logger), m_websocket_client_factory(websocket_client_factory), m_process_response_callback([](std::string, std::exception_ptr) {}), m_close_callback([](std::exception_ptr) {}), m_signalr_client_config(signalr_client_config), @@ -101,14 +101,14 @@ namespace signalr catch (const std::exception & e) { logger.log( - trace_level::error, + log_level::error, std::string("[websocket transport] error receiving response from websocket: ") .append(e.what())); } catch (...) { logger.log( - trace_level::error, + log_level::error, "[websocket transport] unknown error occurred when receiving response from websocket"); exception = std::make_exception_ptr(signalr_exception("unknown error")); @@ -135,7 +135,7 @@ namespace signalr { // this should not be hit // we wait for the receive loop to complete before completing stop (which will then destruct the transport and client) - logger.log(trace_level::critical, + logger.log(log_level::critical, "[websocket transport] websocket client has been destructed before the receive loop completes, this is a bug"); assert(client != nullptr); } @@ -209,7 +209,7 @@ namespace signalr return; } - m_logger.log(trace_level::info, + m_logger.log(log_level::info, std::string("[websocket transport] connecting to: ") .append(url)); @@ -252,7 +252,7 @@ namespace signalr catch (const std::exception & e) { transport->m_logger.log( - trace_level::error, + log_level::error, std::string("[websocket transport] exception when connecting to the server: ") .append(e.what())); @@ -285,7 +285,7 @@ namespace signalr auto close_callback = m_close_callback; auto receive_loop_task = m_receive_loop_task; - m_logger.log(trace_level::debug, "stopping websocket transport"); + m_logger.log(log_level::debug, "stopping websocket transport"); websocket_client->stop([logger, callback, close_callback, receive_loop_task](std::exception_ptr exception) { @@ -297,14 +297,14 @@ namespace signalr { std::rethrow_exception(exception); } - logger.log(trace_level::debug, "websocket transport stopped"); + logger.log(log_level::debug, "websocket transport stopped"); } catch (const std::exception& e) { - if (logger.is_enabled(trace_level::error)) + if (logger.is_enabled(log_level::error)) { logger.log( - trace_level::error, + log_level::error, std::string("websocket transport stopped with error: ") .append(e.what())); } diff --git a/src/signalrclient/websocket_transport.h b/src/signalrclient/websocket_transport.h index c1947ad0..fe8e6be9 100644 --- a/src/signalrclient/websocket_transport.h +++ b/src/signalrclient/websocket_transport.h @@ -14,7 +14,7 @@ namespace signalr class websocket_transport : public transport, public std::enable_shared_from_this { public: - static std::shared_ptr create(const std::function(const signalr_client_config&)>& websocket_client_factory, + static std::shared_ptr create(std::function(const signalr_client_config&)> websocket_client_factory, const signalr_client_config& signalr_client_config, const logger& logger); ~websocket_transport(); @@ -34,7 +34,7 @@ namespace signalr void on_receive(std::function) override; private: - websocket_transport(const std::function(const signalr_client_config&)>& websocket_client_factory, + websocket_transport(std::function(const signalr_client_config&)> websocket_client_factory, const signalr_client_config& signalr_client_config, const logger& logger); std::function(const signalr_client_config&)> m_websocket_client_factory; diff --git a/test/signalrclienttests/CMakeLists.txt b/test/signalrclienttests/CMakeLists.txt index ecb5e0b8..e7b79951 100644 --- a/test/signalrclienttests/CMakeLists.txt +++ b/test/signalrclienttests/CMakeLists.txt @@ -42,6 +42,7 @@ list (APPEND SOURCES ../../src/signalrclient/default_http_client.cpp ../../src/signalrclient/default_websocket_client.cpp ../../src/signalrclient/handshake_protocol.cpp + ../../src/signalrclient/http_utilities.cpp ../../src/signalrclient/hub_connection.cpp ../../src/signalrclient/hub_connection_builder.cpp ../../src/signalrclient/hub_connection_impl.cpp diff --git a/test/signalrclienttests/connection_tests.cpp b/test/signalrclienttests/connection_tests.cpp index 0aced444..47e165a6 100644 --- a/test/signalrclienttests/connection_tests.cpp +++ b/test/signalrclienttests/connection_tests.cpp @@ -6,7 +6,7 @@ #include "test_utils.h" #include "test_websocket_client.h" #include "connection_impl.h" -#include "signalrclient/trace_level.h" +#include "signalrclient/log_level.h" #include "memory_log_writer.h" #include "signalr_default_scheduler.h" #include "signalrclient/signalr_exception.h" @@ -15,14 +15,18 @@ using namespace signalr; -static std::shared_ptr create_connection(std::shared_ptr websocket_client = create_test_websocket_client(), - std::shared_ptr log_writer = std::make_shared(), trace_level trace_level = trace_level::verbose) +static std::shared_ptr create_connection(test_websocket_client* websocket_client = nullptr, + std::shared_ptr log_writer = std::make_shared(), log_level log_level = log_level::verbose) { - return connection_impl::create(create_uri(), trace_level, log_writer, create_test_http_client(), - [websocket_client](const signalr_client_config& config) + return connection_impl::create(create_uri(), log_level, log_writer, create_test_http_client(), + [websocket_client](const signalr_client_config& config) mutable { + if (websocket_client == nullptr) + { + websocket_client = create_test_websocket_client(); + } websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); } @@ -73,7 +77,7 @@ TEST(connection_impl_start, connection_state_is_connecting_when_connection_is_be callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -109,16 +113,16 @@ TEST(connection_impl_start, connection_state_is_connected_when_connection_establ TEST(connection_impl_start, connection_state_is_disconnected_when_connection_cannot_be_established) { - auto http_client = std::shared_ptr(new test_http_client([](const std::string&, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string&, http_request, cancellation_token) { return http_response{ 404, "" }; - })); + }); auto connection = - connection_impl::create(create_uri(), trace_level::none, std::make_shared(), + connection_impl::create(create_uri(), log_level::none, std::make_shared(), [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, nullptr); auto mre = manual_reset_event(); @@ -141,10 +145,12 @@ TEST(connection_impl_start, throws_for_invalid_uri) { std::shared_ptr writer(std::make_shared()); - auto websocket_client = create_test_websocket_client(); - - auto connection = connection_impl::create(":1\t ä bad_uri&a=b", trace_level::error, writer, create_test_http_client(), - [websocket_client](const signalr_client_config&) { return websocket_client; }); + auto connection = connection_impl::create(":1\t ä bad_uri&a=b", log_level::error, writer, create_test_http_client(), + [](const signalr_client_config&) + { + auto websocket_client = create_test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -178,11 +184,11 @@ TEST(connection_impl_start, start_sets_id_query_string) callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto connection = connection_impl::create(create_uri(""), trace_level::error, writer, create_test_http_client(), + auto connection = connection_impl::create(create_uri(""), log_level::error, writer, create_test_http_client(), [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -217,11 +223,11 @@ TEST(connection_impl_start, start_appends_id_query_string) callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto connection = connection_impl::create(create_uri("a=b&c=d"), trace_level::error, + auto connection = connection_impl::create(create_uri("a=b&c=d"), log_level::error, writer, create_test_http_client(), [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -247,16 +253,16 @@ TEST(connection_impl_start, start_logs_exceptions) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string&, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string&, http_request, cancellation_token) { return http_response{ 404, "" }; - })); + }); auto connection = - connection_impl::create(create_uri(), trace_level::error, writer, + connection_impl::create(create_uri(), log_level::error, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, nullptr); auto mre = manual_reset_event(); @@ -280,19 +286,21 @@ TEST(connection_impl_start, start_logs_exceptions) TEST(connection_impl_start, start_propagates_exceptions_from_negotiate) { - auto http_client = std::shared_ptr(new test_http_client([](const std::string&, http_request, cancellation_token) -> http_response + auto http_client = new test_http_client([](const std::string&, http_request, cancellation_token) -> http_response { throw custom_exception(); - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::none, + connection_impl::create(create_uri(), log_level::none, std::make_shared(), [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -322,7 +330,7 @@ TEST(connection_impl_start, start_fails_if_transport_connect_throws) callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -356,7 +364,7 @@ TEST(connection_impl_send, send_fails_if_transport_fails_when_receiving_messages callback(std::make_exception_ptr(std::runtime_error("send error"))); }); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -390,19 +398,21 @@ TEST(connection_impl_start, start_fails_if_negotiate_request_fails) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string&, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string&, http_request, cancellation_token) { return http_response{ 400, "" }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -425,7 +435,7 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_has_error) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { auto response_body = url.find("/negotiate") != std::string::npos @@ -433,22 +443,18 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_has_error) : ""; return http_response{ 200, response_body }; - })); - - auto connect_mre = manual_reset_event(); - auto websocket_client = std::make_shared(); - websocket_client->set_connect_function([&connect_mre](const std::string&, std::function callback) - { - connect_mre.get(); - callback(nullptr); }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -465,15 +471,13 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_has_error) { ASSERT_STREQ("bad negotiate", e.what()); } - - connect_mre.set(); } TEST(connection_impl_start, start_fails_if_negotiate_response_does_not_have_websockets) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { auto response_body = url.find("/negotiate") != std::string::npos @@ -481,16 +485,18 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_does_not_have_webs : ""; return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -513,7 +519,7 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_does_not_have_tran { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { auto response_body = url.find("/negotiate") != std::string::npos @@ -521,16 +527,18 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_does_not_have_tran : ""; return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -553,7 +561,7 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_is_invalid) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { auto response_body = url.find("/negotiate") != std::string::npos @@ -561,16 +569,18 @@ TEST(connection_impl_start, start_fails_if_negotiate_response_is_invalid) : ""; return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -590,7 +600,7 @@ TEST(connection_impl_start, negotiate_follows_redirect) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { std::string response_body = ""; if (url.find("/negotiate") != std::string::npos) @@ -607,65 +617,9 @@ TEST(connection_impl_start, negotiate_follows_redirect) } return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); - - std::string connectUrl; - websocket_client->set_connect_function([&connectUrl](const std::string& url, std::function callback) - { - connectUrl = url; - callback(nullptr); - }); - - auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, - [http_client](const signalr_client_config& config) { - http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) - { - websocket_client->set_config(config); - return websocket_client; - }); - - auto mre = manual_reset_event(); - connection->start([&mre](std::exception_ptr exception) - { - mre.set(exception); }); - mre.get(); - - ASSERT_EQ("ws://redirected/?id=f7707523-307d-4cba-9abf-3eef701241e8", connectUrl); -} - -TEST(connection_impl_start, negotiate_redirect_uses_accessToken) -{ - std::shared_ptr writer(std::make_shared()); - std::string accessToken; - - auto http_client = std::shared_ptr(new test_http_client([&accessToken](const std::string& url, http_request request, cancellation_token) - { - std::string response_body = ""; - if (url.find("/negotiate") != std::string::npos) - { - if (url.find("redirected") != std::string::npos) - { - response_body = "{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", " - "\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }"; - } - else - { - response_body = "{ \"url\": \"http://redirected\", \"accessToken\": \"secret\" }"; - } - } - - accessToken = request.headers["Authorization"]; - return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + auto websocket_client = new test_websocket_client(); std::string connectUrl; websocket_client->set_connect_function([&connectUrl](const std::string& url, std::function callback) @@ -675,14 +629,14 @@ TEST(connection_impl_start, negotiate_redirect_uses_accessToken) }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -694,14 +648,70 @@ TEST(connection_impl_start, negotiate_redirect_uses_accessToken) mre.get(); ASSERT_EQ("ws://redirected/?id=f7707523-307d-4cba-9abf-3eef701241e8", connectUrl); - ASSERT_EQ("Bearer secret", accessToken); } +// +//TEST(connection_impl_start, negotiate_redirect_uses_accessToken) +//{ +// std::shared_ptr writer(std::make_shared()); +// std::string accessToken; +// +// auto http_client = new test_http_client([&accessToken](const std::string& url, http_request request, cancellation_token) +// { +// std::string response_body = ""; +// if (url.find("/negotiate") != std::string::npos) +// { +// if (url.find("redirected") != std::string::npos) +// { +// response_body = "{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", " +// "\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }"; +// } +// else +// { +// response_body = "{ \"url\": \"http://redirected\", \"accessToken\": \"secret\" }"; +// } +// } +// +// accessToken = request.get_headers().at("Authorization"); +// return http_response{ 200, response_body }; +// }); +// +// auto websocket_client = new test_websocket_client(); +// +// std::string connectUrl; +// websocket_client->set_connect_function([&connectUrl](const std::string& url, std::function callback) +// { +// connectUrl = url; +// callback(nullptr); +// }); +// +// auto connection = +// connection_impl::create(create_uri(), log_level::info, writer, +// [http_client](const signalr_client_config& config) { +// http_client->set_scheduler(config.get_scheduler()); +// return std::unique_ptr(http_client); +// }, [websocket_client](const signalr_client_config& config) +// { +// websocket_client->set_config(config); +// return std::unique_ptr(websocket_client); +// }); +// +// auto mre = manual_reset_event(); +// connection->start([&mre](std::exception_ptr exception) +// { +// mre.set(exception); +// }); +// +// mre.get(); +// +// ASSERT_EQ("ws://redirected/?id=f7707523-307d-4cba-9abf-3eef701241e8", connectUrl); +// ASSERT_EQ("Bearer secret", accessToken); +//} TEST(connection_impl_start, negotiate_fails_after_too_many_redirects) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { std::string response_body = ""; if (url.find("/negotiate") != std::string::npos) @@ -711,16 +721,18 @@ TEST(connection_impl_start, negotiate_fails_after_too_many_redirects) } return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -743,7 +755,7 @@ TEST(connection_impl_start, negotiate_fails_if_ProtocolVersion_in_response) { std::shared_ptr writer(std::make_shared()); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { std::string response_body = ""; if (url.find("/negotiate") != std::string::npos) @@ -752,16 +764,18 @@ TEST(connection_impl_start, negotiate_fails_if_ProtocolVersion_in_response) } return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config&) { return websocket_client; }); + return std::unique_ptr(http_client); + }, [](const signalr_client_config&) + { + auto websocket_client = new test_websocket_client(); + return std::unique_ptr(websocket_client); + }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -784,37 +798,35 @@ TEST(connection_impl_start, negotiate_redirect_does_not_overwrite_url) std::shared_ptr writer(std::make_shared()); int redirectCount = 0; - auto http_client = std::shared_ptr(new test_http_client([&redirectCount](const std::string& url, http_request, cancellation_token) - { - std::string response_body = ""; - if (url.find("/negotiate") != std::string::npos) - { - if (url.find("redirected") != std::string::npos) - { - response_body = "{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", " - "\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }"; - } - else - { - response_body = "{ \"url\": \"http://redirected\" }"; - redirectCount++; - } - } - - return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); - auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, - [http_client](const signalr_client_config& config) { + connection_impl::create(create_uri(), log_level::info, writer, + [&redirectCount](const signalr_client_config& config) { + auto http_client = new test_http_client([&redirectCount](const std::string& url, http_request, cancellation_token) + { + std::string response_body = ""; + if (url.find("/negotiate") != std::string::npos) + { + if (url.find("redirected") != std::string::npos) + { + response_body = "{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", " + "\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }"; + } + else + { + response_body = "{ \"url\": \"http://redirected\" }"; + redirectCount++; + } + } + + return http_response{ 200, response_body }; + }); http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = new test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -852,7 +864,7 @@ TEST(connection_impl_start, negotiate_redirect_uses_own_query_string) callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { std::string response_body = ""; if (url.find("/negotiate") != std::string::npos) @@ -869,16 +881,16 @@ TEST(connection_impl_start, negotiate_redirect_uses_own_query_string) } return http_response{ 200, response_body }; - })); + }); - auto connection = connection_impl::create(create_uri("a=b&c=d"), trace_level::error, writer, + auto connection = connection_impl::create(create_uri("a=b&c=d"), log_level::error, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -913,7 +925,7 @@ TEST(connection_impl_start, negotiate_with_negotiateVersion_uses_connectionToken callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { std::string response_body = ""; if (url.find("/negotiate") != std::string::npos) @@ -924,16 +936,16 @@ TEST(connection_impl_start, negotiate_with_negotiateVersion_uses_connectionToken } return http_response{ 200, response_body }; - })); + }); - auto connection = connection_impl::create(create_uri(), trace_level::error, writer, + auto connection = connection_impl::create(create_uri(), log_level::error, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -966,7 +978,7 @@ TEST(connection_impl_start, correct_connection_id_returned_with_negotiateVersion callback(nullptr); }); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { std::string response_body = ""; if (url.find("/negotiate") != std::string::npos) @@ -977,16 +989,16 @@ TEST(connection_impl_start, correct_connection_id_returned_with_negotiateVersion } return http_response{ 200, response_body }; - })); + }); - auto connection = connection_impl::create(create_uri(), trace_level::error, writer, + auto connection = connection_impl::create(create_uri(), log_level::error, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -1006,7 +1018,7 @@ TEST(connection_impl_start, negotiate_can_be_skipped) bool negotiate_called = false; - auto http_client = std::shared_ptr(new test_http_client([&negotiate_called](const std::string& url, http_request request, cancellation_token) + auto http_client = new test_http_client([&negotiate_called](const std::string& url, http_request request, cancellation_token) { negotiate_called = true; @@ -1017,19 +1029,18 @@ TEST(connection_impl_start, negotiate_can_be_skipped) : ""; return http_response{ 200, response_body }; - })); - - auto websocket_client = std::make_shared(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::info, writer, + connection_impl::create(create_uri(), log_level::info, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = new test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }, true); auto mre = manual_reset_event(); @@ -1043,6 +1054,8 @@ TEST(connection_impl_start, negotiate_can_be_skipped) ASSERT_TRUE(connection->get_connection_state() == connection_state::connected); ASSERT_TRUE(connection->get_connection_id().empty()); ASSERT_FALSE(negotiate_called); + + delete http_client; } TEST(connection_impl_process_response, process_response_logs_messages) @@ -1050,7 +1063,7 @@ TEST(connection_impl_process_response, process_response_logs_messages) std::shared_ptr writer(std::make_shared()); auto wait_receive = std::make_shared(); auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::debug); + auto connection = create_connection(websocket_client, writer, log_level::debug); auto message_mre = manual_reset_event(); connection->set_message_received([&message_mre](std::string&& message) @@ -1113,7 +1126,7 @@ TEST(connection_impl_send, message_sent) TEST(connection_impl_send, send_throws_if_connection_not_connected) { auto connection = - create_connection(create_test_websocket_client(), std::make_shared(), trace_level::none); + create_connection(nullptr, std::make_shared(), log_level::none); auto mre = manual_reset_event(); connection->send("whatever", transfer_format::text, [&mre](std::exception_ptr exception) @@ -1141,7 +1154,7 @@ TEST(connection_impl_send, exceptions_from_send_logged_and_propagated) callback(std::make_exception_ptr(std::runtime_error("error"))); }); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1216,7 +1229,7 @@ TEST(connection_impl_set_message_received, exception_from_callback_caught_and_lo auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); auto message_received_event = std::make_shared(); connection->set_message_received([message_received_event](const std::string& m) @@ -1256,7 +1269,7 @@ TEST(connection_impl_set_message_received, non_std_exception_from_callback_caugh auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); auto message_received_event = std::make_shared(); connection->set_message_received([message_received_event](const std::string& m) @@ -1322,17 +1335,17 @@ TEST(connection_impl_set_configuration, set_message_received_callback_can_be_set "cannot set the callback when the connection is not in the disconnected state. current connection state: connected"); } -TEST(connection_impl_set_configuration, set_disconnected_callback_can_be_set_only_in_disconnected_state) +TEST(connection_impl_set_configuration, on_disconnected_callback_can_be_set_only_in_disconnected_state) { can_be_set_only_in_disconnected_state( - [](connection_impl* connection) { connection->set_disconnected([](std::exception_ptr) {}); }, + [](connection_impl* connection) { connection->on_disconnected([](std::exception_ptr) {}); }, "cannot set the disconnected callback when the connection is not in the disconnected state. current connection state: connected"); } TEST(connection_impl_stop, stopping_disconnected_connection_is_no_op) { std::shared_ptr writer{ std::make_shared() }; - auto connection = create_connection(create_test_websocket_client(), writer, trace_level::verbose); + auto connection = create_connection(nullptr, writer, log_level::verbose); auto mre = manual_reset_event(); connection->stop([&mre](std::exception_ptr exception) { @@ -1365,7 +1378,7 @@ TEST(connection_impl_stop, stopping_disconnecting_connection_returns_canceled_ta callback(nullptr); }); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(websocket_client, writer, log_level::verbose); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1413,7 +1426,7 @@ TEST(connection_impl_stop, can_start_and_stop_connection) auto writer = std::shared_ptr{ std::make_shared() }; auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(websocket_client, writer, log_level::verbose); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1443,8 +1456,7 @@ TEST(connection_impl_stop, can_start_and_stop_connection_multiple_times) auto writer = std::shared_ptr{ std::make_shared() }; { - auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(nullptr, writer, log_level::verbose); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1502,8 +1514,7 @@ TEST(connection_impl_stop, dtor_stops_the_connection) auto writer = std::shared_ptr{ std::make_shared() }; { - auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(nullptr, writer, log_level::verbose); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1536,7 +1547,7 @@ TEST(connection_impl_stop, stop_cancels_ongoing_start_request) { auto disconnect_completed_event = std::make_shared(); - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { auto response_body = url.find("/negotiate") != std::string::npos @@ -1545,7 +1556,7 @@ TEST(connection_impl_stop, stop_cancels_ongoing_start_request) : ""; return http_response{ 200, response_body }; - })); + }); auto wait_for_start_mre = manual_reset_event(); @@ -1558,17 +1569,17 @@ TEST(connection_impl_stop, stop_cancels_ongoing_start_request) }); auto writer = std::shared_ptr{ std::make_shared() }; - auto connection = connection_impl::create(create_uri(), trace_level::verbose, writer, + auto connection = connection_impl::create(create_uri(), log_level::verbose, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); - connection->set_disconnected([](std::exception_ptr ex) + connection->on_disconnected([](std::exception_ptr ex) { ASSERT_TRUE(false); }); @@ -1615,7 +1626,7 @@ TEST(connection_impl_stop, ongoing_start_request_canceled_if_connection_stopped_ { auto stop_mre = manual_reset_event(); auto done_mre = manual_reset_event(); - auto http_client = std::shared_ptr(new test_http_client([&stop_mre, &done_mre](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([&stop_mre, &done_mre](const std::string& url, http_request, cancellation_token) { stop_mre.get(); @@ -1628,19 +1639,18 @@ TEST(connection_impl_stop, ongoing_start_request_canceled_if_connection_stopped_ done_mre.set(); return http_response{ 200, response_body }; - })); - - auto websocket_client = create_test_websocket_client(); + }); auto writer = std::shared_ptr{ std::make_shared() }; - auto connection = connection_impl::create(create_uri(), trace_level::verbose, writer, + auto connection = connection_impl::create(create_uri(), log_level::verbose, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -1690,7 +1700,7 @@ TEST(connection_impl_stop, stop_invokes_disconnected_callback) auto connection = create_connection(websocket_client); auto disconnected_invoked = false; - connection->set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked = true; }); + connection->on_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked = true; }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1715,9 +1725,9 @@ TEST(connection_impl_stop, std_exception_from_disconnected_callback_caught_and_l auto writer = std::shared_ptr{ std::make_shared() }; auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); - connection->set_disconnected([](std::exception_ptr) { throw std::runtime_error("exception from disconnected"); }); + connection->on_disconnected([](std::exception_ptr) { throw std::runtime_error("exception from disconnected"); }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1744,9 +1754,9 @@ TEST(connection_impl_stop, exception_from_disconnected_callback_caught_and_logge auto writer = std::shared_ptr{ std::make_shared() }; auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); - connection->set_disconnected([](std::exception_ptr) { throw 42; }); + connection->on_disconnected([](std::exception_ptr) { throw 42; }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1774,7 +1784,7 @@ TEST(connection_impl_stop, transport_error_invokes_disconnected_callback) auto connection = create_connection(websocket_client); auto disconnect_mre = manual_reset_event(); - connection->set_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); + connection->on_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1804,7 +1814,7 @@ TEST(connection_impl_config, custom_headers_set_in_requests) { auto writer = std::shared_ptr{ std::make_shared() }; - auto http_client = std::shared_ptr(new test_http_client([](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) { auto response_body = url.find("/negotiate") != std::string::npos @@ -1821,19 +1831,18 @@ TEST(connection_impl_config, custom_headers_set_in_requests) };*/ return http_response{ 200, response_body }; - })); - - auto websocket_client = create_test_websocket_client(); + }); auto connection = - connection_impl::create(create_uri(), trace_level::verbose, + connection_impl::create(create_uri(), log_level::verbose, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); signalr::signalr_client_config signalr_client_config{}; @@ -1874,7 +1883,7 @@ TEST(connection_impl_change_state, change_state_logs) { std::shared_ptr writer(std::make_shared()); auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(websocket_client, writer, log_level::verbose); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1900,7 +1909,7 @@ TEST(connection_id, connection_id_is_set_if_start_fails_but_negotiate_request_su callback(std::make_exception_ptr(std::runtime_error("connecting failed"))); }); - auto connection = create_connection(websocket_client, writer, trace_level::error); + auto connection = create_connection(websocket_client, writer, log_level::error); ASSERT_EQ("", connection->get_connection_id()); @@ -1928,7 +1937,7 @@ TEST(connection_id, can_get_connection_id_when_connection_in_connected_state) auto writer = std::shared_ptr{ std::make_shared() }; auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(websocket_client, writer, log_level::verbose); std::string connection_id; auto mre = manual_reset_event(); @@ -1955,7 +1964,7 @@ TEST(connection_id, can_get_connection_id_after_connection_has_stopped) auto writer = std::shared_ptr{ std::make_shared() }; auto websocket_client = create_test_websocket_client(); - auto connection = create_connection(websocket_client, writer, trace_level::verbose); + auto connection = create_connection(websocket_client, writer, log_level::verbose); auto mre = manual_reset_event(); connection->start([&mre](std::exception_ptr exception) @@ -1981,32 +1990,30 @@ TEST(connection_id, connection_id_reset_when_starting_connection) auto writer = std::shared_ptr{ std::make_shared() }; - auto websocket_client = create_test_websocket_client(); - - auto http_client = std::shared_ptr(new test_http_client([&fail_http_requests](const std::string& url, http_request, cancellation_token) - { - if (!fail_http_requests) { - auto response_body = - url.find("/negotiate") != std::string::npos - ? "{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", " - "\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }" - : ""; - - return http_response{ 200, response_body }; - } - - return http_response{ 500, "" }; - })); - auto connection = - connection_impl::create(create_uri(), trace_level::none, std::make_shared(), - [http_client](const signalr_client_config& config) { + connection_impl::create(create_uri(), log_level::none, std::make_shared(), + [&fail_http_requests](const signalr_client_config& config) { + auto http_client = new test_http_client([&fail_http_requests](const std::string& url, http_request, cancellation_token) + { + if (!fail_http_requests) { + auto response_body = + url.find("/negotiate") != std::string::npos + ? "{\"connectionId\" : \"f7707523-307d-4cba-9abf-3eef701241e8\", " + "\"availableTransports\" : [ { \"transport\": \"WebSockets\", \"transferFormats\": [ \"Text\", \"Binary\" ] } ] }" + : ""; + + return http_response{ 200, response_body }; + } + + return http_response{ 500, "" }; + }); http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto mre = manual_reset_event(); @@ -2043,8 +2050,7 @@ TEST(connection_impl_stop, triggers_http_send_token) auto writer = std::shared_ptr{ std::make_shared() }; auto send_started = manual_reset_event(); - auto websocket_client = create_test_websocket_client(); - auto http_client = std::shared_ptr(new test_http_client([&send_started](const std::string& url, http_request, cancellation_token token) + auto http_client = new test_http_client([&send_started](const std::string& url, http_request, cancellation_token token) { send_started.set(); auto mre = manual_reset_event(); @@ -2060,16 +2066,17 @@ TEST(connection_impl_stop, triggers_http_send_token) : ""; return http_response{ 200, response_body }; - })); + }); auto connection = - connection_impl::create(create_uri(), trace_level::verbose, writer, + connection_impl::create(create_uri(), log_level::verbose, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto start_mre = manual_reset_event(); @@ -2105,8 +2112,7 @@ TEST(connection_impl_stop, http_client_throws_from_registered_token) auto writer = std::shared_ptr{ std::make_shared() }; auto send_started = manual_reset_event(); - auto websocket_client = create_test_websocket_client(); - auto http_client = std::shared_ptr(new test_http_client([&send_started](const std::string& url, http_request, cancellation_token token) + auto http_client = new test_http_client([&send_started](const std::string& url, http_request, cancellation_token token) { auto mre = manual_reset_event(); token.register_callback([&mre]() @@ -2123,16 +2129,17 @@ TEST(connection_impl_stop, http_client_throws_from_registered_token) : ""; return http_response{ 200, response_body }; - })); + }); auto connection = - connection_impl::create(create_uri(), trace_level::verbose, writer, + connection_impl::create(create_uri(), log_level::verbose, writer, [http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; - }, [websocket_client](const signalr_client_config& config) + return std::unique_ptr(http_client); + }, [](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }); auto start_mre = manual_reset_event(); @@ -2211,54 +2218,54 @@ class stop_capturing_websocket_client : public websocket_client std::function m_stop_callback; bool m_exception_on_stop; }; - -// regression test: if a websocket_client impl held onto a reference of the stop callback we passed in it could be destructed in the middle of the stop callback running -// which would delete the callback while we're still running it, resulting in unexpected behavior -TEST(connection_impl_stop, works_with_stop_callback_capturing_websocket_client_with_error) -{ - auto writer = std::shared_ptr{ std::make_shared() }; - - auto connection = - connection_impl::create(create_uri(), trace_level::verbose, writer, - create_test_http_client(), [](const signalr_client_config&) - { - return std::make_shared(true); - }); - - auto start_mre = manual_reset_event(); - connection->start([&start_mre](std::exception_ptr exception) - { - start_mre.set(exception); - }); - - start_mre.get(); - - auto stop_mre = manual_reset_event(); - connection->stop([&stop_mre](std::exception_ptr exception) - { - stop_mre.set(exception); - }, nullptr); - - try - { - stop_mre.get(); - ASSERT_TRUE(false); - } - catch (...) {} - - ASSERT_NE("", connection->get_connection_id()); - ASSERT_EQ(connection_state::disconnected, connection->get_connection_state()); -} +// +//// regression test: if a websocket_client impl held onto a reference of the stop callback we passed in it could be destructed in the middle of the stop callback running +//// which would delete the callback while we're still running it, resulting in unexpected behavior +//TEST(connection_impl_stop, works_with_stop_callback_capturing_websocket_client_with_error) +//{ +// auto writer = std::shared_ptr{ std::make_shared() }; +// +// auto connection = +// connection_impl::create(create_uri(), log_level::verbose, writer, +// create_test_http_client(), [](const signalr_client_config&) +// { +// return std::unique_ptr(new stop_capturing_websocket_client(true)); +// }); +// +// auto start_mre = manual_reset_event(); +// connection->start([&start_mre](std::exception_ptr exception) +// { +// start_mre.set(exception); +// }); +// +// start_mre.get(); +// +// auto stop_mre = manual_reset_event(); +// connection->stop([&stop_mre](std::exception_ptr exception) +// { +// stop_mre.set(exception); +// }, nullptr); +// +// try +// { +// stop_mre.get(); +// ASSERT_TRUE(false); +// } +// catch (...) {} +// +// ASSERT_NE("", connection->get_connection_id()); +// ASSERT_EQ(connection_state::disconnected, connection->get_connection_state()); +//} TEST(connection_impl_stop, works_with_stop_callback_capturing_websocket_client) { auto writer = std::shared_ptr{ std::make_shared() }; auto connection = - connection_impl::create(create_uri(), trace_level::verbose, writer, + connection_impl::create(create_uri(), log_level::verbose, writer, create_test_http_client(), [](const signalr_client_config&) { - return std::make_shared(); + return std::unique_ptr(new stop_capturing_websocket_client()); }); auto start_mre = manual_reset_event(); diff --git a/test/signalrclienttests/hub_connection_tests.cpp b/test/signalrclienttests/hub_connection_tests.cpp index 9b44a6cf..732a827b 100644 --- a/test/signalrclienttests/hub_connection_tests.cpp +++ b/test/signalrclienttests/hub_connection_tests.cpp @@ -15,16 +15,22 @@ using namespace signalr; -std::unique_ptr create_hub_connection(std::shared_ptr websocket_client = create_test_websocket_client(), - std::shared_ptr log_writer = std::make_shared(), trace_level trace_level = trace_level::verbose) +std::unique_ptr create_hub_connection(test_websocket_client* websocket_client = nullptr, + std::shared_ptr log_writer = std::make_shared(), log_level log_level = log_level::verbose, + signalr_client_config config = {}) { - return hub_connection_builder::create(create_uri()) - .with_logging(log_writer, trace_level) + return hub_connection_builder(create_uri()) + .configure_options(config) + .with_logging(log_writer, log_level) .with_http_client_factory(create_test_http_client()) - .with_websocket_factory([websocket_client](const signalr_client_config& config) + .with_websocket_factory([websocket_client](const signalr_client_config& config) mutable { + if (websocket_client == nullptr) + { + websocket_client = create_test_websocket_client(); + } websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }) .build(); } @@ -107,20 +113,23 @@ TEST(url, negotiate_appended_to_url) for (const auto& base_url : base_urls) { std::string requested_url; - auto http_client = std::make_shared([&requested_url](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([&requested_url](const std::string& url, http_request, cancellation_token) { requested_url = url; return http_response{ 404, "" }; }); - auto hub_connection = hub_connection_builder::create(base_url) - .with_logging(std::make_shared(), trace_level::none) + auto hub_connection = hub_connection_builder(base_url) + .with_logging(std::make_shared(), log_level::none) .with_http_client_factory([http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); + }) + .with_websocket_factory([](const signalr_client_config&) + { + return std::unique_ptr(create_test_websocket_client()); }) - .with_websocket_factory([](const signalr_client_config&) { return create_test_websocket_client(); }) .build(); auto mre = manual_reset_event(); @@ -211,7 +220,7 @@ TEST(start, start_fails_for_handshake_response_with_error) auto websocket_client = create_test_websocket_client(); auto hub_connection = create_hub_connection(websocket_client); std::exception_ptr exception; - hub_connection->set_disconnected([&exception](std::exception_ptr ex) + hub_connection->on_disconnected([&exception](std::exception_ptr ex) { exception = ex; }); @@ -401,10 +410,9 @@ TEST(start, start_fails_if_stop_called_before_handshake_response) TEST(start, start_fails_if_handshake_times_out) { auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client); auto config = signalr_client_config(); config.set_handshake_timeout(std::chrono::seconds(1)); - hub_connection->set_client_config(config); + auto hub_connection = create_hub_connection(websocket_client, std::make_shared(), log_level::verbose, config); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -430,20 +438,23 @@ TEST(start, start_fails_if_handshake_times_out) TEST(start, propogates_exception_from_negotiate) { - auto http_client = std::make_shared([](const std::string& url, http_request, cancellation_token) -> http_response + auto http_client = new test_http_client([](const std::string& url, http_request, cancellation_token) -> http_response { throw custom_exception(); }); - auto websocket_client = create_test_websocket_client(); - auto hub_connection = hub_connection_builder::create("http://fakeuri") - .with_logging(std::make_shared(), trace_level::none) + auto hub_connection = hub_connection_builder("http://fakeuri") + .with_logging(std::make_shared(), log_level::none) .with_http_client_factory([http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); + }) + .with_websocket_factory([](const signalr_client_config&) + { + auto websocket_client = create_test_websocket_client(); + return std::unique_ptr(websocket_client); }) - .with_websocket_factory([websocket_client](const signalr_client_config&) { return websocket_client; }) .build(); auto mre = manual_reset_event(); @@ -469,33 +480,32 @@ TEST(start, propogates_exception_from_negotiate) TEST(start, propogates_exception_from_negotiate_and_can_start_again) { auto start_count = 0; - auto http_client = std::make_shared([&start_count](const std::string& url, http_request, cancellation_token) -> http_response - { - start_count++; - if (start_count == 1) - { - throw custom_exception(); - } - throw custom_exception("custom exception 2"); - }); - - auto websocket_client = create_test_websocket_client(); - auto hub_connection = hub_connection_builder::create("http://fakeuri") - .with_logging(std::make_shared(), trace_level::none) - .with_http_client_factory([http_client](const signalr_client_config& config) + auto hub_connection = hub_connection_builder("http://fakeuri") + .with_logging(std::make_shared(), log_level::none) + .with_http_client_factory([&start_count](const signalr_client_config& config) { + auto http_client = new test_http_client([&start_count](const std::string& url, http_request, cancellation_token) -> http_response + { + start_count++; + if (start_count == 1) + { + throw custom_exception(); + } + throw custom_exception("custom exception 2"); + }); http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }) - .with_websocket_factory([websocket_client](const signalr_client_config& config) + .with_websocket_factory([](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }) .build(); std::atomic disconnected { false }; - hub_connection->set_disconnected([&disconnected](std::exception_ptr ex) + hub_connection->on_disconnected([&disconnected](std::exception_ptr ex) { disconnected.store(true); }); @@ -566,8 +576,7 @@ TEST(stop, stop_stops_connection) TEST(stop, does_nothing_on_disconnected_connection) { - auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client); + auto hub_connection = create_hub_connection(); auto mre = manual_reset_event(); @@ -586,8 +595,7 @@ TEST(stop, does_nothing_on_disconnected_connection) // Makes sure the destructor of hub_connection is safe after moving the object TEST(dtor, can_move_connection) { - auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client); + auto hub_connection = create_hub_connection(); auto hub_connection2 = std::move(hub_connection); } @@ -603,7 +611,7 @@ TEST(stop, second_stop_waits_for_first_stop) }); auto hub_connection = create_hub_connection(websocket_client); bool connection_closed = false; - hub_connection->set_disconnected([&connection_closed](std::exception_ptr) + hub_connection->on_disconnected([&connection_closed](std::exception_ptr) { connection_closed = true; }); @@ -646,50 +654,50 @@ TEST(stop, second_stop_waits_for_first_stop) ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); } -TEST(stop, blocking_stop_callback_does_not_prevent_start) -{ - auto transport_stop_mre = manual_reset_event(); - auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client); - - auto mre = manual_reset_event(); - hub_connection->start([&mre](std::exception_ptr exception) - { - mre.set(exception); - }); - - ASSERT_FALSE(websocket_client->receive_loop_started.wait(5000)); - ASSERT_FALSE(websocket_client->handshake_sent.wait(5000)); - websocket_client->receive_message("{}\x1e"); - - mre.get(); - - auto blocking_mre = manual_reset_event(); - hub_connection->stop([&mre, &blocking_mre](std::exception_ptr exception) - { - mre.set(exception); - blocking_mre.get(); - mre.set(); - }); - - mre.get(); - ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); - - hub_connection->start([&mre](std::exception_ptr exception) - { - mre.set(exception); - }); - - ASSERT_FALSE(websocket_client->receive_loop_started.wait(5000)); - ASSERT_FALSE(websocket_client->handshake_sent.wait(5000)); - websocket_client->receive_message("{}\x1e"); - - mre.get(); - ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); - - blocking_mre.set(); - mre.get(); -} +//TEST(stop, blocking_stop_callback_does_not_prevent_start) +//{ +// auto transport_stop_mre = manual_reset_event(); +// auto websocket_client = create_test_websocket_client(); +// auto hub_connection = create_hub_connection(websocket_client); +// +// auto mre = manual_reset_event(); +// hub_connection->start([&mre](std::exception_ptr exception) +// { +// mre.set(exception); +// }); +// +// ASSERT_FALSE(websocket_client->receive_loop_started.wait(5000)); +// ASSERT_FALSE(websocket_client->handshake_sent.wait(5000)); +// websocket_client->receive_message("{}\x1e"); +// +// mre.get(); +// +// auto blocking_mre = manual_reset_event(); +// hub_connection->stop([&mre, &blocking_mre](std::exception_ptr exception) +// { +// mre.set(exception); +// blocking_mre.get(); +// mre.set(); +// }); +// +// mre.get(); +// ASSERT_EQ(connection_state::disconnected, hub_connection->get_connection_state()); +// +// hub_connection->start([&mre](std::exception_ptr exception) +// { +// mre.set(exception); +// }); +// +// ASSERT_FALSE(websocket_client->receive_loop_started.wait(5000)); +// ASSERT_FALSE(websocket_client->handshake_sent.wait(5000)); +// websocket_client->receive_message("{}\x1e"); +// +// mre.get(); +// ASSERT_EQ(connection_state::connected, hub_connection->get_connection_state()); +// +// blocking_mre.set(); +// mre.get(); +//} TEST(stop, disconnected_callback_called_when_hub_connection_stops) { @@ -697,7 +705,7 @@ TEST(stop, disconnected_callback_called_when_hub_connection_stops) auto hub_connection = create_hub_connection(websocket_client); auto disconnected_invoked = false; - hub_connection->set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked = true; }); + hub_connection->on_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked = true; }); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -728,7 +736,7 @@ TEST(stop, disconnected_callback_called_when_transport_error_occurs) auto hub_connection = create_hub_connection(websocket_client); auto disconnected_invoked = manual_reset_event(); - hub_connection->set_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked.set(); }); + hub_connection->on_disconnected([&disconnected_invoked](std::exception_ptr) { disconnected_invoked.set(); }); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -754,7 +762,7 @@ TEST(stop, transport_error_propogates_to_disconnected_callback) auto hub_connection = create_hub_connection(websocket_client); auto disconnected_invoked = manual_reset_event(); - hub_connection->set_disconnected([&disconnected_invoked](std::exception_ptr exception) { disconnected_invoked.set(exception); }); + hub_connection->on_disconnected([&disconnected_invoked](std::exception_ptr exception) { disconnected_invoked.set(exception); }); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -788,7 +796,7 @@ TEST(stop, connection_stopped_when_going_out_of_scope) { auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::verbose); + auto hub_connection = create_hub_connection(websocket_client, writer, log_level::verbose); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -903,8 +911,7 @@ TEST(stop, stops_with_inprogress_negotiate) { auto stop_mre = manual_reset_event(); auto done_mre = manual_reset_event(); - auto websocket_client = create_test_websocket_client(); - auto http_client = std::shared_ptr(new test_http_client([&stop_mre, &done_mre](const std::string& url, http_request, cancellation_token) + auto http_client = new test_http_client([&stop_mre, &done_mre](const std::string& url, http_request, cancellation_token) { stop_mre.get(); @@ -917,25 +924,26 @@ TEST(stop, stops_with_inprogress_negotiate) done_mre.set(); return http_response{ 200, response_body }; - })); + }); - auto hub_connection = hub_connection_builder::create(create_uri()) - .with_logging(std::make_shared(), trace_level::verbose) + auto hub_connection = hub_connection_builder(create_uri()) + .with_logging(std::make_shared(), log_level::verbose) .with_http_client_factory([http_client](const signalr_client_config& config) { http_client->set_scheduler(config.get_scheduler()); - return http_client; + return std::unique_ptr(http_client); }) - .with_websocket_factory([websocket_client](const signalr_client_config& config) + .with_websocket_factory([](const signalr_client_config& config) { + auto websocket_client = create_test_websocket_client(); websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }) .build(); auto disconnected_called = false; // disconnected not called for connections that never started successfully - hub_connection->set_disconnected([&disconnected_called](std::exception_ptr ex) + hub_connection->on_disconnected([&disconnected_called](std::exception_ptr ex) { disconnected_called = true; }); @@ -1077,10 +1085,10 @@ TEST(hub_invocation, hub_connection_closes_when_invocation_response_missing_argu auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::error); + auto hub_connection = create_hub_connection(websocket_client, writer, log_level::error); auto close_mre = manual_reset_event(); - hub_connection->set_disconnected([&close_mre](std::exception_ptr ex) + hub_connection->on_disconnected([&close_mre](std::exception_ptr ex) { close_mre.set(ex); }); @@ -1121,10 +1129,10 @@ TEST(hub_invocation, hub_connection_closes_when_invocation_response_missing_targ auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::error); + auto hub_connection = create_hub_connection(websocket_client, writer, log_level::error); auto close_mre = manual_reset_event(); - hub_connection->set_disconnected([&close_mre](std::exception_ptr ex) + hub_connection->on_disconnected([&close_mre](std::exception_ptr ex) { close_mre.set(ex); }); @@ -1439,7 +1447,7 @@ TEST(receive, logs_if_callback_for_given_id_not_found) auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::info); + auto hub_connection = create_hub_connection(websocket_client, writer, log_level::info); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -1468,10 +1476,10 @@ TEST(receive, closes_if_error_from_parsing) auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = create_hub_connection(websocket_client, writer, trace_level::info); + auto hub_connection = create_hub_connection(websocket_client, writer, log_level::info); auto disconnect_mre = manual_reset_event(); - hub_connection->set_disconnected([&disconnect_mre](std::exception_ptr ex) + hub_connection->on_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); @@ -1741,7 +1749,7 @@ TEST(invoke, invoke_handles_zero_value_as_int) class test_scheduler : public scheduler { public: - virtual void schedule(const signalr_base_cb& cb, std::chrono::milliseconds delay = std::chrono::milliseconds::zero()) override + virtual void schedule(std::function cb, std::chrono::milliseconds delay = std::chrono::milliseconds::zero()) override { schedule_count++; std::thread([cb, delay]() @@ -1757,21 +1765,20 @@ class test_scheduler : public scheduler TEST(config, can_replace_scheduler) { auto websocket_client = create_test_websocket_client(); - auto hub_connection = hub_connection_builder::create(create_uri()) - .with_logging(std::make_shared(), trace_level::verbose) + signalr_client_config config{}; + auto scheduler = std::make_shared(); + config.set_scheduler(scheduler); + auto hub_connection = hub_connection_builder(create_uri()) + .configure_options(config) + .with_logging(std::make_shared(), log_level::verbose) .with_http_client_factory(create_test_http_client()) .with_websocket_factory([websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }) .build(); - signalr_client_config config{}; - auto scheduler = std::make_shared(); - config.set_scheduler(scheduler); - hub_connection->set_client_config(config); - // do some "work" to verify scheduler is used auto mre = manual_reset_event(); @@ -1854,10 +1861,11 @@ TEST(send, throws_if_protocol_fails) auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = hub_connection_impl::create("", std::move(std::unique_ptr(new throw_hub_protocol())), signalr::trace_level::info, writer, nullptr, [websocket_client](const signalr_client_config& config) + auto hub_connection = hub_connection_impl::create("", std::move(std::unique_ptr(new throw_hub_protocol())), + {}, signalr::log_level::info, writer, nullptr, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }, true); auto mre = manual_reset_event(); @@ -1935,14 +1943,15 @@ TEST(receive, close_connection_on_null_hub_message) auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = hub_connection_impl::create("", std::move(std::unique_ptr(new empty_hub_protocol())), signalr::trace_level::info, writer, nullptr, [websocket_client](const signalr_client_config& config) + auto hub_connection = hub_connection_impl::create("", std::move(std::unique_ptr(new empty_hub_protocol())), + {}, signalr::log_level::info, writer, nullptr, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }, true); auto close_mre = manual_reset_event(); - hub_connection->set_disconnected([&close_mre](std::exception_ptr exception) + hub_connection->on_disconnected([&close_mre](std::exception_ptr exception) { close_mre.set(exception); }); @@ -1995,8 +2004,7 @@ TEST(keepalive, sends_ping_messages) [](const std::string&, std::function callback) { callback(nullptr); }, [](std::function callback) { callback(nullptr); }, false); - auto hub_connection = create_hub_connection(websocket_client); - hub_connection->set_client_config(config); + auto hub_connection = create_hub_connection(websocket_client, std::make_shared(), log_level::verbose, config); auto mre = manual_reset_event(); hub_connection->start([&mre](std::exception_ptr exception) @@ -2025,13 +2033,12 @@ TEST(keepalive, server_timeout_on_no_ping_from_server) config.set_keepalive_interval(std::chrono::seconds(1)); config.set_server_timeout(std::chrono::seconds(1)); auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client); - hub_connection->set_client_config(config); + auto hub_connection = create_hub_connection(websocket_client, std::make_shared(), log_level::verbose, config); auto disconnected_called = false; auto disconnect_mre = manual_reset_event(); - hub_connection->set_disconnected([&disconnected_called, &disconnect_mre](std::exception_ptr ex) + hub_connection->on_disconnected([&disconnected_called, &disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); @@ -2066,11 +2073,10 @@ TEST(keepalive, resets_server_timeout_timer_on_any_message_from_server) config.set_keepalive_interval(std::chrono::seconds(1)); config.set_server_timeout(std::chrono::seconds(1)); auto websocket_client = create_test_websocket_client(); - auto hub_connection = create_hub_connection(websocket_client); - hub_connection->set_client_config(config); + auto hub_connection = create_hub_connection(websocket_client, std::make_shared(), log_level::verbose, config); auto disconnect_mre = manual_reset_event(); - hub_connection->set_disconnected([&disconnect_mre](std::exception_ptr ex) + hub_connection->on_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); @@ -2146,15 +2152,15 @@ TEST(receive, unknown_message_type_closes_connection) auto websocket_client = create_test_websocket_client(); std::shared_ptr writer(std::make_shared()); - auto hub_connection = hub_connection_impl::create("", std::move(std::unique_ptr(new unknown_message_type_hub_protocol())), signalr::trace_level::info, writer, + auto hub_connection = hub_connection_impl::create("", std::move(std::unique_ptr(new unknown_message_type_hub_protocol())), {}, signalr::log_level::info, writer, nullptr, [websocket_client](const signalr_client_config& config) { websocket_client->set_config(config); - return websocket_client; + return std::unique_ptr(websocket_client); }, true); auto disconnect_mre = manual_reset_event(); - hub_connection->set_disconnected([&disconnect_mre](std::exception_ptr ex) + hub_connection->on_disconnected([&disconnect_mre](std::exception_ptr ex) { disconnect_mre.set(ex); }); diff --git a/test/signalrclienttests/logger_tests.cpp b/test/signalrclienttests/logger_tests.cpp index 10df49b6..09c0abc7 100644 --- a/test/signalrclienttests/logger_tests.cpp +++ b/test/signalrclienttests/logger_tests.cpp @@ -10,24 +10,24 @@ #include using namespace signalr; -TEST(logger_write, entry_added_if_trace_level_set) +TEST(logger_write, entry_added_if_log_level_set) { std::shared_ptr writer(std::make_shared()); - logger l(writer, trace_level::info); - l.log(trace_level::info, "message"); + logger l(writer, log_level::info); + l.log(log_level::info, "message"); auto log_entries = std::dynamic_pointer_cast(writer)->get_log_entries(); ASSERT_EQ(1U, log_entries.size()); } -TEST(logger_write, entry_not_added_if_trace_level_not_high_enough) +TEST(logger_write, entry_not_added_if_log_level_not_high_enough) { std::shared_ptr writer(std::make_shared()); - logger l(writer, trace_level::info); - l.log(trace_level::debug, "event"); + logger l(writer, log_level::info); + l.log(log_level::debug, "event"); auto log_entries = std::dynamic_pointer_cast(writer)->get_log_entries(); @@ -38,8 +38,8 @@ TEST(logger_write, entries_formatted_correctly) { std::shared_ptr writer(std::make_shared()); - logger l(writer, trace_level::verbose); - l.log(trace_level::info, "message"); + logger l(writer, log_level::verbose); + l.log(log_level::info, "message"); auto log_entries = std::dynamic_pointer_cast(writer)->get_log_entries(); ASSERT_FALSE(log_entries.empty()); diff --git a/test/signalrclienttests/negotiate_tests.cpp b/test/signalrclienttests/negotiate_tests.cpp index 7cb7db4e..a98b1d9c 100644 --- a/test/signalrclienttests/negotiate_tests.cpp +++ b/test/signalrclienttests/negotiate_tests.cpp @@ -27,7 +27,7 @@ TEST(negotiate, request_created_with_correct_url) auto cts = std::make_shared(); auto mre = manual_reset_event(); - negotiate::negotiate(http_client, "http://fake/signalr", signalr_client_config(), + negotiate::send_negotiate(http_client.get(), "http://fake/signalr", signalr_client_config(), [&mre](signalr::negotiation_response&&, std::exception_ptr exception) { mre.set(); @@ -53,7 +53,7 @@ TEST(negotiate, negotiation_request_sent_and_response_serialized) auto cts = std::make_shared(); auto mre = manual_reset_event(); - negotiate::negotiate(request_factory, "http://fake/signalr", signalr_client_config(), + negotiate::send_negotiate(request_factory.get(), "http://fake/signalr", signalr_client_config(), [&mre](negotiation_response&& response, std::exception_ptr exception) { mre.set(response); @@ -86,7 +86,7 @@ TEST(negotiate, negotiation_response_with_redirect) auto cts = std::make_shared(); auto mre = manual_reset_event(); - negotiate::negotiate(request_factory, "http://fake/signalr", signalr_client_config(), + negotiate::send_negotiate(request_factory.get(), "http://fake/signalr", signalr_client_config(), [&mre](negotiation_response&& response, std::exception_ptr exception) { mre.set(response); @@ -116,7 +116,7 @@ TEST(negotiate, negotiation_response_with_negotiateVersion) auto cts = std::make_shared(); auto mre = manual_reset_event(); - negotiate::negotiate(request_factory, "http://fake/signalr", signalr_client_config(), + negotiate::send_negotiate(request_factory.get(), "http://fake/signalr", signalr_client_config(), [&mre](negotiation_response&& response, std::exception_ptr exception) { mre.set(response); @@ -146,7 +146,7 @@ TEST(negotiate, negotiation_response_with_future_negotiateVersion) auto cts = std::make_shared(); auto mre = manual_reset_event(); - negotiate::negotiate(request_factory, "http://fake/signalr", signalr_client_config(), + negotiate::send_negotiate(request_factory.get(), "http://fake/signalr", signalr_client_config(), [&mre](negotiation_response&& response, std::exception_ptr exception) { mre.set(response); diff --git a/test/signalrclienttests/test_utils.cpp b/test/signalrclienttests/test_utils.cpp index 7ec7aa46..ab057ce4 100644 --- a/test/signalrclienttests/test_utils.cpp +++ b/test/signalrclienttests/test_utils.cpp @@ -30,11 +30,11 @@ bool has_log_entry(const std::string& log_entry, const std::vector& return false; } -std::function(const signalr::signalr_client_config&)> create_test_http_client() +std::function(const signalr::signalr_client_config&)> create_test_http_client() { return [](const signalr_client_config& config) { - auto client = std::shared_ptr(new test_http_client([](const std::string& url, http_request request, cancellation_token) + auto client = std::unique_ptr(new test_http_client([](const std::string& url, http_request request, cancellation_token) { auto response_body = url.find_first_of("/negotiate") != 0 @@ -104,16 +104,16 @@ void assert_signalr_value_equality(const signalr::value& expected, const signalr ASSERT_EQ(expected.type(), actual.type()); switch (expected.type()) { - case value_type::string: + case value::type::string: ASSERT_STREQ(expected.as_string().data(), actual.as_string().data()); break; - case value_type::boolean: + case value::type::boolean: ASSERT_EQ(expected.as_bool(), actual.as_bool()); break; - case value_type::float64: + case value::type::float64: ASSERT_DOUBLE_EQ(expected.as_double(), actual.as_double()); break; - case value_type::map: + case value::type::map: { auto& expected_map = expected.as_map(); auto& actual_map = actual.as_map(); @@ -126,7 +126,7 @@ void assert_signalr_value_equality(const signalr::value& expected, const signalr } break; } - case value_type::array: + case value::type::array: { auto& expected_array = expected.as_array(); auto& actual_array = actual.as_array(); @@ -137,7 +137,7 @@ void assert_signalr_value_equality(const signalr::value& expected, const signalr } break; } - case value_type::binary: + case value::type::binary: { auto& expected_binary = expected.as_binary(); auto& actual_binary = actual.as_binary(); @@ -148,7 +148,7 @@ void assert_signalr_value_equality(const signalr::value& expected, const signalr } break; } - case value_type::null: + case value::type::null: break; default: ASSERT_TRUE(false); diff --git a/test/signalrclienttests/test_utils.h b/test/signalrclienttests/test_utils.h index 69f01889..c6c8ea42 100644 --- a/test/signalrclienttests/test_utils.h +++ b/test/signalrclienttests/test_utils.h @@ -14,7 +14,7 @@ std::string remove_date_from_log_entry(const std::string &log_entry); bool has_log_entry(const std::string& log_entry, const std::vector& logs); -std::function(const signalr::signalr_client_config&)> create_test_http_client(); +std::function(const signalr::signalr_client_config&)> create_test_http_client(); std::string create_uri(); std::string create_uri(const std::string& query_string); std::vector filter_vector(const std::vector& source, const std::string& string); diff --git a/test/signalrclienttests/test_websocket_client.cpp b/test/signalrclienttests/test_websocket_client.cpp index 7434f523..26aeb191 100644 --- a/test/signalrclienttests/test_websocket_client.cpp +++ b/test/signalrclienttests/test_websocket_client.cpp @@ -7,13 +7,13 @@ #include "test_utils.h" #include "signalrclient/signalr_exception.h" -std::shared_ptr create_test_websocket_client( +test_websocket_client* create_test_websocket_client( std::function)> send_function, std::function)> connect_function, std::function)> close_function, bool ignore_pings) { - auto websocket_client = std::make_shared(); + auto websocket_client = new test_websocket_client(); websocket_client->set_send_function(send_function); websocket_client->set_connect_function(connect_function); websocket_client->set_close_function(close_function); diff --git a/test/signalrclienttests/test_websocket_client.h b/test/signalrclienttests/test_websocket_client.h index f11c07a7..8927d3fc 100644 --- a/test/signalrclienttests/test_websocket_client.h +++ b/test/signalrclienttests/test_websocket_client.h @@ -46,9 +46,9 @@ class test_websocket_client : public websocket_client private: std::shared_ptr)>> m_connect_function; - std::shared_ptr < std::function)>> m_send_function; + std::shared_ptr)>> m_send_function; - std::shared_ptr < std::function)>> m_close_function; + std::shared_ptr)>> m_close_function; std::exception_ptr m_receive_exception; std::string m_receive_message; @@ -61,7 +61,7 @@ class test_websocket_client : public websocket_client std::shared_ptr m_scheduler; }; -std::shared_ptr create_test_websocket_client( +test_websocket_client* create_test_websocket_client( std::function)> send_function = [](const std::string&, std::function callback) { callback(nullptr); }, std::function)> connect_function = [](const std::string&, std::function callback) { callback(nullptr); }, std::function)> close_function = [](std::function callback) { callback(nullptr); }, bool ignore_pings = true); \ No newline at end of file diff --git a/test/signalrclienttests/websocket_transport_tests.cpp b/test/signalrclienttests/websocket_transport_tests.cpp index 20f40cc6..8b4a592b 100644 --- a/test/signalrclienttests/websocket_transport_tests.cpp +++ b/test/signalrclienttests/websocket_transport_tests.cpp @@ -31,7 +31,7 @@ TEST(websocket_transport_connect, connect_connects_and_starts_receive_loop) { client->set_config(config); return client; - }, signalr_client_config{}, logger(writer, trace_level::info)); + }, signalr_client_config{}, logger(writer, log_level::info)); auto mre = manual_reset_event(); ws_transport->start("ws://fakeuri.org/connect?param=42", [&mre](std::exception_ptr exception) @@ -69,7 +69,7 @@ TEST(websocket_transport_connect, connect_propagates_exceptions) { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); try { @@ -100,7 +100,7 @@ TEST(websocket_transport_connect, connect_logs_exceptions) { client->set_config(config); return client; - }, signalr_client_config{}, logger(writer, trace_level::error)); + }, signalr_client_config{}, logger(writer, log_level::error)); auto mre = manual_reset_event(); ws_transport->start("ws://fakeuri.org", [&mre](std::exception_ptr exception) @@ -131,7 +131,7 @@ TEST(websocket_transport_connect, cannot_call_connect_on_already_connected_trans { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->start("ws://fakeuri.org", [&mre](std::exception_ptr exception) @@ -168,7 +168,7 @@ TEST(websocket_transport_connect, can_connect_after_disconnecting) { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->start("ws://fakeuri.org", [&mre](std::exception_ptr exception) @@ -212,7 +212,7 @@ TEST(websocket_transport_send, send_creates_and_sends_websocket_messages) { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->start("ws://url", [&mre](std::exception_ptr exception) @@ -252,7 +252,7 @@ TEST(websocket_transport_disconnect, disconnect_closes_websocket) { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->start("ws://url", [&mre](std::exception_ptr exception) @@ -285,7 +285,7 @@ TEST(websocket_transport_stop, propogates_exception_from_close) { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->start("ws://url", [&mre](std::exception_ptr exception) @@ -322,7 +322,7 @@ TEST(websocket_transport_disconnect, disconnect_logs_exceptions) { client->set_config(config); return client; - }, signalr_client_config{}, logger(writer, trace_level::error)); + }, signalr_client_config{}, logger(writer, log_level::error)); auto mre = manual_reset_event(); ws_transport->start("ws://url", [&mre](std::exception_ptr exception) @@ -371,7 +371,7 @@ TEST(websocket_transport_disconnect, receive_not_called_after_disconnect) { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->start("ws://fakeuri.org", [&mre](std::exception_ptr) @@ -420,7 +420,7 @@ TEST(websocket_transport_disconnect, disconnect_is_no_op_if_transport_not_starte { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); auto mre = manual_reset_event(); ws_transport->stop([&mre](std::exception_ptr exception) @@ -433,18 +433,18 @@ TEST(websocket_transport_disconnect, disconnect_is_no_op_if_transport_not_starte } template -void receive_loop_logs_exception_runner(const T& e, const std::string& expected_message, trace_level trace_level); +void receive_loop_logs_exception_runner(const T& e, const std::string& expected_message, log_level log_level); TEST(websocket_transport_receive_loop, receive_loop_logs_std_exception) { receive_loop_logs_exception_runner( std::runtime_error("exception"), "[error ] [websocket transport] error receiving response from websocket: exception\n", - trace_level::error); + log_level::error); } template -void receive_loop_logs_exception_runner(const T& e, const std::string& expected_message, trace_level trace_level) +void receive_loop_logs_exception_runner(const T& e, const std::string& expected_message, log_level log_level) { auto client = std::make_shared(); std::shared_ptr writer(std::make_shared()); @@ -453,7 +453,7 @@ void receive_loop_logs_exception_runner(const T& e, const std::string& expected_ { client->set_config(config); return client; - }, signalr_client_config{}, logger(writer, trace_level)); + }, signalr_client_config{}, logger(writer, log_level)); auto mre = manual_reset_event(); ws_transport->start("ws://url", [&mre](std::exception_ptr exception) @@ -507,7 +507,7 @@ TEST(websocket_transport_receive_loop, process_response_callback_called_when_mes { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); ws_transport->on_receive(process_response); auto mre = manual_reset_event(); @@ -561,7 +561,7 @@ TEST(websocket_transport_receive_loop, error_callback_called_when_exception_thro { client->set_config(config); return client; - }, signalr_client_config{}, logger(std::make_shared(), trace_level::none)); + }, signalr_client_config{}, logger(std::make_shared(), log_level::none)); ws_transport->on_close(error_callback); auto mre = manual_reset_event(); @@ -588,7 +588,7 @@ TEST(websocket_transport_get_transport_type, get_transport_type_returns_websocke client->set_config(config); return client; }, signalr_client_config{}, - logger(std::make_shared(), trace_level::none)); + logger(std::make_shared(), log_level::none)); ASSERT_EQ(transport_type::websockets, ws_transport->get_transport_type()); } @@ -637,7 +637,7 @@ TEST(stop, error_from_receive_on_stop_properly_closes) auto client = std::make_shared(); return client; }, signalr_client_config{}, - logger(std::make_shared(), trace_level::none)); + logger(std::make_shared(), log_level::none)); std::atomic_int stop_called{ 0 }; std::atomic_int on_close_called{ 0 }; @@ -704,7 +704,7 @@ TEST(websocket_client_custom_impl, caching_callbacks_does_not_leak) auto client = std::make_shared(); return client; }, signalr_client_config{}, - logger(std::make_shared(), trace_level::none)); + logger(std::make_shared(), log_level::none)); ws_transport->start("ws://fakeuri.org", [](std::exception_ptr) {}); auto mre = manual_reset_event(); From 8cf0416eeec265db07be656712d87468216ace33 Mon Sep 17 00:00:00 2001 From: Brennan Conroy Date: Fri, 2 Dec 2022 15:27:31 -0800 Subject: [PATCH 3/3] wip --- include/signalrclient/http_client.h | 42 +++++---- include/signalrclient/signalr_value.h | 85 +++++++------------ src/signalrclient/connection_impl.cpp | 4 +- src/signalrclient/default_http_client.cpp | 6 +- src/signalrclient/default_http_client.h | 2 +- src/signalrclient/handshake_protocol.cpp | 3 +- src/signalrclient/http_utilities.cpp | 29 +++---- .../messagepack_hub_protocol.cpp | 2 +- src/signalrclient/negotiate.cpp | 2 +- src/signalrclient/signalr_value.cpp | 47 +++------- test/signalrclienttests/test_http_client.cpp | 2 +- test/signalrclienttests/test_http_client.h | 2 +- 12 files changed, 85 insertions(+), 141 deletions(-) diff --git a/include/signalrclient/http_client.h b/include/signalrclient/http_client.h index 9f0da04d..73241be6 100644 --- a/include/signalrclient/http_client.h +++ b/include/signalrclient/http_client.h @@ -13,39 +13,38 @@ namespace signalr { - enum class http_method - { - GET, - POST - }; - class http_request final { public: - http_method get_method() const; + enum class method + { + GET, + POST + }; + + method get_method() const noexcept; - const std::map& get_headers() const; + const std::map& get_headers() const noexcept; - const std::string& get_content() const; + const std::string& get_content() const noexcept; - std::chrono::seconds get_timeout() const; + std::chrono::seconds get_timeout() const noexcept; private: friend class negotiate; - http_method m_method; + method m_method; std::map m_headers; std::string m_content; std::chrono::seconds m_timeout; http_request() - : m_method(http_method::GET), m_timeout(std::chrono::seconds(120)) + : m_method(method::GET), m_timeout(std::chrono::seconds(120)) { } - void set_timeout(std::chrono::seconds timeout); - void set_content(const std::string& body); - void set_content(std::string&& body); - void set_headers(const std::map& headers); - void set_method(http_method method); + void set_timeout(std::chrono::seconds timeout) noexcept; + void set_content(std::string body) noexcept; + void set_headers(std::map headers) noexcept; + void set_method(method method) noexcept; }; class http_response final @@ -53,8 +52,7 @@ namespace signalr public: http_response() {} http_response(http_response&& rhs) noexcept : m_status_code(rhs.m_status_code), m_content(std::move(rhs.m_content)) {} - http_response(int code, const std::string& content) : m_status_code(code), m_content(content) {} - http_response(int code, std::string&& content) : m_status_code(code), m_content(std::move(content)) {} + http_response(int code, std::string content) : m_status_code(code), m_content(std::move(content)) {} http_response(const http_response& rhs) : m_status_code(rhs.m_status_code), m_content(rhs.m_content) {} http_response& operator=(const http_response& rhs) @@ -76,8 +74,8 @@ namespace signalr private: friend class negotiate; - int get_status_code() const; - const std::string& get_content() const; + int get_status_code() const noexcept; + const std::string& get_content() const noexcept; int m_status_code = 0; std::string m_content; @@ -86,7 +84,7 @@ namespace signalr class http_client { public: - virtual void send(const std::string& url, http_request& request, + virtual void send(const std::string& url, const http_request& request, std::function callback, cancellation_token token) = 0; virtual ~http_client() {} diff --git a/include/signalrclient/signalr_value.h b/include/signalrclient/signalr_value.h index b0c736c9..e03b0993 100644 --- a/include/signalrclient/signalr_value.h +++ b/include/signalrclient/signalr_value.h @@ -33,79 +33,54 @@ namespace signalr }; /** - * Create an object representing a value_type::null value. + * Create an object representing a value::type::null value. */ SIGNALRCLIENT_API value(); /** - * Create an object representing a value_type::null value. + * Create an object representing a value::type::null value. */ SIGNALRCLIENT_API value(std::nullptr_t); /** - * Create an object representing a default value for the given value_type. + * Create an object representing a default value for the given value::type. */ SIGNALRCLIENT_API value(type t); /** - * Create an object representing a value_type::boolean with the given bool value. + * Create an object representing a value::type::boolean with the given bool value. */ SIGNALRCLIENT_API value(bool val); /** - * Create an object representing a value_type::float64 with the given double value. + * Create an object representing a value::type::float64 with the given double value. */ SIGNALRCLIENT_API value(double val); /** - * Create an object representing a value_type::string with the given string value. + * Create an object representing a value::type::string with the given string value. */ - SIGNALRCLIENT_API value(const std::string& val); + SIGNALRCLIENT_API value(std::string val); /** - * Create an object representing a value_type::string with the given string value. - */ - SIGNALRCLIENT_API value(std::string&& val); - - /** - * Create an object representing a value_type::string with the given string value. + * Create an object representing a value::type::string with the given string value. */ SIGNALRCLIENT_API value(const char* val); /** - * Create an object representing a value_type::string with the given string value. - */ - SIGNALRCLIENT_API value(const char* val, size_t length); - - /** - * Create an object representing a value_type::array with the given vector of value's. - */ - SIGNALRCLIENT_API value(const std::vector& val); - - /** - * Create an object representing a value_type::array with the given vector of value's. - */ - SIGNALRCLIENT_API value(std::vector&& val); - - /** - * Create an object representing a value_type::map with the given map of string-value's. - */ - SIGNALRCLIENT_API value(const std::map& map); - - /** - * Create an object representing a value_type::map with the given map of string-value's. + * Create an object representing a value::type::array with the given vector of value's. */ - SIGNALRCLIENT_API value(std::map&& map); + SIGNALRCLIENT_API value(std::vector val); /** - * Create an object representing a value_type::binary with the given array of byte's. + * Create an object representing a value::type::map with the given map of string-value's. */ - SIGNALRCLIENT_API value(const std::vector& bin); + SIGNALRCLIENT_API value(std::map map); /** - * Create an object representing a value_type::binary with the given array of byte's. + * Create an object representing a value::type::binary with the given array of byte's. */ - SIGNALRCLIENT_API value(std::vector&& bin); + SIGNALRCLIENT_API value(std::vector bin); /** * Copies an existing value. @@ -120,7 +95,7 @@ namespace signalr /** * Cleans up the resources associated with the value. */ - SIGNALRCLIENT_API ~value(); + SIGNALRCLIENT_API ~value() noexcept; /** * Copies an existing value. @@ -135,70 +110,70 @@ namespace signalr /** * True if the object stored is a Key-Value pair. */ - SIGNALRCLIENT_API bool is_map() const; + SIGNALRCLIENT_API bool is_map() const noexcept; /** * True if the object stored is a double. */ - SIGNALRCLIENT_API bool is_double() const; + SIGNALRCLIENT_API bool is_double() const noexcept; /** * True if the object stored is a string. */ - SIGNALRCLIENT_API bool is_string() const; + SIGNALRCLIENT_API bool is_string() const noexcept; /** * True if the object stored is empty. */ - SIGNALRCLIENT_API bool is_null() const; + SIGNALRCLIENT_API bool is_null() const noexcept; /** * True if the object stored is an array of signalr::value's. */ - SIGNALRCLIENT_API bool is_array() const; + SIGNALRCLIENT_API bool is_array() const noexcept; /** * True if the object stored is a bool. */ - SIGNALRCLIENT_API bool is_bool() const; + SIGNALRCLIENT_API bool is_bool() const noexcept; /** * True if the object stored is a binary blob. */ - SIGNALRCLIENT_API bool is_binary() const; + SIGNALRCLIENT_API bool is_binary() const noexcept; /** - * Returns the stored object as a double. This will throw if the underlying object is not a signalr::type::float64. + * Returns the stored object as a double. This will throw if the underlying object is not a signalr::value::type::float64. */ SIGNALRCLIENT_API double as_double() const; /** - * Returns the stored object as a bool. This will throw if the underlying object is not a signalr::type::boolean. + * Returns the stored object as a bool. This will throw if the underlying object is not a signalr::value::type::boolean. */ SIGNALRCLIENT_API bool as_bool() const; /** - * Returns the stored object as a string. This will throw if the underlying object is not a signalr::type::string. + * Returns the stored object as a string. This will throw if the underlying object is not a signalr::value::type::string. */ SIGNALRCLIENT_API const std::string& as_string() const; /** - * Returns the stored object as an array of signalr::value's. This will throw if the underlying object is not a signalr::type::array. + * Returns the stored object as an array of signalr::value's. This will throw if the underlying object is not a signalr::value::type::array. */ SIGNALRCLIENT_API const std::vector& as_array() const; /** - * Returns the stored object as a map of property name to signalr::value. This will throw if the underlying object is not a signalr::type::map. + * Returns the stored object as a map of property name to signalr::value. This will throw if the underlying object is not a signalr::value::type::map. */ SIGNALRCLIENT_API const std::map& as_map() const; /** - * Returns the stored object as an array of bytes. This will throw if the underlying object is not a signalr::type::binary. + * Returns the stored object as an array of bytes. This will throw if the underlying object is not a signalr::value::type::binary. */ SIGNALRCLIENT_API const std::vector& as_binary() const; /** - * Returns the signalr::type that represents the stored object. + * Returns the signalr::value::type that represents the stored object. */ SIGNALRCLIENT_API type type() const; @@ -216,7 +191,7 @@ namespace signalr // constructor of types in union are not implicitly called // this is expected as we only construct a single type in the union once we know - // what that type is when constructing the signalr_value type. + // what that type is when constructing the signalr::value type. #pragma warning (push) #pragma warning (disable: 4582) storage() {} diff --git a/src/signalrclient/connection_impl.cpp b/src/signalrclient/connection_impl.cpp index cd5278bf..4303054f 100644 --- a/src/signalrclient/connection_impl.cpp +++ b/src/signalrclient/connection_impl.cpp @@ -304,8 +304,8 @@ namespace signalr } auto http_client = m_http_client_factory(m_signalr_client_config); - std::shared_ptr s(std::move(http_client)); - start_negotiate_internal(url, 0, transport_started, std::move(s)); + std::shared_ptr shared_client(std::move(http_client)); + start_negotiate_internal(url, 0, transport_started, std::move(shared_client)); } void connection_impl::start_negotiate_internal(const std::string& url, int redirect_count, diff --git a/src/signalrclient/default_http_client.cpp b/src/signalrclient/default_http_client.cpp index 21ccfb78..2a5cffcb 100644 --- a/src/signalrclient/default_http_client.cpp +++ b/src/signalrclient/default_http_client.cpp @@ -18,15 +18,15 @@ namespace signalr : m_config(config) { } - void default_http_client::send(const std::string& url, http_request& request, + void default_http_client::send(const std::string& url, const http_request& request, std::function callback, cancellation_token token) { web::http::method method; - if (request.get_method() == http_method::GET) + if (request.get_method() == http_request::method::GET) { method = U("GET"); } - else if (request.get_method() == http_method::POST) + else if (request.get_method() == http_request::method::POST) { method = U("POST"); } diff --git a/src/signalrclient/default_http_client.h b/src/signalrclient/default_http_client.h index afc3487d..d575bae3 100644 --- a/src/signalrclient/default_http_client.h +++ b/src/signalrclient/default_http_client.h @@ -14,7 +14,7 @@ namespace signalr public: explicit default_http_client(const signalr_client_config& config = {}) noexcept; - void send(const std::string& url, http_request& request, + void send(const std::string& url, const http_request& request, std::function callback, cancellation_token token) override; private: diff --git a/src/signalrclient/handshake_protocol.cpp b/src/signalrclient/handshake_protocol.cpp index fb8542c4..6cde6635 100644 --- a/src/signalrclient/handshake_protocol.cpp +++ b/src/signalrclient/handshake_protocol.cpp @@ -13,9 +13,10 @@ namespace signalr { std::string write_handshake(const std::unique_ptr& protocol) { + auto protocol_value = signalr::value(protocol->name()); auto map = std::map { - { "protocol", signalr::value(protocol->name()) }, + { "protocol", std::move(protocol_value) }, { "version", signalr::value((double)protocol->version()) } }; diff --git a/src/signalrclient/http_utilities.cpp b/src/signalrclient/http_utilities.cpp index 009a1d43..082e37e6 100644 --- a/src/signalrclient/http_utilities.cpp +++ b/src/signalrclient/http_utilities.cpp @@ -7,57 +7,52 @@ namespace signalr { - http_method http_request::get_method() const + http_request::method http_request::get_method() const noexcept { return m_method; } - const std::map& http_request::get_headers() const + const std::map& http_request::get_headers() const noexcept { return m_headers; } - const std::string& http_request::get_content() const + const std::string& http_request::get_content() const noexcept { return m_content; } - std::chrono::seconds http_request::get_timeout() const + std::chrono::seconds http_request::get_timeout() const noexcept { return m_timeout; } - void http_request::set_timeout(std::chrono::seconds timeout) + void http_request::set_timeout(std::chrono::seconds timeout) noexcept { m_timeout = timeout; } - void http_request::set_content(const std::string& body) + void http_request::set_content(std::string body) noexcept { - m_content = body; + m_content = std::move(body); } - void http_request::set_content(std::string&& body) + void http_request::set_headers(std::map headers) noexcept { - m_content = body; + m_headers = std::move(headers); } - void http_request::set_headers(const std::map& headers) - { - m_headers = headers; - } - - void http_request::set_method(http_method method) + void http_request::set_method(http_request::method method) noexcept { m_method = method; } - int http_response::get_status_code() const + int http_response::get_status_code() const noexcept { return m_status_code; } - const std::string& http_response::get_content() const + const std::string& http_response::get_content() const noexcept { return m_content; } diff --git a/src/signalrclient/messagepack_hub_protocol.cpp b/src/signalrclient/messagepack_hub_protocol.cpp index 471c7ee2..74fba96a 100644 --- a/src/signalrclient/messagepack_hub_protocol.cpp +++ b/src/signalrclient/messagepack_hub_protocol.cpp @@ -42,7 +42,7 @@ namespace signalr case msgpack::type::object_type::NEGATIVE_INTEGER: return signalr::value((double)v.via.i64); case msgpack::type::object_type::STR: - return signalr::value(v.via.str.ptr, v.via.str.size); + return signalr::value(std::string(v.via.str.ptr, v.via.str.size)); case msgpack::type::object_type::ARRAY: { std::vector vec; diff --git a/src/signalrclient/negotiate.cpp b/src/signalrclient/negotiate.cpp index 8015c116..4cbd8ca2 100644 --- a/src/signalrclient/negotiate.cpp +++ b/src/signalrclient/negotiate.cpp @@ -29,7 +29,7 @@ namespace signalr // TODO: signalr_client_config http_request request; - request.set_method(http_method::POST); + request.set_method(http_request::method::POST); request.set_headers(config.get_http_headers()); // TODO: timeout? // request.timeout = ; diff --git a/src/signalrclient/signalr_value.cpp b/src/signalrclient/signalr_value.cpp index 477542a0..31801ef0 100644 --- a/src/signalrclient/signalr_value.cpp +++ b/src/signalrclient/signalr_value.cpp @@ -74,12 +74,7 @@ namespace signalr mStorage.number = val; } - value::value(const std::string& val) : mType(type::string) - { - new (&mStorage.string) std::string(val); - } - - value::value(std::string&& val) : mType(type::string) + value::value(std::string val) : mType(type::string) { new (&mStorage.string) std::string(std::move(val)); } @@ -89,37 +84,17 @@ namespace signalr new (&mStorage.string) std::string(val); } - value::value(const char* val, size_t length) : mType(type::string) - { - new (&mStorage.string) std::string(val, length); - } - - value::value(const std::vector& val) : mType(type::array) - { - new (&mStorage.array) std::vector(val); - } - - value::value(std::vector&& val) : mType(type::array) + value::value(std::vector val) : mType(type::array) { new (&mStorage.array) std::vector(std::move(val)); } - value::value(const std::map& map) : mType(type::map) - { - new (&mStorage.map) std::map(map); - } - - value::value(std::map&& map) : mType(type::map) + value::value(std::map map) : mType(type::map) { new (&mStorage.map) std::map(std::move(map)); } - value::value(const std::vector& bin) : mType(type::binary) - { - new (&mStorage.binary) std::vector(bin); - } - - value::value(std::vector&& bin) : mType(type::binary) + value::value(std::vector bin) : mType(type::binary) { new (&mStorage.binary) std::vector(std::move(bin)); } @@ -277,37 +252,37 @@ namespace signalr return *this; } - bool value::is_map() const + bool value::is_map() const noexcept { return mType == signalr::value::type::map; } - bool value::is_double() const + bool value::is_double() const noexcept { return mType == signalr::value::type::float64; } - bool value::is_string() const + bool value::is_string() const noexcept { return mType == signalr::value::type::string; } - bool value::is_null() const + bool value::is_null() const noexcept { return mType == signalr::value::type::null; } - bool value::is_array() const + bool value::is_array() const noexcept { return mType == signalr::value::type::array; } - bool value::is_bool() const + bool value::is_bool() const noexcept { return mType == signalr::value::type::boolean; } - bool value::is_binary() const + bool value::is_binary() const noexcept { return mType == signalr::value::type::binary; } diff --git a/test/signalrclienttests/test_http_client.cpp b/test/signalrclienttests/test_http_client.cpp index f00845fe..1e40df3c 100644 --- a/test/signalrclienttests/test_http_client.cpp +++ b/test/signalrclienttests/test_http_client.cpp @@ -10,7 +10,7 @@ test_http_client::test_http_client(std::function callback, cancellation_token token) { auto create_response = m_http_response; diff --git a/test/signalrclienttests/test_http_client.h b/test/signalrclienttests/test_http_client.h index 564ed757..cb6b05ba 100644 --- a/test/signalrclienttests/test_http_client.h +++ b/test/signalrclienttests/test_http_client.h @@ -13,7 +13,7 @@ class test_http_client : public http_client { public: test_http_client(std::function create_http_response_fn); - void send(const std::string& url, http_request& request, + void send(const std::string& url, const http_request& request, std::function callback, cancellation_token token) override; void set_scheduler(std::shared_ptr scheduler);