Kurlyk
Loading...
Searching...
No Matches
SimpleWebSocketClientAdapter.hpp
Go to the documentation of this file.
1#pragma once
2#ifndef _KURLYK_SIMPLE_WEB_SOCKET_CLIENT_ADAPTER_HPP_INCLUDED
3#define _KURLYK_SIMPLE_WEB_SOCKET_CLIENT_ADAPTER_HPP_INCLUDED
4
11
12namespace kurlyk {
13
19 public:
20 using WsClient = SimpleWeb::SocketClient<SimpleWeb::WS>;
21 using WssClient = SimpleWeb::SocketClient<SimpleWeb::WSS>;
22
29
31 virtual ~SimpleWebSocketClientAdapter() = default;
32
35
38 std::string get_http_version() override final {
39 std::lock_guard<std::mutex> lock(m_client_mutex);
40 if (m_wss_connection) return m_wss_connection->http_version;
41 if (m_ws_connection) return m_ws_connection->http_version;
42 return std::string();
43 }
44
47 Headers get_headers() override final {
48 Headers headers;
49 std::lock_guard<std::mutex> lock(m_client_mutex);
51 copy_headers(m_wss_connection->header, headers);
52 return headers;
53 }
54 if (m_ws_connection){
55 copy_headers(m_ws_connection->header, headers);
56 return headers;
57 }
58 return Headers();
59 }
60
63 std::string get_remote_endpoint() override final {
64 std::lock_guard<std::mutex> lock(m_client_mutex);
67 return std::string();
68 }
69
70 private:
71 std::mutex m_client_mutex;
72 std::shared_ptr<SimpleWeb::io_context> m_io_context;
73 std::shared_ptr<WsClient> m_ws_client;
74 std::shared_ptr<WssClient> m_wss_client;
75 std::shared_ptr<WsClient::Connection> m_ws_connection;
76 std::shared_ptr<WssClient::Connection> m_wss_connection;
77
78# ifdef BOOST_ASIO_VERSION
82 std::error_code convert_boost_to_std(const boost::system::error_code& boost_ec) {
83 return std::error_code(boost_ec.value(), std::generic_category());
84 }
85# endif
86
89 bool init_websocket() override final {
90 // Проверяем инициализацию конфигурации и контекста
91 const size_t MIN_URL_SIZE = 6;
92 if (!m_io_context ||
93 !m_config ||
94 m_config->url.size() < MIN_URL_SIZE) {
95 return false;
96 }
97
98 std::string protocol = utils::extract_protocol(m_config->url);
99 if (protocol != "wss" && protocol != "ws") {
100 return false;
101 }
102
103 try {
104 std::lock_guard<std::mutex> lock(m_client_mutex);
105 if (protocol == "wss") {
107 WssClient,
108 WssClient::Connection,
109 WssClient::InMessage>();
110 } else {
112 WsClient,
113 WsClient::Connection,
114 WsClient::InMessage>();
115 }
116 } catch(...) {
117 return false;
118 }
119
120 return true;
121 }
122
124 void deinit_websocket() override final {
125 std::lock_guard<std::mutex> lock(m_client_mutex);
126 m_wss_client.reset();
127 m_ws_client.reset();
128 m_ws_connection.reset();
129 m_wss_connection.reset();
130 }
131
134 void send_message(std::shared_ptr<WebSocketSendInfo>& send_info) override final {
135 std::unique_lock<std::mutex> lock(m_client_mutex);
137 lock.unlock();
138 if (!send_info->callback) return;
140 return;
141 }
143 else send_message(m_ws_connection, send_info);
144 }
145
148 void send_close(std::shared_ptr<WebSocketSendInfo>& send_info) override final {
149 std::unique_lock<std::mutex> lock(m_client_mutex);
151 lock.unlock();
152 if (!send_info->callback) return;
154 return;
155 }
157 else send_close(m_ws_connection, send_info);
158 };
159
164 template<class ConnectionType>
166 const ConnectionType& connection,
167 const send_info_ptr_t& send_info) {
168 connection->send(
169 send_info->message,
170 [this, send_info](const SimpleWeb::error_code &ec) {
171 if (!send_info->callback) return;
172# ifdef ASIO_STANDALONE
173 add_send_callback(ec, send_info->callback);
174# else
175 add_send_callback(convert_boost_to_std(ec), send_info->callback);
176# endif
177 });
178 }
179
184 template<class ConnectionType>
186 const ConnectionType& connection,
187 const send_info_ptr_t& send_info) {
188 connection->send_close(
189 send_info->status,
190 send_info->message,
191 [this, send_info](const SimpleWeb::error_code& ec) {
192 if (!send_info->callback) return;
193# ifdef ASIO_STANDALONE
194 add_send_callback(ec, send_info->callback);
195# else
196 add_send_callback(convert_boost_to_std(ec), send_info->callback);
197# endif
198 });
199 }
200
202 template<class ClientType, class ConnectionType, class MessageType>
203 void init_client() {
204 auto client = create_client<ClientType>();
205 client->io_service = m_io_context;
206 client->config.timeout_idle = m_config->idle_timeout;
207 client->config.timeout_request = m_config->request_timeout;
208
209 if (!m_config->headers.empty()) {
210 copy_headers(m_config->headers, client->config.header);
211 }
212 if (!m_config->user_agent.empty() &&
213 m_config->headers.find("User-Agent") == m_config->headers.end()) {
214 client->config.header.insert({"User-Agent", m_config->user_agent});
215 }
216 if (!m_config->accept_encoding.empty() &&
217 m_config->headers.find("Accept-Encoding") == m_config->headers.end()) {
218 client->config.header.insert({"Accept-Encoding", m_config->accept_encoding});
219 }
220 if (!m_config->cookie.empty() &&
221 m_config->headers.find("Cookie") == m_config->headers.end()) {
222 client->config.header.insert({"Cookie", m_config->cookie});
223 }
224 if (!m_config->proxy_server.empty()) {
225 client->config.proxy_server = m_config->proxy_server;
226 }
227 if (!m_config->proxy_auth.empty()) {
228 client->config.proxy_auth = m_config->proxy_auth;
229 }
230
231 // Настираиваем фунции обратного вызова
232 client->on_open = [this](std::shared_ptr<ConnectionType> connection) {
233 std::lock_guard<std::mutex> lock(m_client_mutex);
236 };
237
238 client->on_message = [this](
239 std::shared_ptr<ConnectionType> connection,
240 std::shared_ptr<MessageType> message) {
242 };
243
244 client->on_close = [this](
245 std::shared_ptr<ConnectionType> connection,
246 const int status,
247 const std::string &reason) {
249 };
250
251 // See http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference.html, Error Codes for error code meanings
252 client->on_error = [this](
253 std::shared_ptr<ConnectionType> connection,
254 const SimpleWeb::error_code &ec) {
256 };
257
258 client->start();
260 }
261
262 template<class T>
263 std::shared_ptr<T> create_client(
264 typename std::enable_if<std::is_same<T, WssClient>::value>::type* = 0) {
265 if (m_ws_client) m_ws_client.reset();
266 m_wss_client = std::make_shared<T>(
268 m_config->verify_cert,
269 m_config->cert_file,
270 m_config->key_file,
271 m_config->ca_file);
272 return m_wss_client;
273 }
274
275 template<class T>
276 std::shared_ptr<T> create_client(
277 typename std::enable_if<std::is_same<T, WsClient>::value>::type* = 0) {
278 if (m_wss_client) m_wss_client.reset();
279 m_ws_client = std::make_shared<T>(utils::remove_ws_prefix(m_config->url));
280 return m_ws_client;
281 }
282
283 template<class ConnectionType>
284 std::unique_ptr<WebSocketEventData> create_websocket_open_event(
285 std::shared_ptr<ConnectionType>& connection) {
286 auto websocket_event = create_websocket_event();
287 websocket_event->event_type = WebSocketEventType::WS_OPEN;
288 websocket_event->status_code = static_cast<long>(SimpleWeb::status_code(connection->status_code));
289 return websocket_event;
290 }
291
292 template<class MessageType>
293 std::unique_ptr<WebSocketEventData> create_websocket_message_event(
294 std::shared_ptr<MessageType>& message) {
295 auto websocket_event = create_websocket_event();
296 websocket_event->event_type = WebSocketEventType::WS_MESSAGE;
297 websocket_event->message = message->string();
298 return websocket_event;
299 }
300
301 template<class T>
303 std::shared_ptr<T> &connection,
304 typename std::enable_if<std::is_same<T, WssClient::Connection>::value>::type* = 0) {
305 m_wss_connection = connection;
306 }
307
308 template<class T>
310 std::shared_ptr<T> &connection,
311 typename std::enable_if<std::is_same<T, WsClient::Connection>::value>::type* = 0) {
312 m_ws_connection = connection;
313 }
314
315 template<class ConnectionType>
316 std::string endpoint_to_string(const std::shared_ptr<ConnectionType>& connection) const {
317 return connection->remote_endpoint().address().to_string() + ":" +
318 std::to_string(connection->remote_endpoint().port());
319 }
320
321 template<typename SrcMap, typename DstMap>
322 void copy_headers(const SrcMap& src, DstMap& dst) {
323 dst.clear();
324 for (const auto& header : src) {
325 dst.insert(header);
326 }
327 }
328 };
329
330}; // namespace kurlyk
331
332#endif // _KURLYK_SIMPLE_WEB_SOCKET_CLIENT_ADAPTER_HPP_INCLUDED
std::unique_ptr< WebSocketEventData > create_websocket_event()
Creates a generic WebSocket event.
BaseWebSocketClient()=default
Default constructor.
std::unique_ptr< WebSocketEventData > create_websocket_close_event(const std::string &reason="Normal Closure", int status_code=1000)
Creates a WebSocket close event with a specified reason and status code.
void add_fsm_event(FsmEvent event_type, std::unique_ptr< WebSocketEventData > event_data)
Adds an FSM event to the event queue and triggers the notify handler.
std::unique_ptr< WebSocketConfig > m_config
Current configuration for the WebSocket.
std::shared_ptr< WebSocketSendInfo > send_info_ptr_t
Alias for shared pointers to WebSocketSendInfo.
@ MessageReceived
Incoming WebSocket message.
@ ConnectionOpened
Connection opened successfully.
std::unique_ptr< WebSocketEventData > create_websocket_error_event(const std::error_code &error_code)
Creates a WebSocket error event with a specified error code.
void operator=(const SimpleWebSocketClientAdapter &)=delete
SimpleWeb::SocketClient< SimpleWeb::WSS > WssClient
SimpleWebSocketClientAdapter()
Constructs the WebSocket client and initializes the io_context.
void deinit_websocket() override final
Deinitializes the WebSocket connection.
Headers get_headers() override final
Retrieves the headers associated with the WebSocket connection.
std::shared_ptr< SimpleWeb::io_context > m_io_context
SimpleWeb::SocketClient< SimpleWeb::WS > WsClient
void copy_headers(const SrcMap &src, DstMap &dst)
void init_connection(std::shared_ptr< T > &connection, typename std::enable_if< std::is_same< T, WssClient::Connection >::value >::type *=0)
void send_close(const ConnectionType &connection, const send_info_ptr_t &send_info)
Helper to send a close request on a specific connection type.
std::shared_ptr< WssClient::Connection > m_wss_connection
std::shared_ptr< T > create_client(typename std::enable_if< std::is_same< T, WssClient >::value >::type *=0)
std::shared_ptr< WsClient::Connection > m_ws_connection
virtual ~SimpleWebSocketClientAdapter()=default
Default destructor for cleanup.
void init_client()
Initializes a WebSocket client based on the provided type and sets up callbacks.
std::shared_ptr< T > create_client(typename std::enable_if< std::is_same< T, WsClient >::value >::type *=0)
void send_message(std::shared_ptr< WebSocketSendInfo > &send_info) override final
Sends a WebSocket message.
std::string get_http_version() override final
Retrieves the HTTP version used in the WebSocket connection.
SimpleWebSocketClientAdapter(const SimpleWebSocketClientAdapter &)=delete
std::unique_ptr< WebSocketEventData > create_websocket_message_event(std::shared_ptr< MessageType > &message)
std::string get_remote_endpoint() override final
Retrieves the remote endpoint information.
void send_close(std::shared_ptr< WebSocketSendInfo > &send_info) override final
Sends a WebSocket close request.
std::unique_ptr< WebSocketEventData > create_websocket_open_event(std::shared_ptr< ConnectionType > &connection)
void init_connection(std::shared_ptr< T > &connection, typename std::enable_if< std::is_same< T, WsClient::Connection >::value >::type *=0)
bool init_websocket() override final
Initializes and starts a WebSocket connection.
std::string endpoint_to_string(const std::shared_ptr< ConnectionType > &connection) const
void send_message(const ConnectionType &connection, const send_info_ptr_t &send_info)
Helper to send a message on a specific connection type.
void notify()
Notifies the worker to check for pending tasks.
void start()
Starts the worker thread if it is not already running.
static SimpleWebSocketWorker & get_instance()
Get the singleton instance of SimpleWebSocketWorker.
std::shared_ptr< SimpleWeb::io_context > get_io_context()
Provides access to the I/O context for WebSocket operations.
@ NotConnected
Operation requires an active connection but none exists.
std::string extract_protocol(const std::string &url)
Extracts the protocol from a URL.
Definition url_utils.hpp:13
std::error_code make_error_code(ClientError e)
Creates a std::error_code from a ClientError value.
std::string remove_ws_prefix(const std::string &url)
Removes the first occurrence of "wss://" or "ws://" from the given URL.
Definition url_utils.hpp:27
Primary namespace for the Kurlyk library, encompassing initialization, request management,...
@ WS_MESSAGE
Message received.
Definition enums.hpp:33
@ WS_OPEN
Connection established.
Definition enums.hpp:32
utils::CaseInsensitiveMultimap Headers
Alias for HTTP headers, providing a case-insensitive unordered multimap.