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>;
24
31
33 virtual ~SimpleWebSocketClientAdapter() = default;
34
37
40 std::string get_http_version() override final {
41 std::lock_guard<std::mutex> lock(m_client_mutex);
42 if (m_wss_connection) return m_wss_connection->http_version;
43 if (m_ws_connection) return m_ws_connection->http_version;
44 return std::string();
45 }
46
49 Headers get_headers() override final {
50 Headers headers;
51 std::lock_guard<std::mutex> lock(m_client_mutex);
53 copy_headers(m_wss_connection->header, headers);
54 return headers;
55 }
56 if (m_ws_connection){
57 copy_headers(m_ws_connection->header, headers);
58 return headers;
59 }
60 return Headers();
61 }
62
65 std::string get_remote_endpoint() override final {
66 std::lock_guard<std::mutex> lock(m_client_mutex);
69 return std::string();
70 }
71
72 private:
73 std::mutex m_client_mutex;
74 std::shared_ptr<SimpleWeb::io_context> m_io_context;
75 std::shared_ptr<WsClient> m_ws_client;
76 std::shared_ptr<WssClient> m_wss_client;
77 std::shared_ptr<WsClient::Connection> m_ws_connection;
78 std::shared_ptr<WssClient::Connection> m_wss_connection;
79
80# ifdef BOOST_ASIO_VERSION
84 std::error_code convert_boost_to_std(const boost::system::error_code& boost_ec) {
85 return std::error_code(boost_ec.value(), std::generic_category());
86 }
87# endif
88
91 bool init_websocket() override final {
92 // Проверяем инициализацию конфигурации и контекста
93 const size_t MIN_URL_SIZE = 6;
94 if (!m_io_context ||
95 !m_config ||
96 m_config->url.size() < MIN_URL_SIZE) {
97 return false;
98 }
99
100 std::string protocol = utils::extract_protocol(m_config->url);
101 if (protocol != "wss" && protocol != "ws") {
102 return false;
103 }
104
105 try {
106 std::lock_guard<std::mutex> lock(m_client_mutex);
107 if (protocol == "wss") {
109 WssClient,
110 WssClient::Connection,
111 WssClient::InMessage>();
112 } else {
114 WsClient,
115 WsClient::Connection,
116 WsClient::InMessage>();
117 }
118 } catch(...) {
119 return false;
120 }
121
122 return true;
123 }
124
126 void deinit_websocket() override final {
127 std::lock_guard<std::mutex> lock(m_client_mutex);
128 m_wss_client.reset();
129 m_ws_client.reset();
130 m_ws_connection.reset();
131 m_wss_connection.reset();
132 }
133
136 void send_message(std::shared_ptr<WebSocketSendInfo>& send_info) override final {
137 std::unique_lock<std::mutex> lock(m_client_mutex);
139 lock.unlock();
140 if (!send_info->callback) return;
142 return;
143 }
145 else send_message(m_ws_connection, send_info);
146 }
147
150 void send_close(std::shared_ptr<WebSocketSendInfo>& send_info) override final {
151 std::unique_lock<std::mutex> lock(m_client_mutex);
153 lock.unlock();
154 if (!send_info->callback) return;
156 return;
157 }
159 else send_close(m_ws_connection, send_info);
160 };
161
166 template<class ConnectionType>
168 const ConnectionType& connection,
169 const send_info_ptr_t& send_info) {
170 connection->send(
171 send_info->message,
172 [this, send_info](const SimpleWeb::error_code &ec) {
173 if (!send_info->callback) return;
174# ifdef ASIO_STANDALONE
175 add_send_callback(ec, send_info->callback);
176# else
177 add_send_callback(convert_boost_to_std(ec), send_info->callback);
178# endif
179 });
180 }
181
186 template<class ConnectionType>
188 const ConnectionType& connection,
189 const send_info_ptr_t& send_info) {
190 connection->send_close(
191 send_info->status,
192 send_info->message,
193 [this, send_info](const SimpleWeb::error_code& ec) {
194 if (!send_info->callback) return;
195# ifdef ASIO_STANDALONE
196 add_send_callback(ec, send_info->callback);
197# else
198 add_send_callback(convert_boost_to_std(ec), send_info->callback);
199# endif
200 });
201 }
202
204 template<class ClientType, class ConnectionType, class MessageType>
205 void init_client() {
206 auto client = create_client<ClientType>();
207 client->io_service = m_io_context;
208 client->config.timeout_idle = m_config->idle_timeout;
209 client->config.timeout_request = m_config->request_timeout;
210
211 if (!m_config->headers.empty()) {
212 copy_headers(m_config->headers, client->config.header);
213 }
214 if (!m_config->user_agent.empty() &&
215 m_config->headers.find("User-Agent") == m_config->headers.end()) {
216 client->config.header.insert({"User-Agent", m_config->user_agent});
217 }
218 if (!m_config->accept_encoding.empty() &&
219 m_config->headers.find("Accept-Encoding") == m_config->headers.end()) {
220 client->config.header.insert({"Accept-Encoding", m_config->accept_encoding});
221 }
222 if (!m_config->cookie.empty() &&
223 m_config->headers.find("Cookie") == m_config->headers.end()) {
224 client->config.header.insert({"Cookie", m_config->cookie});
225 }
226 if (!m_config->proxy_server.empty()) {
227 client->config.proxy_server = m_config->proxy_server;
228 }
229 if (!m_config->proxy_auth.empty()) {
230 client->config.proxy_auth = m_config->proxy_auth;
231 }
232
233 // Настираиваем фунции обратного вызова
234 client->on_open = [this](std::shared_ptr<ConnectionType> connection) {
235 std::lock_guard<std::mutex> lock(m_client_mutex);
238 };
239
240 client->on_message = [this](
241 std::shared_ptr<ConnectionType> connection,
242 std::shared_ptr<MessageType> message) {
244 };
245
246 client->on_close = [this](
247 std::shared_ptr<ConnectionType> connection,
248 const int status,
249 const std::string &reason) {
251 };
252
253 // See http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference.html, Error Codes for error code meanings
254 client->on_error = [this](
255 std::shared_ptr<ConnectionType> connection,
256 const SimpleWeb::error_code &ec) {
258 };
259
260 client->start();
262 }
263
264 template<class T>
265 std::shared_ptr<T> create_client(
266 typename std::enable_if<std::is_same<T, WssClient>::value>::type* = 0) {
267 if (m_ws_client) m_ws_client.reset();
268 m_wss_client = std::make_shared<T>(
270 m_config->verify_cert,
271 m_config->cert_file,
272 m_config->key_file,
273 m_config->ca_file);
274 return m_wss_client;
275 }
276
277 template<class T>
278 std::shared_ptr<T> create_client(
279 typename std::enable_if<std::is_same<T, WsClient>::value>::type* = 0) {
280 if (m_wss_client) m_wss_client.reset();
281 m_ws_client = std::make_shared<T>(utils::remove_ws_prefix(m_config->url));
282 return m_ws_client;
283 }
284
285 template<class ConnectionType>
286 std::unique_ptr<WebSocketEventData> create_websocket_open_event(
287 std::shared_ptr<ConnectionType>& connection) {
288 auto websocket_event = create_websocket_event();
289 websocket_event->event_type = WebSocketEventType::WS_OPEN;
290 websocket_event->status_code = static_cast<long>(SimpleWeb::status_code(connection->status_code));
291 return websocket_event;
292 }
293
294 template<class MessageType>
295 std::unique_ptr<WebSocketEventData> create_websocket_message_event(
296 std::shared_ptr<MessageType>& message) {
297 auto websocket_event = create_websocket_event();
298 websocket_event->event_type = WebSocketEventType::WS_MESSAGE;
299 websocket_event->message = message->string();
300 return websocket_event;
301 }
302
303 template<class T>
305 std::shared_ptr<T> &connection,
306 typename std::enable_if<std::is_same<T, WssClient::Connection>::value>::type* = 0) {
307 m_wss_connection = connection;
308 }
309
310 template<class T>
312 std::shared_ptr<T> &connection,
313 typename std::enable_if<std::is_same<T, WsClient::Connection>::value>::type* = 0) {
314 m_ws_connection = connection;
315 }
316
317 template<class ConnectionType>
318 std::string endpoint_to_string(const std::shared_ptr<ConnectionType>& connection) const {
319 return connection->remote_endpoint().address().to_string() + ":" +
320 std::to_string(connection->remote_endpoint().port());
321 }
322
323 template<typename SrcMap, typename DstMap>
324 void copy_headers(const SrcMap& src, DstMap& dst) {
325 dst.clear();
326 for (const auto& header : src) {
327 dst.insert(header);
328 }
329 }
330 };
331
332}; // namespace kurlyk
333
334#endif // _KURLYK_SIMPLE_WEB_SOCKET_CLIENT_ADAPTER_HPP_INCLUDED
bool send_message(const std::string &message, long rate_limit_id, std::function< void(const std::error_code &ec)> callback=nullptr) override final
Sends a message through the WebSocket.
std::unique_ptr< WebSocketEventData > create_websocket_event()
Creates a generic WebSocket event.
BaseWebSocketClient()=default
Default constructor.
bool send_close(const int status=1000, const std::string &reason=std::string(), std::function< void(const std::error_code &ec)> callback=nullptr) override final
Sends a close request through the WebSocket.
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.