25#ifndef _KURLYK_EMSCRIPTEN_WEB_SOCKET_CLIENT_ADAPTER_HPP_INCLUDED
26#define _KURLYK_EMSCRIPTEN_WEB_SOCKET_CLIENT_ADAPTER_HPP_INCLUDED
30#include <emscripten/fetch.h>
31#include <emscripten/websocket.h>
32#include <system_error>
60 std::function<void(std::unique_ptr<WebSocketEventData>)>&
event_handler() override final {
67 bool set_config(std::unique_ptr<WebSocketConfig> config)
override final {
69 std::lock_guard<std::mutex> lock1(
m_client_mutex, std::adopt_lock);
70 std::lock_guard<std::mutex> lock2(
m_config_mutex, std::adopt_lock);
117 const std::string &message,
118 const RateLimitType& rate_limit_type = RateLimitType::General,
119 std::function<
void(
const std::error_code& ec)> callback =
nullptr) override final {
120 if (message.empty())
return false;
123# if __cplusplus >= 201402L
124 m_message_queue.push_back(std::make_shared<WebSocketSendInfo>(message, rate_limit_type,
false, 0, callback));
137 const int status = 1000,
138 const std::string &reason = std::string(),
139 std::function<
void(
const std::error_code& ec)> callback =
nullptr) override final {
142# if __cplusplus >= 201402L
143 m_message_queue.push_back(std::make_shared<WebSocketSendInfo>(reason, RateLimitType::General,
true, status, callback));
164 std::unique_ptr<WebSocketEventData>
event = std::move(*
m_event_queue.begin());
171 process_update_config();
216 std::function<void(std::unique_ptr<WebSocketEventData>)>
m_on_event;
242 if (!emscripten_websocket_is_supported()) {
243 send_event_websocket_error(std::error_code(10022, std::system_category()));
249 send_event_websocket_error(std::error_code(10022, std::system_category()));
256 std::vector<const char*> protocols_c_str;
257 for (
const auto& protocol :
m_config->protocols) {
258 protocols_c_str.push_back(protocol.c_str());
262 if (
m_config->m_config->protocols.empty() &&
263 m_config->headers.find(
"Sec-WebSocket-Protocol") !=
m_config->headers.end()) {
265 std::string protocol_header =
m_config->headers[
"Sec-WebSocket-Protocol"];
268 std::stringstream ss(protocol_header);
269 std::string protocol;
270 while (std::getline(ss, protocol,
',')) {
272 protocol.erase(0, protocol.find_first_not_of(
' '));
273 protocol.erase(protocol.find_last_not_of(
' ') + 1);
275 protocols_c_str.push_back(protocol.c_str());
279 protocols_c_str.push_back(
nullptr);
281 EmscriptenWebSocketCreateAttributes ws_attrs = {
283 protocols_c_str.data(),
289 send_event_websocket_error(std::error_code(10022, std::system_category()));
303 lock_message.unlock();
314 lock_client.unlock();
316 send_event_websocket_error(std::error_code(995, std::system_category()));
327 std::list<send_info_ptr_t> message_queue;
330 auto& send_info = *it;
336 message_queue.push_back(std::move(send_info));
340 if (message_queue.empty())
return;
343 EMSCRIPTEN_RESULT result;
344 for (
const auto &send_info : message_queue) {
348 if (!send_info->callback)
continue;
349 send_info->callback(std::make_error_code(std::errc::not_connected));
355 if (send_info->is_send_close) {
357 result = emscripten_websocket_close(
m_client_ws, send_info->status,
"normal closure");
359 if (!send_info->callback)
continue;
360 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
361 send_info->callback(std::make_error_code(std::errc::not_connected));
364 send_info->callback(ec);
371 result = emscripten_websocket_send_binary(
m_client_ws, send_info->message.c_str(), send_info->message.size());
373 if (!send_info->callback)
continue;
374 if (result != EMSCRIPTEN_RESULT_SUCCESS) {
375 send_info->callback(std::make_error_code(std::errc::not_connected));
378 send_info->callback(ec);
393 for (
auto &event : event_queue) {
486 const EmscriptenWebSocketOpenEvent* event_data,
489 if (client) client->on_open(event_data);
495 const EmscriptenWebSocketCloseEvent* event_data,
498 if (client) client->on_close(event_data);
504 const EmscriptenWebSocketErrorEvent* event_data,
507 if (client) client->on_error(event_data);
513 const EmscriptenWebSocketMessageEvent* event_data,
516 if (client) client->on_message(event_data);
522 void on_open(
const EmscriptenWebSocketOpenEvent* event_data) {
529 void on_message(
const EmscriptenWebSocketMessageEvent* event_data) {
534 void on_error(
const EmscriptenWebSocketErrorEvent* event_data) {
543 void on_close(
const EmscriptenWebSocketCloseEvent* event_data) {
554# if __cplusplus >= 201402L
555 auto event = std::make_unique<WebSocketEventData>();
559 event->sender = shared_from_this();
564 const EmscriptenWebSocketOpenEvent* event_data) {
566 event->event_type = WebSocketEventType::Open;
571 const EmscriptenWebSocketMessageEvent* event_data) {
573 event->event_type = WebSocketEventType::Message;
574 event->message.assign(event_data->data, event_data->numBytes);
579 const EmscriptenWebSocketErrorEvent* event_data) {
581 event->event_type = WebSocketEventType::Error;
582 event->error_code = std::error_code(995, std::system_category());
587 const EmscriptenWebSocketCloseEvent* event_data) {
589 event->event_type = WebSocketEventType::Close;
590 event->reason = event_data->reason;
591 event->status_code = event_data->code;
std::chrono::steady_clock::time_point time_point_t
std::unique_ptr< WebSocketEventData > create_websocket_event(const EmscriptenWebSocketErrorEvent *event_data)
std::unique_ptr< WebSocketConfig > m_config
bool send_message(const std::string &message, const RateLimitType &rate_limit_type=RateLimitType::General, std::function< void(const std::error_code &ec)> callback=nullptr) override final
Send a message through the WebSocket.
std::mutex m_config_mutex
std::shared_ptr< WebSocketSendInfo > send_info_ptr_t
std::unique_ptr< WebSocketEventData > create_websocket_event(const EmscriptenWebSocketMessageEvent *event_data)
std::list< event_data_ptr_t > m_event_queue
void on_error(const EmscriptenWebSocketErrorEvent *event_data)
std::unique_ptr< WebSocketEventData > receive_event() override final
Retrieve the next pending event.
std::mutex m_message_queue_mutex
void process_handle_event()
Process the events queue.
void process() override final
Process pending operations such as connecting, sending, and handling events.
std::list< send_info_ptr_t > m_message_queue
void disconnect() override final
Disconnect from the WebSocket server.
std::shared_ptr< WssClient::Connection > m_wss_connection
time_point_t m_start_time
void operator=(const EmscriptenWebSocketClientAdapter &)=delete
std::atomic< bool > m_is_connection_active
std::unique_ptr< WebSocketEventData > create_websocket_event()
static EM_BOOL on_message_cb(int event_type, const EmscriptenWebSocketMessageEvent *event_data, void *user_data)
std::function< void(std::unique_ptr< WebSocketEventData >)> & event_handler() override final
Accessor for the event handler function.
void on_message(const EmscriptenWebSocketMessageEvent *event_data)
static EM_BOOL on_close_cb(int event_type, const EmscriptenWebSocketCloseEvent *event_data, void *user_data)
static EM_BOOL on_error_cb(int event_type, const EmscriptenWebSocketErrorEvent *event_data, void *user_data)
void reset() override final
Reset the WebSocket client state.
~EmscriptenWebSocketClientAdapter() override final
Destructor: Cleans up resources and resets the WebSocket client state.
enum kurlyk::EmscriptenWebSocketClientAdapter::WebSocketState m_ws_state
std::unique_ptr< WebSocketConfig > m_pending_config
bool set_config(std::unique_ptr< WebSocketConfig > config) override final
Sets the WebSocket configuration.
void connect() override final
Initiate connection to the WebSocket server.
std::list< std::unique_ptr< WebSocketEventData > > receive_events() override final
Retrieve all pending events.
static EM_BOOL on_open_cb(int event_type, const EmscriptenWebSocketOpenEvent *event_data, void *user_data)
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
Send a close request through the WebSocket.
WebSocketState
State for the WebSocket connection.
@ STOPPED
Connection stopped.
@ WORKING
Connection is active.
@ CONNECTING
Waiting for connection establishment.
@ DISCONNECTING
Waiting for disconnection.
enum kurlyk::EmscriptenWebSocketClientAdapter::FsmState m_fsm_state
EmscriptenWebSocketClientAdapter(const EmscriptenWebSocketClientAdapter &)=delete
void process_fsm_connecting()
void on_close(const EmscriptenWebSocketCloseEvent *event_data)
std::unique_ptr< WebSocketEventData > create_websocket_event(const EmscriptenWebSocketCloseEvent *event_data)
std::atomic< bool > m_is_running
FsmState
Finite state machine states controlling client workflow.
@ WORKING
Connection active.
@ CONNECTING
Waiting for connection.
@ RECONNECTING
Attempting reconnection.
void process_message_queue()
Process the queue of messages waiting to be sent.
const bool is_connected() override final
Checks if the WebSocket is connected.
EmscriptenWebSocketClientAdapter()
Constructor: Initializes the WebSocket client.
WebSocketRateLimiter m_rate_limiter
std::function< void(std::unique_ptr< WebSocketEventData >)> m_on_event
std::mutex m_client_mutex
FsmEvent
Represents events in the finite state machine.
@ ConnectionError
Connection error occurred.
@ UpdateConfig
Configuration update requested.
@ ConnectionClosed
Connection closed.
@ RequestConnect
Request to connect.
@ RequestDisconnect
Request to disconnect.
@ ConnectionOpened
Connection opened.
std::unique_ptr< WebSocketEventData > event_data_ptr_t
std::shared_ptr< WsClient::Connection > m_ws_connection
EMSCRIPTEN_WEBSOCKET_T m_client_ws
void on_open(const EmscriptenWebSocketOpenEvent *event_data)
std::unique_ptr< WebSocketEventData > create_websocket_event(const EmscriptenWebSocketOpenEvent *event_data)
utils::EventQueue< FsmEvent > m_fsm_event_queue
const bool is_running() override final
Checks if the client is currently running.
Interface for a WebSocket client, providing methods for connection management, configuration,...
Encapsulates data for a WebSocket event, providing information about event type, message,...
Manages rate limiting for WebSocket requests based on predefined limits.
Holds information for sending a WebSocket message, including rate limiting, close status,...
A thread-safe event queue that supports blocking and non-blocking event retrieval.
bool is_valid_url(const std::string &url, const std::vector< std::string > &protocol)
Validates if a URL is correctly formatted.
Primary namespace for the Kurlyk library, encompassing initialization, request management,...
RateLimitType
Defines rate limit scope categories.