ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
server.h File Reference

ACIP server-side protocol API. More...

Go to the source code of this file.

Data Structures

struct  acip_frame_workspace_t
 Send ASCII frame to client (server → client). More...

Functions

asciichat_error_t acip_server_receive_and_dispatch (acip_transport_t *transport, void *client_ctx, const acip_server_callbacks_t *callbacks)
 Receive packet from client and dispatch to callbacks.
void acip_frame_workspace_destroy (acip_frame_workspace_t *workspace)
asciichat_error_t acip_send_ascii_frame (acip_transport_t *transport, acip_frame_workspace_t *workspace, const char *frame_data, size_t frame_size, uint32_t width, uint32_t height, const char *client_id)
asciichat_error_t acip_send_ascii_frame_contract (acip_transport_t *transport, acip_frame_workspace_t *workspace, const char *text, size_t length, uint32_t width, uint32_t height, const acip_render_settings_t *settings, uint32_t effects, const char *client_id)
asciichat_error_t acip_send_clear_console (acip_transport_t *transport)
 Send clear console command to client (server → client).
asciichat_error_t acip_send_server_state (acip_transport_t *transport, const server_state_packet_t *state)
 Send server state update to client (server → client).

Detailed Description

ACIP server-side protocol API.

Server-side API for ascii-chat protocol. Provides functions for:

  • Receiving and dispatching packets from clients
  • Sending ASCII frames to clients
  • Sending server state updates
  • Sending console control commands
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
January 2026

Definition in file include/ascii-chat/network/acip/server.h.

Function Documentation

◆ acip_frame_workspace_destroy()

void acip_frame_workspace_destroy ( acip_frame_workspace_t * workspace)

Definition at line 161 of file lib/network/acip/server.c.

161 {
162 if (!workspace)
163 return;
165}
void compression_workspace_destroy(compression_workspace_t *workspace)

References acip_frame_workspace_t::compression, and compression_workspace_destroy().

Referenced by client_video_render_thread(), session_host_create(), and session_host_destroy().

◆ acip_send_ascii_frame()

asciichat_error_t acip_send_ascii_frame ( acip_transport_t * transport,
acip_frame_workspace_t * workspace,
const char * frame_data,
size_t frame_size,
uint32_t width,
uint32_t height,
const char * client_id )

Definition at line 155 of file lib/network/acip/server.c.

157 {
158 return acip_send_ascii_frame_contract(transport, workspace, text, length, width, height, NULL, 0, client_id);
159}
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
asciichat_error_t acip_send_ascii_frame_contract(acip_transport_t *transport, acip_frame_workspace_t *workspace, const char *frame_data, size_t frame_size, uint32_t width, uint32_t height, const acip_render_settings_t *settings, uint32_t effects, const char *client_id)

References acip_send_ascii_frame_contract(), height, and width.

Referenced by session_host_broadcast_frame(), and session_host_send_frame().

◆ acip_send_ascii_frame_contract()

asciichat_error_t acip_send_ascii_frame_contract ( acip_transport_t * transport,
acip_frame_workspace_t * workspace,
const char * text,
size_t length,
uint32_t width,
uint32_t height,
const acip_render_settings_t * settings,
uint32_t effects,
const char * client_id )

Definition at line 93 of file lib/network/acip/server.c.

