|
cwist
Modern C web framework with libttak runtime
|
The WebSocket module allows upgrading standard HTTP connections to persistent WebSocket connections.
Upgrades an incoming HTTP request to a WebSocket connection.
cwist_websocket context on success, or NULL on failure.101 Switching Protocols response.cwist_websocket_destroy.Receives a single WebSocket frame.
NULL if the connection is closed or an error occurs.cwist_websocket_frame_destroy.Sends data as a WebSocket frame.
CWIST_WS_FRAME_TEXT: Text data (UTF-8)CWIST_WS_FRAME_BINARY: Binary dataCWIST_WS_FRAME_CLOSE: Connection closeCWIST_WS_FRAME_PING / CWIST_WS_FRAME_PONG: HeartbeatUse cwist_app_ws to register a WebSocket route.
Header: <cwist/net/websocket/websocket_async.h>
In C1M mode (CWIST_C1M_MODE=1) the reactor watches sockets and delivers each complete message through a callback instead of blocking in cwist_websocket_receive. Use cwist_app_ws_async to register a route on this path.
Registers a reactor-driven WebSocket route. For each complete message the reactor invokes on_message(ws, frame, user_data) on the reactor thread. user_data is an opaque pointer passed through unchanged; use it for per-handler state (broadcast list, room context, etc.).
Callback invoked once per complete message. The callback must release frame with cwist_websocket_frame_destroy(). It is safe to call cwist_websocket_async_send() and cwist_websocket_async_close() from inside this callback.
Sends one FIN-terminated frame without blocking. On EAGAIN or a short write the remainder is parked on a one-shot reactor write slot and drained when the socket becomes writable. Returns 0 on success, -1 on failure.
Initiates the close handshake without blocking. Queues a CLOSE frame and schedules connection cleanup. Safe to call from inside the on_message callback; NULL is ignored.
Supported since v3.8. The feature is opt-in only and changes no existing behavior when unused.
cwist/graphql_ws.h implements the graphql-transport-ws subprotocol on top of the non-blocking WebSocket transport:
connection_init -> connection_ack; subscribe before init closes the socket with code 4429.subscribe {id, payload:{query,variables,operationName}} -> one next {id, payload:{data:{...}}} per published event, error {id, payload:[...]} when the operation fails to start, complete {id} when it ends.ping/pong JSON keepalive after init. Malformed traffic closes with 4400/4401; duplicate operation ids close with 4409.Subscription fields are registered on an endpoint with cwist_graphql_ws_add_subscription(); the resolver returns an event source (cwist_graphql_event_source_create() + cwist_graphql_event_source_add_topic()). Application code fans events out through the in-process, thread-safe topic broker cwist_graphql_publish(topic, payload) — delivery to the wire happens on the owning reactor thread, so publish may be called from any thread.
Client complete {id} and socket close both tear the subscription down without leaking. See tests/test_graphql_subscriptions.c for an end-to-end example over a socketpair-driven reactor.