Mercurial
view seobeo/docs/web_socket_server.md @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | 7b1719fa918c |
| children |
line wrap: on
line source
# Seobeo WebSocket Server - Usage Guide A clean, easy-to-use WebSocket server library that integrates seamlessly with the existing Seobeo HTTP server. ## Features 1. **Automatic Upgrade Handling**: Automatically detects and upgrades HTTP connections to WebSocket 2. **Route-Based Handlers**: Register WebSocket handlers for specific paths (like HTTP routing) 3. **Text and Binary Messages**: Send/receive both text and binary data 4. **Broadcast Support**: Send messages to all connected clients 5. **Connection Management**: Automatic connection tracking and cleanup 6. **Integrated with HTTP Server**: Works alongside existing HTTP routes and static file serving 7. **RFC 6455 Compliant**: Full WebSocket protocol support ## API Overview ### Initialization and Registration ```c // Initialize WebSocket server system void Seobeo_WebSocket_Server_Init(); // Register a WebSocket handler for a specific path void Seobeo_WebSocket_Server_Register(const char *path, Seobeo_WebSocket_Server_Handler handler, void *p_user_data); ``` ### Handler Function Type ```c typedef void (*Seobeo_WebSocket_Server_Handler)( Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data ); ``` ### Sending Messages ```c // Send to specific client int32 Seobeo_WebSocket_Server_Send_Text(Seobeo_WebSocket_Server_Connection *p_conn, const char *text); int32 Seobeo_WebSocket_Server_Send_Binary(Seobeo_WebSocket_Server_Connection *p_conn, const uint8 *data, size_t length); // Broadcast to all clients void Seobeo_WebSocket_Server_Broadcast_Text(const char *text); void Seobeo_WebSocket_Server_Broadcast_Binary(const uint8 *data, size_t length); ``` ### Connection Management ```c // Close specific connection void Seobeo_WebSocket_Server_Connection_Close(Seobeo_WebSocket_Server_Connection *p_conn, uint16 code, const char *reason); ``` ## Examples ### 1. Simple Echo Server ```c #include "seobeo/seobeo.h" void Echo_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { printf("Received: %.*s\n", (int)p_msg->length, (char*)p_msg->data); Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data); } } int main() { // Initialize WebSocket routing Seobeo_WebSocket_Server_Init(); // Register echo handler Seobeo_WebSocket_Server_Register("/echo", Echo_Handler, NULL); // Start HTTP server (automatically handles WebSocket upgrades) Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 2. Chat Room Server ```c void Chat_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { char message[2048]; snprintf(message, sizeof(message), "[%s]: %.*s", p_conn->client_id, (int)p_msg->length, (char*)p_msg->data); printf("Broadcasting: %s\n", message); Seobeo_WebSocket_Server_Broadcast_Text(message); } } int main() { Seobeo_WebSocket_Server_Init(); Seobeo_WebSocket_Server_Register("/chat", Chat_Handler, NULL); printf("Chat server started on ws://localhost:8080/chat\n"); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 3. Binary Data Broadcasting ```c void Binary_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_BINARY) { printf("Received %zu bytes, broadcasting...\n", p_msg->length); Seobeo_WebSocket_Server_Broadcast_Binary(p_msg->data, p_msg->length); } } int main() { Seobeo_WebSocket_Server_Init(); Seobeo_WebSocket_Server_Register("/binary", Binary_Handler, NULL); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 4. Multiple Endpoints ```c void Echo_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data); } void Chat_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { char msg[2048]; snprintf(msg, sizeof(msg), "[%s]: %.*s", p_conn->client_id, (int)p_msg->length, (char*)p_msg->data); Seobeo_WebSocket_Server_Broadcast_Text(msg); } } int main() { Seobeo_WebSocket_Server_Init(); // Register multiple WebSocket endpoints Seobeo_WebSocket_Server_Register("/echo", Echo_Handler, NULL); Seobeo_WebSocket_Server_Register("/chat", Chat_Handler, NULL); printf("Server started with:\n"); printf(" ws://localhost:8080/echo - Echo server\n"); printf(" ws://localhost:8080/chat - Chat room\n"); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 5. Custom User Data ```c typedef struct { int message_count; char name[64]; } ChatRoomData; void Chat_Handler_With_Data(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { ChatRoomData *p_data = (ChatRoomData*)p_user_data; if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) { p_data->message_count++; char message[2048]; snprintf(message, sizeof(message), "[%s #%d]: %.*s", p_data->name, p_data->message_count, (int)p_msg->length, (char*)p_msg->data); Seobeo_WebSocket_Server_Broadcast_Text(message); } } int main() { ChatRoomData room_data = {0}; strcpy(room_data.name, "Main Room"); Seobeo_WebSocket_Server_Init(); Seobeo_WebSocket_Server_Register("/chat", Chat_Handler_With_Data, &room_data); Seobeo_Web_Server_Start(NULL, "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ### 6. Mixed HTTP and WebSocket Server ```c // HTTP route handler Seobeo_Request_Entry* Get_Status(Seobeo_Request_Entry *req, Dowa_Arena *arena) { Seobeo_Request_Entry *resp = NULL; Dowa_HashMap_Push_Arena(resp, "status", "200", arena); Dowa_HashMap_Push_Arena(resp, "content-type", "application/json", arena); Dowa_HashMap_Push_Arena(resp, "body", "{\"status\": \"online\"}", arena); return resp; } // WebSocket handler void WS_Handler(Seobeo_WebSocket_Server_Connection *p_conn, Seobeo_WebSocket_Message *p_msg, void *p_user_data) { if (p_msg->opcode == SEOBEO_WS_OPCODE_TEXT) Seobeo_WebSocket_Server_Send_Text(p_conn, (char*)p_msg->data); } int main() { // Initialize both HTTP and WebSocket routing Seobeo_Router_Init(); Seobeo_WebSocket_Server_Init(); // Register HTTP routes Seobeo_Router_Register("GET", "/api/status", Get_Status); // Register WebSocket routes Seobeo_WebSocket_Server_Register("/ws", WS_Handler, NULL); printf("Server started:\n"); printf(" HTTP: http://localhost:8080/api/status\n"); printf(" WebSocket: ws://localhost:8080/ws\n"); Seobeo_Web_Server_Start("./public", "8080", SEOBEO_MODE_FORK, 0); return 0; } ``` ## Building ### Build the server example: ```bash bazel build //seobeo:websocket_server_example ``` ### Run the server: ```bash bazel-bin/seobeo/websocket_server_example ``` ### Test with a client: You can test the server using the WebSocket client API or any WebSocket client tool: ```bash # Using websocat (install: cargo install websocat) websocat ws://localhost:8080/echo # Using wscat (install: npm install -g wscat) wscat -c ws://localhost:8080/chat ``` ## Connection Structure ```c struct Seobeo_WebSocket_Server_Connection_Struct { Seobeo_Handle *p_handle; // Underlying socket handle char *client_id; // Unique client identifier boolean is_active; // Connection status // Fragment handling (internal) uint8 *fragment_buffer; size_t fragment_length; size_t fragment_capacity; Seobeo_WebSocket_Opcode fragment_opcode; Seobeo_WebSocket_Server_Connection *next; // Linked list }; ``` ## Protocol Details The server implementation follows RFC 6455: 1. **Handshake**: Responds to HTTP Upgrade requests with proper Sec-WebSocket-Accept key 2. **Frame Format**: Server sends unmasked frames (RFC requirement) 3. **Frame Receiving**: Server receives and unmasks client frames 4. **Fragmentation**: Handles fragmented messages automatically 5. **Control Frames**: Proper handling of ping, pong, and close frames 6. **Broadcast**: Efficiently sends to all active connections ## Key Differences from Client | Feature | Client | Server | |---------|--------|--------| | Frame Masking | Masks outgoing frames | Does NOT mask outgoing frames | | Connection | Initiates connection | Accepts connections | | Upgrade | Sends upgrade request | Responds to upgrade request | | Multiple Connections | Single connection | Manages multiple connections | | Broadcast | N/A | Can broadcast to all clients | ## Coding Standards The implementation follows your specified coding standards: - Naming: `Seobeo_WebSocket_Server_Init`, `Seobeo_WebSocket_Server_Send_Text` - Two spaces for indentation - New line before `{` unless it's a struct - Single statement: no need for `{}` ## Integration with Existing Server The WebSocket server integrates seamlessly: 1. **Automatic Detection**: The HTTP server automatically checks for WebSocket upgrade requests 2. **No Conflicts**: WebSocket and HTTP routes coexist peacefully 3. **Same Port**: WebSocket and HTTP share the same server port 4. **Unified Server**: Use `Seobeo_Web_Server_Start()` for everything ## Testing the Server ### JavaScript Client (Browser): ```javascript const ws = new WebSocket('ws://localhost:8080/echo'); ws.onopen = () => { console.log('Connected!'); ws.send('Hello, Server!'); }; ws.onmessage = (event) => { console.log('Received:', event.data); }; ``` ### Python Client: ```python import websocket ws = websocket.create_connection("ws://localhost:8080/chat") ws.send("Hello from Python!") print(ws.recv()) ws.close() ``` ## Performance Considerations 1. **Fork Mode**: Each connection runs in a separate process (SEOBEO_MODE_FORK) 2. **Edge Mode**: Multi-threaded connections (SEOBEO_MODE_EDGE) 3. **Broadcast**: Iterates through all connections (O(n) complexity) 4. **Fragmentation**: Large messages are automatically fragmented (1MB chunks) ## Complete Feature Comparison | Feature | Implemented | |---------|-------------| | ✅ WebSocket upgrade handshake | Yes | | ✅ Text messages | Yes | | ✅ Binary messages | Yes | | ✅ Message fragmentation | Yes | | ✅ Ping/Pong | Yes | | ✅ Close handshake | Yes | | ✅ Multiple endpoints | Yes | | ✅ Broadcast | Yes | | ✅ Connection tracking | Yes | | ✅ Integration with HTTP server | Yes | | ✅ Custom user data per handler | Yes | The Seobeo WebSocket Server provides a complete, production-ready WebSocket implementation that works seamlessly with the existing HTTP server!