96 {
97 ASCII_OTEL_SCOPE(ACIP_SEND_ASCII_FRAME_CONTRACT);
98 if (!transport || !frame_data || !workspace) {
99 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport or frame_data");
100 }
101
102 if (frame_size == 0) {
103 return SET_ERRNO(ERROR_INVALID_PARAM, "Empty frame data");
104 }
105
106 if (frame_size > UINT32_MAX) {
107 return SET_ERRNO(ERROR_NETWORK_SIZE, "ASCII frame is too large: %zu bytes", frame_size);
108 }
109
110 log_dev("SEND_ASCII_FRAME: client_id=%s, width=%u, height=%u, frame_size=%zu bytes", client_id, width, height,
111 frame_size);
112
113 // Calculate CRC32 checksum of frame data for integrity verification
114 uint32_t checksum_value = asciichat_crc32(frame_data, frame_size);
115 log_debug("★ SEND_ASCII_FRAME: CRC32 checksum calculated: 0x%08x for %zu bytes", checksum_value, frame_size);
116
117 // Compress ANSI text before sending it. Native and browser clients decode zstd frames.
118 const void *payload_data = frame_data;
119 size_t payload_size = frame_size;
120 bool is_compressed = false;
121 if (frame_size >= COMPRESSION_MIN_SIZE &&
122 compress_workspace(&workspace->compression, frame_data, frame_size, 1) == ASCIICHAT_OK &&
123 should_compress(frame_size, workspace->compression.output.length)) {
124 payload_data = workspace->compression.output.data;
125 payload_size = workspace->compression.output.length;
126 is_compressed = true;
127 }
128
129 // Create ASCII frame packet header
131 header.width = HOST_TO_NET_U32(width);
132 header.height = HOST_TO_NET_U32(height);
133 header.original_size = HOST_TO_NET_U32((uint32_t)frame_size);
134 header.compressed_size = HOST_TO_NET_U32(is_compressed ? (uint32_t)payload_size : 0);
135 header.checksum = HOST_TO_NET_U32(checksum_value);
137 size_t contract_length = 0;
138 if (settings) {
139 asciichat_error_t encoded = frame_render_contract_encode(settings, effects, contract, &contract_length);
140 if (encoded != ASCIICHAT_OK)
141 return encoded;
142 }
143 header.flags =
144 HOST_TO_NET_U32((is_compressed ? FRAME_FLAG_IS_COMPRESSED : 0) | (settings ? FRAME_FLAG_RENDER_CONTRACT : 0));
145
146 socket_buffer_t slices[3] = {{&header, sizeof(header)}};
147 size_t count = 1;
148 if (contract_length)
149 slices[count++] = (socket_buffer_t){contract, contract_length};
150 slices[count++] = (socket_buffer_t){payload_data, payload_size};
151 asciichat_error_t result = packet_send_via_transportv(transport, PACKET_TYPE_ASCII_FRAME, slices, count, 0);
152 return result;
153}
#define SET_ERRNO(code,...)
asciichat_error_t compress_workspace(compression_workspace_t *workspace, const void *input, size_t size, int level)
#define HOST_TO_NET_U32(val)
Definition endian.h:66
asciichat_error_t frame_render_contract_encode(const acip_render_settings_t *settings, uint32_t effects, uint8_t *wire, size_t *length)
unsigned int uint32_t
Definition common.h:62
unsigned char uint8_t
Definition common.h:60
#define COMPRESSION_MIN_SIZE
Minimum packet size to attempt compression (1KB).
Definition compression.h:62
bool should_compress(size_t original_size, size_t compressed_size)
Determine if compression should be used for given data sizes.
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
@ ERROR_INVALID_PARAM
#define log_dev(...)
Log a DEV message (most verbose, development only).
Definition log/log.h:581
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
@ PACKET_TYPE_ASCII_FRAME
Complete ASCII frame with all metadata.
Definition packet.h:383
#define FRAME_FLAG_RENDER_CONTRACT
Explicit versioned render contract precedes encoded ASCII text.
#define FRAME_FLAG_IS_COMPRESSED
Frame data is compressed.
#define asciichat_crc32(data, len)
Main CRC32 dispatcher macro - use this in application code.
Definition crc32.h:147
#define ASCII_OTEL_SCOPE(id)
Definition otel.h:72
#define FRAME_RENDER_CONTRACT_MAX
asciichat_error_t packet_send_via_transportv(acip_transport_t *transport, packet_type_t type, const socket_buffer_t *payload, size_t count, uint32_t client_id)
Send arbitrary packet via transport (generic packet sender).
Definition send.c:155
The wire metadata for one rendered ASCII frame. width and height describe the terminal grid,...
Definition packet.h:902
uint32_t width
Terminal width in characters.
Definition packet.h:904
buffer_workspace_t output

