Files
MARTe-Integrated-Components/Client/streamhub/WSClient.h
T
2026-06-12 15:25:13 +02:00

101 lines
2.8 KiB
C++

/**
* @file WSClient.h
* @brief RFC 6455 WebSocket client (POSIX sockets, background receive thread).
*
* The receive thread continuously reads frames and places them in a queue.
* The main (ImGui) thread drains the queue each frame and also sends frames.
*
* Reuses WSFrame.h / SHA1.h / Base64.h from Source/Applications/StreamHub/.
*/
#pragma once
#include <string>
#include <vector>
#include <queue>
#include <mutex>
#include <thread>
#include <functional>
#include <atomic>
#include <cstdint>
namespace StreamHubClient {
/**
* @brief A received WebSocket frame.
*/
struct WSMessage {
bool isBinary;
std::vector<uint8_t> data; ///< Payload bytes (text frames are also stored here)
};
/**
* @brief Minimal RFC 6455 WebSocket client.
*
* Usage:
* WSClient ws;
* ws.connect("127.0.0.1", 8090);
* // main loop:
* ws.poll(handler); // drain received messages
* ws.sendText(json); // send a JSON command
* ws.disconnect();
*/
class WSClient {
public:
WSClient();
~WSClient();
/**
* @brief (Re)connect to host:port in the background.
* Non-blocking — sets a reconnect target; the receive thread handles the actual
* connect/reconnect loop.
*/
void connect(const std::string& host, uint16_t port);
/** @brief Gracefully close the WebSocket connection and stop the receive thread. */
void disconnect();
/**
* @brief Non-blocking reconnect to a (possibly new) host:port.
* Closes the current socket so the background thread detects the drop and
* reconnects immediately. Does NOT join the thread — safe to call from the UI.
*/
void reconnect(const std::string& host, uint16_t port);
/** @return true if the WebSocket handshake completed and the connection is open. */
bool isConnected() const;
/**
* @brief Drain all pending received messages and pass each to `handler`.
* Must be called from the main thread.
*/
void poll(const std::function<void(const WSMessage&)>& handler);
/** @brief Send a JSON text frame. Thread-safe. */
void sendText(const std::string& json);
/** @brief Send a binary frame. Thread-safe. */
void sendBinary(const uint8_t* data, size_t len);
private:
void recvLoop();
bool doConnect();
bool doHandshake();
bool recvExact(uint8_t* buf, size_t len);
bool sendRaw(const uint8_t* buf, size_t len);
std::string host_;
uint16_t port_ = 0;
int sock_ = -1;
std::atomic<bool> connected_ {false};
std::atomic<bool> stopThread_ {false};
std::atomic<bool> reconnect_ {false};
std::thread recvThread_;
mutable std::mutex sendMutex_;
mutable std::mutex queueMutex_;
std::queue<WSMessage> recvQueue_;
};
} /* namespace StreamHubClient */