// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #pragma once #include #include #include "cpprest/http_client.h" #include "signalrclient/trace_level.h" #include "signalrclient/connection_state.h" #include "signalrclient/signalr_client_config.h" #include "web_request_factory.h" #include "transport_factory.h" #include "logger.h" #include "negotiation_response.h" #include "event.h" namespace signalr { // Note: // Factory methods and private constructors prevent from using this class incorrectly. Because this class // derives from `std::enable_shared_from_this` the instance has to be owned by a `std::shared_ptr` whenever // a member method calls `std::shared_from_this()` otherwise the behavior is undefined. Therefore constructors // are private to disallow creating instances directly and factory methods return `std::shared_ptr`. class connection_impl : public std::enable_shared_from_this { public: static std::shared_ptr create(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr& log_writer); static std::shared_ptr create(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr& log_writer, std::unique_ptr web_request_factory, std::unique_ptr transport_factory); connection_impl(const connection_impl&) = delete; connection_impl& operator=(const connection_impl&) = delete; ~connection_impl(); pplx::task start(); pplx::task send(const utility::string_t &data); pplx::task stop(); connection_state get_connection_state() const; utility::string_t get_connection_id() const; void set_message_received_string(const std::function& message_received); void set_message_received_json(const std::function& message_received); void set_reconnecting(const std::function& reconnecting); void set_reconnected(const std::function& reconnected); void set_disconnected(const std::function& disconnected); void set_client_config(const signalr_client_config& config); void set_reconnect_delay(const int reconnect_delay /*milliseconds*/); void set_connection_data(const utility::string_t& connection_data); private: web::uri m_base_url; utility::string_t m_query_string; std::atomic m_connection_state; logger m_logger; std::shared_ptr m_transport; std::unique_ptr m_web_request_factory; std::unique_ptr m_transport_factory; std::function m_message_received; std::function m_reconnecting; std::function m_reconnected; std::function m_disconnected; signalr_client_config m_signalr_client_config; pplx::cancellation_token_source m_disconnect_cts; std::mutex m_stop_lock; event m_start_completed_event; utility::string_t m_connection_id; utility::string_t m_connection_data; int m_reconnect_window; // in milliseconds int m_reconnect_delay; // in milliseconds utility::string_t m_message_id; utility::string_t m_groups_token; bool m_handshakeReceived; connection_impl(const utility::string_t& url, const utility::string_t& query_string, trace_level trace_level, const std::shared_ptr& log_writer, std::unique_ptr web_request_factory, std::unique_ptr transport_factory); pplx::task> start_transport(negotiation_response negotiation_response); pplx::task send_connect_request(const std::shared_ptr& transport, const pplx::task_completion_event& connect_request_tce); void process_response(const utility::string_t& response, const pplx::task_completion_event& connect_request_tce); pplx::task shutdown(); void reconnect(); pplx::task try_reconnect(const web::uri& reconnect_url, const utility::datetime::interval_type reconnect_start_time, int reconnect_window, int reconnect_delay, pplx::cancellation_token_source disconnect_cts); bool change_state(connection_state old_state, connection_state new_state); connection_state change_state(connection_state new_state); void handle_connection_state_change(connection_state old_state, connection_state new_state); void invoke_message_received(const web::json::value& message); static utility::string_t translate_connection_state(connection_state state); void ensure_disconnected(const utility::string_t& error_message); }; }