References ASCII_OTEL_SCOPE, asciichat_crc32, ASCIICHAT_OK, compress_workspace(), acip_frame_workspace_t::compression, COMPRESSION_MIN_SIZE, buffer_workspace_t::data, ERROR_INVALID_PARAM, ERROR_NETWORK_SIZE, FRAME_FLAG_IS_COMPRESSED, FRAME_FLAG_RENDER_CONTRACT, frame_render_contract_encode(), FRAME_RENDER_CONTRACT_MAX, height, HOST_TO_NET_U32, buffer_workspace_t::length, log_debug, log_dev, compression_workspace_t::output, packet_send_via_transportv(), PACKET_TYPE_ASCII_FRAME, SET_ERRNO, should_compress(), ascii_frame_packet_t::width, and width.

Referenced by acip_send_ascii_frame(), and server_send_video().

◆ acip_send_clear_console()

asciichat_error_t acip_send_clear_console ( acip_transport_t * transport)

Send clear console command to client (server → client).

Instructs client to clear the terminal/console.

Parameters
transportTransport instance
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 167 of file lib/network/acip/server.c.

167 {
168 if (!transport) {
169 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport");
170 }
171
172 return packet_send_via_transport(transport, PACKET_TYPE_CLEAR_CONSOLE, NULL, 0, 0);
173}
@ PACKET_TYPE_CLEAR_CONSOLE
Server tells client to clear console.
Definition packet.h:419
asciichat_error_t packet_send_via_transport(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, uint32_t client_id)
Definition send.c:190

References ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_CLEAR_CONSOLE, and SET_ERRNO.

Referenced by server_send_video().

◆ acip_send_server_state()

asciichat_error_t acip_send_server_state ( acip_transport_t * transport,
const server_state_packet_t * state )

Send server state update to client (server → client).

Notifies client of server state changes (client count, grid layout, etc.)

Parameters
transportTransport instance
stateServer state structure
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 175 of file lib/network/acip/server.c.

175 {
176 ASCII_OTEL_SCOPE(ACIP_SEND_SERVER_STATE);
177 if (!transport || !state) {
178 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport or state");
179 }
180
181 return packet_send_via_transport(transport, PACKET_TYPE_SERVER_STATE, state, sizeof(*state), 0);
182}
@ PACKET_TYPE_SERVER_STATE
Server sends current state to clients.
Definition packet.h:421

References ASCII_OTEL_SCOPE, ERROR_INVALID_PARAM, packet_send_via_transport(), PACKET_TYPE_SERVER_STATE, and SET_ERRNO.

Referenced by send_server_state_to_client(), server_send_state(), and session_host_set_client_transport().

◆ acip_server_receive_and_dispatch()

asciichat_error_t acip_server_receive_and_dispatch ( acip_transport_t * transport,
void * client_ctx,
const acip_server_callbacks_t * callbacks )

Receive packet from client and dispatch to callbacks.

High-level receive function for server side. Receives a single packet from the transport, handles decryption, and dispatches to appropriate callback handler.

Parameters
transportTransport instance
client_ctxClient context pointer (passed to callbacks)
callbacksCallback structure for handling received packets
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 33 of file lib/network/acip/server.c.

