132 lines
6.5 KiB
C
132 lines
6.5 KiB
C
#ifndef FUSED_WS_CLIENT_H
|
|
#define FUSED_WS_CLIENT_H
|
|
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <pthread.h>
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/err.h>
|
|
#include "book.h"
|
|
#include "config.h"
|
|
#include "hash.h"
|
|
#include "evaluate.h"
|
|
#include "fill_handler.h"
|
|
|
|
#define MAX_BALANCE_ENTRIES 64
|
|
|
|
typedef struct {
|
|
char currency[16];
|
|
double available;
|
|
} balance_entry_t;
|
|
|
|
#define WS_MAX_FRAME_SIZE (128 * 1024)
|
|
#define WS_MAX_CONNECTIONS 8
|
|
#define WS_READ_BUF_SIZE (64 * 1024)
|
|
|
|
/* WebSocket connection state machine */
|
|
typedef enum {
|
|
WS_STATE_DISCONNECTED, /* not connected */
|
|
WS_STATE_CONNECTING, /* TCP/TLS handshake in progress */
|
|
WS_STATE_GETTING_TOKEN, /* awaiting KuCoin WebSocket token */
|
|
WS_STATE_SUBSCRIBING, /* sending subscription messages */
|
|
WS_STATE_CONNECTED, /* fully connected and subscribed */
|
|
WS_STATE_CLOSING /* graceful close in progress */
|
|
} ws_state_t;
|
|
|
|
/* State for a single WebSocket connection */
|
|
typedef struct {
|
|
int fd; /* TCP socket fd */
|
|
SSL *ssl; /* OpenSSL SSL object */
|
|
SSL_CTX *ctx; /* OpenSSL SSL context */
|
|
BIO *bio_mem; /* memory BIO for SSL read buffering */
|
|
BIO *bio_ssl; /* SSL BIO */
|
|
BIO *bio_socket; /* socket BIO */
|
|
|
|
char host[256]; /* WebSocket server hostname */
|
|
int port; /* WebSocket server port */
|
|
char token[256]; /* KuCoin connection token */
|
|
char connect_id[64]; /* KuCoin connection ID */
|
|
uint32_t ping_interval_ms; /* negotiated ping interval (ms) */
|
|
uint32_t ping_timeout_ms; /* ping response timeout (ms) */
|
|
|
|
ws_state_t state; /* current connection state */
|
|
uint64_t last_ping_ms; /* timestamp of last sent ping */
|
|
uint64_t last_activity_ms; /* timestamp of last rx/tx activity */
|
|
uint32_t reconnect_count; /* consecutive reconnection count */
|
|
double reconnect_delay; /* current reconnect backoff delay */
|
|
double reconnect_base_delay; /* initial reconnect delay */
|
|
double reconnect_max_delay; /* max reconnect delay */
|
|
|
|
uint8_t read_buf[WS_READ_BUF_SIZE]; /* raw socket read buffer */
|
|
size_t read_pos; /* current read position */
|
|
size_t read_len; /* bytes available in read_buf */
|
|
|
|
uint8_t frame_buf[WS_MAX_FRAME_SIZE]; /* reassembled WebSocket frame */
|
|
size_t frame_payload_len; /* payload length of current frame */
|
|
bool frame_finished; /* true when full frame received */
|
|
uint8_t frame_opcode; /* opcode of current frame */
|
|
int64_t t_sock_arrive_ms; /* wall-clock when last SSL_read returned */
|
|
|
|
uint16_t symbol_indices[MAX_SYMBOLS]; /* subscribed symbol indices */
|
|
uint32_t symbol_count; /* number of subscribed symbols */
|
|
} ws_connection_t;
|
|
|
|
/* Top-level WebSocket client managing multiple connections */
|
|
typedef struct {
|
|
ws_connection_t connections[WS_MAX_CONNECTIONS]; /* fixed-size connection pool */
|
|
uint32_t connection_count; /* number of active connections */
|
|
const config_t *cfg; /* pointer to configuration */
|
|
symbol_table_t *symbols; /* pointer to symbol table */
|
|
order_book_t *books; /* pointer to shared order books */
|
|
evaluator_t *evaluator; /* pointer to evaluator */
|
|
bool running; /* false signals client to stop */
|
|
fill_channel_t *fill_ch; /* fill event channel (hot→executor) */
|
|
int fill_drop_warn; /* rate-limited fill drop warning counter */
|
|
balance_entry_t balance_cache[MAX_BALANCE_ENTRIES]; /* latest available balances from WS */
|
|
int balance_count;
|
|
pthread_mutex_t balance_lock;
|
|
int balance_wake_fd; /* eventfd: written on every balance update */
|
|
} ws_client_t;
|
|
|
|
/* Initialise a WebSocket client with config, symbol table, books, and evaluator */
|
|
int ws_client_init(ws_client_t *client, const config_t *cfg,
|
|
symbol_table_t *symbols, order_book_t *books,
|
|
evaluator_t *evaluator);
|
|
/* Destroy WebSocket client and close all connections */
|
|
void ws_client_destroy(ws_client_t *client);
|
|
/* Initiate a WebSocket connection (non-blocking) */
|
|
int ws_client_connect(ws_client_t *client, uint32_t conn_idx);
|
|
/* Disconnect a WebSocket connection */
|
|
void ws_client_disconnect(ws_client_t *client, uint32_t conn_idx);
|
|
/* Read and process data from a WebSocket connection */
|
|
int ws_client_read(ws_client_t *client, uint32_t conn_idx);
|
|
/* Write raw data to a WebSocket connection */
|
|
int ws_client_write(ws_connection_t *conn, const void *data, size_t len);
|
|
/* Subscribe to a set of symbols on a connection */
|
|
int ws_client_subscribe(ws_client_t *client, uint32_t conn_idx,
|
|
const uint16_t *symbol_indices, uint32_t count);
|
|
/* Unsubscribe from a set of symbols on a connection */
|
|
int ws_client_unsubscribe(ws_client_t *client, uint32_t conn_idx,
|
|
const uint16_t *symbol_indices, uint32_t count);
|
|
/* Fetch a WebSocket token from the KuCoin API (prefers private when cfg has keys) */
|
|
int ws_client_fetch_token_priv(ws_connection_t *conn, const config_t *cfg);
|
|
/* Process a received WebSocket frame (dispatch to book updates, etc.).
|
|
* Returns symbol index on book update, -1 otherwise. */
|
|
int16_t ws_client_process_frame(ws_client_t *client, uint32_t conn_idx);
|
|
/* Send a WebSocket ping frame */
|
|
int ws_client_send_ping(ws_connection_t *conn);
|
|
/* Get current monotonic timestamp in milliseconds */
|
|
uint64_t ws_client_now_ms(void);
|
|
|
|
/* Wait for balance WS to confirm available >= min_amount for a currency.
|
|
Blocks on the balance wake eventfd for up to timeout_ms.
|
|
Returns true once the condition is met, false on timeout. */
|
|
bool ws_client_await_balance(ws_client_t *client, const char *currency,
|
|
double min_amount, int64_t timeout_ms);
|
|
|
|
/* Read the latest known available balance for a currency from cache (thread-safe).
|
|
Returns 0 if currency is not in cache. */
|
|
double ws_client_latest_balance(ws_client_t *client, const char *currency);
|
|
|
|
#endif
|