34 {
35 ASCII_OTEL_SCOPE(ACIP_SERVER_RECEIVE_AND_DISPATCH);
36 uint64_t dispatch_start_ns = time_get_ns();
38 "ACIP_SERVER_DISPATCH: Entry, transport=%p, client_ctx=%p, callbacks=%p, timestamp=%llu",
39 (void *)transport, client_ctx, (const void *)callbacks, (unsigned long long)dispatch_start_ns);
40
41 if (!transport) {
42 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid transport (NULL)");
43 }
44 if (!callbacks) {
45 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid callbacks (NULL)");
46 }
47
48 // Check if transport is connected
49 if (!transport->methods->is_connected(transport)) {
50 return SET_ERRNO(ERROR_NETWORK, "Transport not connected");
51 }
52
53 packet_envelope_t envelope = {0};
54 asciichat_error_t received = packet_receive_via_transport(transport, &envelope.type, &envelope.data, &envelope.len,
55 &envelope.allocated_buffer);
56 if (received != ASCIICHAT_OK)
57 return received;
58
59 // Dispatch packet to appropriate ACIP handler
60 // Server receives packets FROM clients, so use server packet handler
61 log_info("ACIP_DISPATCH_PKT: type=%d, len=%zu, client_ctx=%p", envelope.type, envelope.len, client_ctx);
62 log_info("📤 [FRAME_DISPATCH] Starting handler dispatch for packet type=%d (0x%04x), payload=%zu bytes",
63 envelope.type, envelope.type, envelope.len);
64 uint64_t dispatch_handler_start_ns = time_get_ns();
65 asciichat_error_t dispatch_result =
66 acip_handle_server_packet(transport, envelope.type, envelope.data, envelope.len, client_ctx, callbacks);
67 uint64_t dispatch_handler_end_ns = time_get_ns();
68 char handler_duration_str[TIME_DURATION_BUFFER_SIZE];
69 time_pretty((uint64_t)(dispatch_handler_end_ns - dispatch_handler_start_ns), -1, handler_duration_str,
70 sizeof(handler_duration_str));
71 log_info("[WS_TIMING] Handler for type=%d took %s (result=%d)", envelope.type, handler_duration_str, dispatch_result);
72
73 if (dispatch_result != ASCIICHAT_OK) {
74 log_error("❌ [FRAME_DISPATCH_FAILED] Handler returned error for type=%d: %s", envelope.type,
75 asciichat_error_format(NULL, dispatch_result));
76 } else {
77 log_info("✅ [FRAME_DISPATCH_SUCCESS] Handler completed successfully for type=%d", envelope.type);
78 }
79
80 // Always free the allocated buffer (even if handler failed)
81 if (envelope.allocated_buffer) {
82 buffer_release(envelope.allocated_buffer);
83 }
84
85 // Return handler result
86 return dispatch_result;
87}
const char * asciichat_error_format(const char *message, asciichat_error_t code)
#define buffer_release(data)
Definition buffer.h:91
unsigned long long uint64_t
Definition common.h:63
@ ERROR_NETWORK
Definition error_codes.h:72
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
int time_pretty(uint64_t nanoseconds, int decimals, char *buffer, size_t buffer_size)
Format nanoseconds as a compact duration with configurable sub-minute precision.
Definition time.c:374
#define TIME_DURATION_BUFFER_SIZE
Definition time.h:40
#define US_PER_MS_INT
Definition time.h:172
asciichat_error_t acip_handle_server_packet(acip_transport_t *transport, packet_type_t type, const void *payload, size_t payload_len, void *client_ctx, const acip_server_callbacks_t *callbacks)
Handle incoming packet on server side.
Definition handlers.c:799
#define log_dev_every(interval_us, fmt,...)
Rate-limited DEV logging.
Definition log/log.h:746
asciichat_error_t packet_receive_via_transport(acip_transport_t *transport, packet_type_t *type, void **payload, size_t *payload_len, void **alloc_buffer)
Receive a packet via transport with header parsing and validation.
Definition send.c:200
Packet envelope containing received packet data.
Definition packet.h:1185

References acip_handle_server_packet(), ASCII_OTEL_SCOPE, asciichat_error_format(), ASCIICHAT_OK, buffer_release, ERROR_INVALID_PARAM, ERROR_NETWORK, acip_transport_methods_t::is_connected, log_dev_every, log_error, log_info, acip_transport::methods, packet_receive_via_transport(), SET_ERRNO, TIME_DURATION_BUFFER_SIZE, time_pretty(), and US_PER_MS_INT.