### Instantiate WebSocketOptions Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/types.md Provides an example of how to create a WebSocketOptions instance with specific configuration values for a WebSocket client connection. ```rust let options = WebSocketOptions { path: "/chat?room=lobby", host: "example.com:8080", origin: "https://example.com", sub_protocols: Some(&["chat", "superchat"]), additional_headers: Some(&["Authorization: Bearer xyz"]), }; ``` -------------------------------- ### Rust Example: Initiating WebSocket Connection Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Demonstrates how to use the `connect` method to establish a WebSocket connection. Ensure you have a running WebSocket server and appropriate stream implementation. ```rust use embedded_websocket::framer::Framer; use embedded_websocket::{WebSocketClient, WebSocketOptions}; use std::net::TcpStream; let mut stream = TcpStream::connect("127.0.0.1:1337").unwrap(); let mut read_buf = [0u8; 4000]; let mut read_cursor = 0; let mut write_buf = [0u8; 4000]; let mut websocket = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut websocket, ); let options = WebSocketOptions { path: "/chat", host: "localhost:1337", origin: "http://localhost:1337", sub_protocols: None, additional_headers: None, }; let sub_protocol = framer.connect(&mut stream, &options).unwrap(); ``` -------------------------------- ### WebSocket Options Configuration Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md This example demonstrates how to configure essential WebSocket options, including the required path, host, origin, and optional sub-protocols and headers. ```rust let options = WebSocketOptions { path: "/chat", // Required host: "example.com:8080", // Required origin: "https://example.com", // Required sub_protocols: Some(&["chat"]), additional_headers: Some(&["Auth: x"]), }; ``` -------------------------------- ### WebSocketOptions Usage Example Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/configuration.md Demonstrates how to instantiate and use the WebSocketOptions struct to configure a client connection. This includes setting path, host, origin, and optional sub-protocols and headers. ```rust use embedded_websocket as ws; let websocket_options = ws::WebSocketOptions { path: "/chat?room=lobby", host: "example.com:8080", origin: "https://example.com", sub_protocols: Some(&["chat", "superchat"]), additional_headers: Some(&["Authorization: Bearer mytoken123"]), }; let mut buffer = [0u8; 2000]; let mut ws_client = ws::WebSocketClient::new_client(rand::thread_rng()); let (len, key) = ws_client.client_connect(&websocket_options, &mut buffer)?; ``` -------------------------------- ### Initiate Async WebSocket Handshake (Client) Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer-async.md Starts the client-side WebSocket opening handshake asynchronously. It sends an HTTP GET request, awaits and validates the server's 101 Switching Protocols response, and handles the Sec-WebSocket-Accept header. Use this when establishing a new client connection. ```rust pub async fn connect<'a, B, E>( &mut self, stream: &mut (impl Stream> + Sink<&'a [u8], Error = E> + Unpin), buffer: &'a mut [u8], websocket_options: &WebSocketOptions<'_>, ) -> Result, FramerError> where B: AsRef<[u8]>, ``` -------------------------------- ### Typical WebSocket Client Code Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Example of setting up and using a WebSocket client to connect to a server, send a message, and receive responses. ```rust use embedded_websocket::{framer::Framer, WebSocketClient, WebSocketOptions}; use std::net::TcpStream; let mut stream = TcpStream::connect("127.0.0.1:8080")?; let mut read_buf = [0u8; 4000]; let mut read_cursor = 0; let mut write_buf = [0u8; 4000]; let mut frame_buf = [0u8; 4000]; let mut ws = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new(&mut read_buf, &mut read_cursor, &mut write_buf, &mut ws); let options = WebSocketOptions { path: "/chat", host: "localhost:8080", origin: "http://localhost", sub_protocols: None, additional_headers: None, }; framer.connect(&mut stream, &options)?; framer.write(&mut stream, WebSocketSendMessageType::Text, true, b"Hello")?; while let ReadResult::Text(text) = framer.read(&mut stream, &mut frame_buf)? { println!("Received: {}", text); } ``` -------------------------------- ### no_std Example with CustomStream Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/configuration.md This example demonstrates a basic setup for no_std environments, requiring a custom implementation of the Stream trait for reading and writing data. ```rust #![no_std] use embedded_websocket as ws; use embedded_websocket::framer::Stream; struct CustomStream { // Your implementation } impl Stream for CustomStream { fn read(&mut self, buf: &mut [u8]) -> Result { // Read from your transport (UART, SPI, etc.) } fn write_all(&mut self, buf: &[u8]) -> Result<(), E> { // Write to your transport } } let mut ws_server = ws::WebSocketServer::new_server(); // ... use with your CustomStream ``` -------------------------------- ### Typical WebSocket Server Code Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Example of setting up a basic WebSocket server to listen for incoming connections, accept WebSocket handshakes, and echo received text messages. ```rust use embedded_websocket::{framer::Framer, WebSocketServer, read_http_header}; use std::net::{TcpListener, TcpStream}; let listener = TcpListener::bind("127.0.0.1:8080")?; for stream in listener.incoming() { let mut stream = stream?; let mut read_buf = [0u8; 4000]; let mut write_buf = [0u8; 4000]; let mut frame_buf = [0u8; 4000]; let mut ws = WebSocketServer::new_server(); let mut framer = Framer::new(&mut read_buf, &mut 0, &mut write_buf, &mut ws); // Parse HTTP request to get WebSocketContext // ... (use httparse or similar) let context = read_http_header(headers)?; framer.accept(&mut stream, &context)?; // Echo messages back while let ReadResult::Text(text) = framer.read(&mut stream, &mut frame_buf)? { framer.write(&mut stream, WebSocketSendMessageType::Text, true, text.as_bytes())?; } } ``` -------------------------------- ### Initiate WebSocket Client Connection Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Use `client_connect` to generate an HTTP GET request for the WebSocket opening handshake. Ensure the provided buffer is at least 2000 bytes. ```rust use embedded_websocket as ws; let mut buffer: [u8; 2000] = [0; 2000]; let mut ws_client = ws::WebSocketClient::new_client(rand::thread_rng()); let websocket_options = ws::WebSocketOptions { path: "/chat", host: "localhost", origin: "http://localhost", sub_protocols: Some(&["chat"]), additional_headers: None, }; let (len, web_socket_key) = ws_client.client_connect(&websocket_options, &mut buffer).unwrap(); let http_request = std::str::from_utf8(&buffer[..len]).unwrap(); ``` -------------------------------- ### Example usage of EmptyRng::new() Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/random.md Demonstrates how to instantiate `EmptyRng` using its `new()` constructor. This is typically used in server contexts. ```rust use embedded_websocket::EmptyRng; let rng = EmptyRng::new(); ``` -------------------------------- ### Project Structure Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Overview of the directory structure for the embedded-websocket project, including source files, examples, and configuration. ```tree embedded-websocket/ ├── src/ │ ├── lib.rs # Core WebSocket type and protocol implementation │ ├── framer.rs # Stream-based wrapper (recommended) │ ├── framer_async.rs # Async wrapper (experimental) │ ├── http.rs # HTTP handshake utilities │ ├── random.rs # RNG helpers │ └── ... ├── examples/ │ ├── client.rs # Client example with Framer │ ├── server.rs # Server example with Framer │ ├── client_async.rs # Async client example │ └── server_async.rs # Async server example └── Cargo.toml ``` -------------------------------- ### Configure Buffers for 64KB Messages in Rust Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/configuration.md Sets up buffer sizes for reading from the socket, writing to the socket, and holding complete messages. This example configures buffers suitable for handling messages up to 64KB. ```rust const READ_BUF_SIZE: usize = 4096; // Read from socket const WRITE_BUF_SIZE: usize = 4096; // Write to socket const FRAME_BUF_SIZE: usize = 65536; // Complete message buffer let mut read_buf = [0u8; READ_BUF_SIZE]; let mut write_buf = [0u8; WRITE_BUF_SIZE]; let mut frame_buf = [0u8; FRAME_BUF_SIZE]; let mut read_cursor = 0; let mut ws = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut ws, ); ``` -------------------------------- ### Framer Constructor Example Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Demonstrates how to create a new Framer instance by providing mutable references to read/write buffers, a read cursor, and a WebSocket instance. Ensure buffers are adequately sized (e.g., 4KB) and the read cursor is initialized to 0. ```rust use embedded_websocket::framer::Framer; use embedded_websocket::WebSocketClient; let mut read_buf = [0u8; 4000]; let mut read_cursor = 0; let mut write_buf = [0u8; 4000]; let mut websocket = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut websocket, ); ``` -------------------------------- ### Example WebSocket Client Usage Source: https://github.com/ninjasource/embedded-websocket/blob/master/README.md Initiates a websocket connection, performs an opening handshake, sends a text message, and then initiates a close handshake. Requires implementing Read and Write traits if using the framer module in a no_std environment. ```rust use embedded_websocket::client::WebSocketClient; use embedded_websocket::framer::{Framer, FramerError}; use embedded_websocket::options::WebSocketOptions; use embedded_websocket::send::WebSocketSendMessageType; use embedded_websocket::status::WebSocketCloseStatusCode; use std::net::TcpStream; // open a TCP stream to localhost port 1337 let address = "127.0.0.1:1337"; println!("Connecting to: {}", address); let mut stream = TcpStream::connect(address).map_err(FramerError::Io)?; println!("Connected."); let mut read_buf = [0; 4000]; let mut read_cursor = 0; let mut write_buf = [0; 4000]; let mut frame_buf = [0; 4000]; let mut websocket = WebSocketClient::new_client(rand::thread_rng()); // initiate a websocket opening handshake let websocket_options = WebSocketOptions { path: "/chat", host: "localhost", origin: "http://localhost:1337", sub_protocols: None, additional_headers: None, }; let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut websocket, ); framer.connect(&mut stream, &websocket_options)?; let message = "Hello, World!"; framer.write( &mut stream, WebSocketSendMessageType::Text, true, message.as_bytes(), )?; while let Some(s) = framer.read_text(&mut stream, &mut frame_buf)? { println!("Received: {}", s); // close the websocket after receiving the first reply framer.close(&mut stream, WebSocketCloseStatusCode::NormalClosure, None)?; println!("Sent close handshake"); } println!("Connection closed"); ``` -------------------------------- ### client_connect Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Initiates a WebSocket opening handshake from the client side. Generates an HTTP GET request containing the Sec-WebSocket-Key header and builds the handshake request in the output buffer. ```APIDOC ## client_connect ### Description Initiates a WebSocket opening handshake from the client side. Generates an HTTP GET request containing the Sec-WebSocket-Key header and builds the handshake request in the output buffer. ### Method `pub fn client_connect` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **websocket_options** (`&WebSocketOptions`) - Required - Configuration for the connection including path, host, origin, sub-protocols, and additional headers. - **to** (`&mut [u8]`) - Required - Buffer where the HTTP handshake request will be written. Should be at least 2000 bytes to accommodate all headers. ### Returns - `Result<(usize, WebSocketKey)>` - The number of bytes written to `to` and the generated Sec-WebSocket-Key. ### Errors - `Unknown` - If the internal 1KB HTTP request buffer is too small (should be impossible for reasonable input sizes). - `Utf8Error` - If there was an error generating the accept string (should be impossible). - `WebsocketAlreadyOpen` - If called when the WebSocket is already in the Open state. ### Example ```rust use embedded_websocket as ws; let mut buffer: [u8; 2000] = [0; 2000]; let mut ws_client = ws::WebSocketClient::new_client(rand::thread_rng()); let websocket_options = ws::WebSocketOptions { path: "/chat", host: "localhost", origin: "http://localhost", sub_protocols: Some(&["chat"]), additional_headers: None, }; let (len, web_socket_key) = ws_client.client_connect(&websocket_options, &mut buffer).unwrap(); let http_request = std::str::from_utf8(&buffer[..len]).unwrap(); ``` ``` -------------------------------- ### Custom no_std RngCore implementation for embedded clients Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/random.md Provides an example of a custom `RngCore` implementation for `no_std` environments. This allows clients to use hardware RNGs or other entropy sources. ```rust use rand_core::RngCore; struct MyEmbeddedRng; impl RngCore for MyEmbeddedRng { fn next_u32(&mut self) -> u32 { // Read from hardware RNG or other entropy source 0xdeadbeef } fn next_u64(&mut self) -> u64 { ... } fn fill_bytes(&mut self, dest: &mut [u8]) { ... } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { ... } } let ws = WebSocketClient::new_client(MyEmbeddedRng); ``` -------------------------------- ### Build WebSocket Client Handshake Request Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/http-utils.md Constructs the HTTP GET request for initiating a WebSocket connection. It generates a random key, formats standard WebSocket headers, and includes any custom headers or sub-protocols. ```rust pub fn build_connect_handshake_request( websocket_options: &WebSocketOptions, rng: &mut impl RngCore, to: &mut [u8], ) -> Result<(usize, WebSocketKey)> ``` -------------------------------- ### Initiate WebSocket Close Handshake Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Use this function to start the closing process for an open WebSocket connection. It changes the connection state to CloseSent and requires a buffer to write the close frame. Ensure the buffer is large enough to accommodate the frame, status code, and description. ```rust pub fn close( &mut self, close_status: WebSocketCloseStatusCode, status_description: Option<&str>, to: &mut [u8], ) -> Result ``` ```rust use embedded_websocket as ws; let mut buffer: [u8; 1000] = [0; 1000]; let mut ws_client = ws::WebSocketClient::new_client(rand::thread_rng()); ws_client.state = ws::WebSocketState::Open; let len = ws_client.close( ws::WebSocketCloseStatusCode::NormalClosure, Some("Goodbye"), &mut buffer ).unwrap(); ``` -------------------------------- ### Get WebSocket State Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Returns the current WebSocket connection state without modifying it. ```rust pub fn state(&self) -> WebSocketState ``` ```rust if framer.state() == WebSocketState::Open { println!("Connection is open"); } ``` -------------------------------- ### Create WebSocket Server Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Instantiate a new WebSocket server. ```rust let mut ws = WebSocketServer::new_server(); ``` -------------------------------- ### build_connect_handshake_request Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/http-utils.md Builds the HTTP GET request for the WebSocket client opening handshake. This function is used internally by `WebSocket::client_connect()`. ```APIDOC ## build_connect_handshake_request ### Description Builds the HTTP GET request for the WebSocket client opening handshake. Used internally by `WebSocket::client_connect()`. ### Method Not applicable (function signature provided) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust // Example usage within client_connect (not directly callable by user) pub fn build_connect_handshake_request( websocket_options: &WebSocketOptions, rng: &mut impl RngCore, to: &mut [u8], ) -> Result<(usize, WebSocketKey)> ``` ### Response #### Success Response - `Ok((usize, WebSocketKey))` - The number of bytes written and the generated Sec-WebSocket-Key. #### Response Example ```rust // Returns Ok((bytes_written, sec_websocket_key)) ``` ### Errors - `Unknown` — If the internal 1KB buffer is too small. - `Utf8Error` — If there's an error encoding the base64 key. ``` -------------------------------- ### WebSocket Server Connection Steps Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Outline of steps to establish a WebSocket server connection. Involves receiving an HTTP request, parsing headers, and sending a 101 response. ```text 1. Create WebSocket server 2. Receive HTTP request from client 3. Parse headers with read_http_header() 4. Call server_accept() with key → generates HTTP 101 response 5. Send response to client 6. State changes to Open → ready to read/write ``` -------------------------------- ### WebSocket Client Connection Steps Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Outline of steps to establish a WebSocket client connection. Requires RNG, WebSocketOptions, and involves sending an HTTP request to the server. ```text 1. Create WebSocket client with RNG 2. Create WebSocketOptions with path, host, origin 3. Call client_connect() -> get Sec-WebSocket-Key 4. Send HTTP request to server 5. Read server response 6. Call client_accept() with key and response 7. State changes to Open → ready to read/write ``` -------------------------------- ### WebSocket server creation with EmptyRng Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/random.md Shows how to create a WebSocket server instance using `EmptyRng`. This is the recommended approach for servers as per RFC 6455. ```rust // Type: WebSocket let ws = WebSocketServer::new_server(); ``` -------------------------------- ### WebSocket Client and Server Creation Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Instantiate a new WebSocket client or server. ```APIDOC ## Creating a WebSocket ### Client ```rust let mut ws = WebSocketClient::new_client(rand::thread_rng()); ``` ### Server ```rust let mut ws = WebSocketServer::new_server(); ``` ``` -------------------------------- ### Create New WebSocket Server Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Initializes a new WebSocket server instance. This server does not require an RNG as payloads are unmasked. It is equivalent to `WebSocket`. ```rust use embedded_websocket as ws; let mut ws_server = ws::WebSocketServer::new_server(); assert_eq!(ws::WebSocketState::None, ws_server.state); ``` -------------------------------- ### Create WebSocket Client Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Instantiate a new WebSocket client. Requires a random number generator. ```rust let mut ws = WebSocketClient::new_client(rand::thread_rng()); ``` -------------------------------- ### read Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Reads and decodes a WebSocket frame from the input buffer. Handles fragmentation automatically by remembering the frame header state across calls. The output buffer can be smaller than the frame payload; in that case, call `read` again with the remaining input data to get the rest of the payload. ```APIDOC ## read ### Description Reads and decodes a WebSocket frame from the input buffer. Handles fragmentation automatically by remembering the frame header state across calls. The output buffer can be smaller than the frame payload; in that case, call `read` again with the remaining input data to get the rest of the payload. ### Method Signature ```rust pub fn read(&mut self, from: &[u8], to: &mut [u8]) -> Result ``` ### Parameters #### Path Parameters - **from** (`&[u8]`) - Required - Buffer containing the raw WebSocket frame data (typically from a TCP socket). - **to** (`&mut [u8]`) - Required - Buffer where the decoded frame payload will be written. ### Returns - `Result` - A structure containing: - `len_from: usize` - Number of bytes consumed from the input buffer. - `len_to: usize` - Number of bytes written to the output buffer. - `end_of_message: bool` - True if the entire message is now complete. - `close_status: Option` - For close frames, the status code. - `message_type: WebSocketReceiveMessageType` - The frame type (Text, Binary, Ping, Pong, CloseMustReply, CloseCompleted). ### Errors - `WebSocketNotOpen` - If the WebSocket state is not Open or CloseSent. - `InvalidOpCode` - If the frame contains an unrecognized opcode. - `UnexpectedContinuationFrame` - If a continuation frame is received without a preceding initial frame. - `ReadFrameIncomplete` - If the input buffer does not contain a complete WebSocket header (minimum 2-14 bytes). - `InvalidFrameLength` - If the frame length cannot be decoded properly. ### Example ```rust use embedded_websocket as ws; let buffer1 = [129, 5, 104, 101, 108, 108, 111]; // "hello" let mut buffer2: [u8; 128] = [0; 128]; let mut ws_client = ws::WebSocketClient::new_client(rand::thread_rng()); ws_client.state = ws::WebSocketState::Open; let ws_result = ws_client.read(&buffer1, &mut buffer2).unwrap(); assert_eq!("hello".as_bytes(), &buffer2[..ws_result.len_to]); assert_eq!(true, ws_result.end_of_message); ``` ``` -------------------------------- ### Accept WebSocket Connection Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Use this method to accept an incoming client connection and generate the HTTP 101 Switching Protocols response. Ensure the provided buffer is at least 1024 bytes. ```rust pub fn server_accept( &mut self, sec_websocket_key: &WebSocketKey, sec_websocket_protocol: Option<&WebSocketSubProtocol>, to: &mut [u8], ) -> Result ``` ```rust use embedded_websocket as ws; let mut buffer: [u8; 1000] = [0; 1000]; let mut ws_server = ws::WebSocketServer::new_server(); let ws_key = ws::WebSocketKey::from("Z7OY1UwHOx/nkSz38kfPwg=="); let sub_protocol = ws::WebSocketSubProtocol::from("chat"); let len = ws_server.server_accept(&ws_key, Some(&sub_protocol), &mut buffer).unwrap(); let response = std::str::from_utf8(&buffer[..len]).unwrap(); ``` -------------------------------- ### Framer: Connect and Accept WebSocket Connections Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Use the Framer to establish a client connection or accept an incoming server connection. The `connect` method requires stream and options, while `accept` requires stream and context. ```rust // Client framer.connect(&mut stream, &options)?; ``` ```rust // Server framer.accept(&mut stream, &context)?; ``` -------------------------------- ### WebSocket Constructors Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Functions to create new WebSocket clients and servers. ```APIDOC ## WebSocket::new_client(rng) ### Description Creates a new WebSocket client instance. ### Returns `WebSocketClient` - An instance of a WebSocket client. ### See Also [websocket-core.md](websocket-core.md) ``` ```APIDOC ## WebSocket::new_server() ### Description Creates a new WebSocket server instance. ### Returns `WebSocketServer` - An instance of a WebSocket server. ### See Also [websocket-core.md](websocket-core.md) ``` ```APIDOC ## Framer::new(...) ### Description Creates a new Framer instance. ### Returns `Framer<'a, TRng, TWebSocketType>` - An instance of a Framer. ### See Also [framer.md](framer.md) ``` -------------------------------- ### Accept Async WebSocket Connection (Rust) Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer-async.md Use this method to accept an incoming asynchronous WebSocket connection on the server. It writes the HTTP 101 response to the provided stream. Ensure you have a valid `WebSocketContext` derived from the client's HTTP request. ```rust pub async fn accept<'a, B, E>( &mut self, stream: &mut (impl Stream> + Sink<&'a [u8], Error = E> + Unpin), buffer: &'a mut [u8], websocket_context: &WebSocketContext, ) -> Result<(), FramerError> ``` -------------------------------- ### WebSocket client creation with SeedableRng Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/random.md Illustrates creating a WebSocket client with a seedable RNG (`StdRng::from_seed`). This is useful for deterministic testing scenarios. ```rust use rand::SeedableRng; use rand::rngs::StdRng; let seed = [0u8; 32]; let mut rng = StdRng::from_seed(seed); let ws = WebSocketClient::new_client(rng); ``` -------------------------------- ### Create New Async Framer Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer-async.md Instantiates an async Framer by wrapping an existing WebSocket client. This is the initial step before performing async WebSocket operations. ```rust use embedded_websocket::framer_async::Framer; use embedded_websocket::WebSocketClient; let ws = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new(ws); ``` -------------------------------- ### Client Sub-Protocol Negotiation Options Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/configuration.md Configure WebSocket client options to request support for multiple sub-protocols. The server will choose the first one it supports from the provided list. ```rust let options = ws::WebSocketOptions { path: "/chat", host: "example.com", origin: "https://example.com", sub_protocols: Some(&["chat-v2", "chat-v1", "raw"]), additional_headers: None, }; ``` -------------------------------- ### WebSocketServer Constructor Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Creates a new WebSocket server instance. This server does not require an RNG as payloads are unmasked. ```APIDOC ## new_server ### Description Creates a new WebSocket server. ### Method new_server ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters None ### Request Example ```rust use embedded_websocket as ws; let mut ws_server = ws::WebSocketServer::new_server(); assert_eq!(ws::WebSocketState::None, ws_server.state); ``` ### Response #### Success Response - **WebSocketServer** - A server-side WebSocket instance (equivalent to `WebSocket`) #### Response Example ```rust // No direct response example provided, but the constructor returns a WebSocketServer instance. ``` ### Errors None during construction. ``` -------------------------------- ### server_accept Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Accepts an incoming client connection and builds the HTTP 101 Switching Protocols response. This method should be called after parsing the client's opening handshake request using `read_http_header`. ```APIDOC ## server_accept ### Description Accepts an incoming client connection and builds the HTTP 101 Switching Protocols response. Call this after parsing the client's opening handshake request using `read_http_header`. ### Method Signature `pub fn server_accept(&mut self, sec_websocket_key: &WebSocketKey, sec_websocket_protocol: Option<&WebSocketSubProtocol>, to: &mut [u8]) -> Result` ### Parameters #### Path Parameters - **sec_websocket_key** (`&WebSocketKey`) - Required - The Sec-WebSocket-Key extracted from the client's HTTP request. - **sec_websocket_protocol** (`Option<&WebSocketSubProtocol>`) - Optional - The sub-protocol to negotiate with the client, or None to not specify one. If the client requested multiple protocols, choose the one you support. - **to** (`&mut [u8]`) - Required - Buffer where the HTTP response will be written. Should be at least 1024 bytes. ### Returns - `Result` - The number of bytes written to the buffer. ### Errors - `Unknown` - If the internal 1KB HTTP response buffer is too small. - `Utf8Error` - If there was an error generating the accept string (should be impossible). - `WebsocketAlreadyOpen` - If called on a WebSocket that is already open. ### Example ```rust use embedded_websocket as ws; let mut buffer: [u8; 1000] = [0; 1000]; let mut ws_server = ws::WebSocketServer::new_server(); let ws_key = ws::WebSocketKey::from("Z7OY1UwHOx/nkSz38kfPwg=="); let sub_protocol = ws::WebSocketSubProtocol::from("chat"); let len = ws_server.server_accept(&ws_key, Some(&sub_protocol), &mut buffer).unwrap(); let response = std::str::from_utf8(&buffer[..len]).unwrap(); ``` ``` -------------------------------- ### Create New WebSocket Client Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/websocket-core.md Instantiates a new WebSocket client using a provided random number generator for mask key generation. Requires `rand::thread_rng()` or any `RngCore` implementation. ```rust use embedded_websocket as ws; use rand; let mut ws_client = ws::WebSocketClient::new_client(rand::thread_rng()); assert_eq!(ws::WebSocketState::None, ws_client.state); ``` -------------------------------- ### WebSocket client creation with thread_rng Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/random.md Demonstrates creating a WebSocket client with `rand::thread_rng()`. This is a common choice for clients needing a random number generator for payload masking. ```rust use rand; // Type: WebSocket let ws = WebSocketClient::new_client(rand::thread_rng()); ``` -------------------------------- ### Accept WebSocket Connection (Rust) Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Use this method on the server side to accept an incoming WebSocket connection. It writes the HTTP 101 response to the provided stream. Ensure the WebSocketContext is correctly extracted from the client's HTTP request. ```rust use embedded_websocket::framer::Framer; use embedded_websocket::{WebSocketServer, read_http_header}; use std::net::TcpStream; let mut stream = TcpStream::connect("127.0.0.1:1337").unwrap(); let mut read_buf = [0u8; 4000]; let mut read_cursor = 0; let mut write_buf = [0u8; 4000]; let mut websocket = WebSocketServer::new_server(); let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut websocket, ); // After parsing the HTTP request, extract the WebSocketContext let websocket_context = read_http_header(parsed_headers).unwrap().unwrap(); framer.accept(&mut stream, &websocket_context).unwrap(); ``` -------------------------------- ### WebSocket State Machine Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Illustrates the state transitions of a WebSocket connection. Useful for understanding connection lifecycle and error handling. ```text None ──(handshake)──> Open ──(close)──> CloseSent ──(receive close)──> Closed │ ^ │ │ └─(receive close)──> CloseReceived ────────┘ Error states: Aborted (handshake failed), Closed (connection terminated) ``` -------------------------------- ### Generate Sec-WebSocket-Accept String Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/http-utils.md Generates the Sec-WebSocket-Accept header value by hashing the client's Sec-WebSocket-Key with a magic string and base64 encoding the result. The output buffer must be at least 28 bytes. ```rust pub fn build_accept_string(sec_websocket_key: &WebSocketKey, output: &mut [u8]) -> Result<()> ``` -------------------------------- ### Recommended Buffer Sizes for WebSocket Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md These constants define the recommended buffer sizes for reading, writing, and framing in a typical WebSocket stream. Use these for general-purpose applications. ```rust const READ_BUF: usize = 4096; // From stream const WRITE_BUF: usize = 4096; // To stream const FRAME_BUF: usize = 65536; // Complete message ``` -------------------------------- ### Server Accepting WebSocket Connection with Sub-Protocol Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/configuration.md On the server side, after reading the HTTP header, select a sub-protocol from the client's requested list. The server must explicitly choose one it supports. ```rust let context = ws::read_http_header(headers)?; // context.sec_websocket_protocol_list = ["chat-v2", "chat-v1", "raw"] // Server only supports chat-v1 let chosen = ws::WebSocketSubProtocol::from("chat-v1"); let len = ws_server.server_accept(&context.sec_websocket_key, Some(&chosen), buffer)?; ``` -------------------------------- ### build_accept_string Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/http-utils.md Generates the Sec-WebSocket-Accept value from the client's Sec-WebSocket-Key. This is used internally by both client and server handshake functions. ```APIDOC ## build_accept_string ### Description Generates the Sec-WebSocket-Accept value from the client's Sec-WebSocket-Key. This is used internally by both client and server handshake functions. The output is always 28 bytes (the base64 encoding of a 20-byte SHA1 hash). ### Method ```rust pub fn build_accept_string(sec_websocket_key: &WebSocketKey, output: &mut [u8]) -> Result<()> ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Description | |---|---|---| | sec_websocket_key | `&WebSocketKey` | The Sec-WebSocket-Key to hash. | | output | `&mut [u8]` | Buffer where the accept string will be written. Must be at least 28 bytes. | ### Returns `Result<()>` ### Errors - `Unknown` — If the output buffer is too small. ### Behavior - Concatenates the key with the magic string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11". - Computes the SHA1 hash of the concatenated string. - Base64-encodes the hash using standard alphabet (no padding needed, always 28 chars). - Writes the 28-byte result to output. ### RFC Reference RFC 6455 Section 1.3 — defines this exact algorithm. ``` -------------------------------- ### Define WebSocketOptions Struct Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/types.md Defines the structure for WebSocket client connection options. This struct holds configuration details like the request path, host, origin, optional sub-protocols, and additional headers for the handshake. ```rust pub struct WebSocketOptions<'a> { pub path: &'a str, pub host: &'a str, pub origin: &'a str, pub sub_protocols: Option<&'a [&'a str]>, pub additional_headers: Option<&'a [&'a str]>, } ``` -------------------------------- ### connect Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Initiates a WebSocket opening handshake on the client side. It automatically handles reading the server's response and validating it. ```APIDOC ## connect ### Description Initiates a WebSocket opening handshake on the client side. Automatically handles reading the server's response and validating it. ### Method Signature ```rust pub fn connect( &mut self, stream: &mut impl Stream, websocket_options: &WebSocketOptions, ) -> Result, FramerError> ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters Table | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | stream | `&mut impl Stream` | — | A stream implementation (e.g., TcpStream) that implements read/write operations. | | websocket_options | `&WebSocketOptions` | — | Configuration including path, host, origin, and optional sub-protocols. | ### Returns `Result, FramerError>` — The negotiated sub-protocol, if any. ### Errors - `FramerError::Io(E)` — If a stream read/write operation fails. - `FramerError::WebSocket(crate::Error)` — If the handshake validation fails. ### Example ```rust use embedded_websocket::framer::Framer; use embedded_websocket::{WebSocketClient, WebSocketOptions}; use std::net::TcpStream; let mut stream = TcpStream::connect("127.0.0.1:1337").unwrap(); let mut read_buf = [0u8; 4000]; let mut read_cursor = 0; let mut write_buf = [0u8; 4000]; let mut websocket = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut websocket, ); let options = WebSocketOptions { path: "/chat", host: "localhost:1337", origin: "http://localhost:1337", sub_protocols: None, additional_headers: None, }; let sub_protocol = framer.connect(&mut stream, &options).unwrap(); ``` ``` -------------------------------- ### accept Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Accepts an incoming WebSocket connection on the server side by writing the HTTP 101 response to the provided stream. ```APIDOC ## accept ### Description Accepts an incoming WebSocket connection on the server side. Write the HTTP 101 response to the stream. ### Method Signature `pub fn accept(&mut self, stream: &mut impl Stream, websocket_context: &WebSocketContext) -> Result<(), FramerError>` ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters Table | Parameter | Type | Description | |---|---|---| | stream | `mut impl Stream` | A stream implementation to write the response to. | | websocket_context | `&WebSocketContext` | The context extracted from the client's HTTP request using `read_http_header`. | ### Returns - `Result<(), FramerError>` ### Errors - `FramerError::Io(E)` — If a stream write operation fails. - `FramerError::WebSocket(crate::Error)` — If building the response fails. ### Example ```rust use embedded_websocket::framer::Framer; use embedded_websocket::{WebSocketServer, read_http_header}; use std::net::TcpStream; let mut stream = TcpStream::connect("127.0.0.1:1337").unwrap(); let mut read_buf = [0u8; 4000]; let mut read_cursor = 0; let mut write_buf = [0u8; 4000]; let mut websocket = WebSocketServer::new_server(); let mut framer = Framer::new( &mut read_buf, &mut read_cursor, &mut write_buf, &mut websocket, ); // After parsing the HTTP request, extract the WebSocketContext let websocket_context = read_http_header(parsed_headers).unwrap().unwrap(); framer.accept(&mut stream, &websocket_context).unwrap(); ``` ``` -------------------------------- ### Build WebSocket Server Handshake Response Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/http-utils.md Constructs the HTTP 101 Switching Protocols response for a WebSocket server. Ensure the provided buffer is at least 1024 bytes. ```rust pub fn build_connect_handshake_response( sec_websocket_key: &WebSocketKey, sec_websocket_protocol: Option<&WebSocketSubProtocol>, to: &mut [u8], ) -> Result ``` ```rust use embedded_websocket as ws; let mut buffer: [u8; 1000] = [0; 1000]; let mut ws_server = ws::WebSocketServer::new_server(); let ws_key = ws::WebSocketKey::from("Z7OY1UwHOx/nkSz38kfPwg=="); let sub_protocol = ws::WebSocketSubProtocol::from("chat"); let len = ws_server.server_accept(&ws_key, Some(&sub_protocol), &mut buffer).unwrap(); let response = std::str::from_utf8(&buffer[..len]).unwrap(); // response will be: // HTTP/1.1 101 Switching Protocols\r\n // Connection: Upgrade\r\n // Upgrade: websocket\r\n // Sec-WebSocket-Protocol: chat\r\n // Sec-WebSocket-Accept: ptPnPeDOTo6khJlzmLhOZSh2tAY=\r\n // \r\n ``` -------------------------------- ### Initialize Framer Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Create a new Framer instance, which wraps a WebSocket connection for easier message handling. It requires mutable references to buffers and the underlying WebSocket client/server. ```rust let mut framer = Framer::new(&mut read_buf, &mut read_cursor, &mut write_buf, &mut ws); ``` -------------------------------- ### Framer::new Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer-async.md Creates a new async Framer instance by wrapping an existing WebSocket instance. ```APIDOC ## Framer::new ### Description Creates a new async Framer wrapping an existing WebSocket instance. ### Signature ```rust pub fn new(websocket: WebSocket) -> Self ``` ### Parameters #### Path Parameters - **websocket** (`WebSocket`) - Required - The WebSocket instance to wrap. Can be either client or server. ### Returns - **Self** — A new async Framer instance. ### Example ```rust use embedded_websocket::framer_async::Framer; use embedded_websocket::WebSocketClient; let ws = WebSocketClient::new_client(rand::thread_rng()); let mut framer = Framer::new(ws); ``` ``` -------------------------------- ### WebSocket Struct Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/CONTENTS.txt Documentation for the core WebSocket struct, including its constructors and key methods for managing WebSocket connections. ```APIDOC ## WebSocket Struct ### Description Provides the core functionality for managing WebSocket connections, supporting generic types for send and receive messages. ### Methods #### Constructor: `new_client()` Creates a new WebSocket client instance. #### Constructor: `new_server()` Creates a new WebSocket server instance. #### Handshake: `client_connect()` Initiates the client-side WebSocket handshake process. #### Handshake Validation: `client_accept()` Validates the server's response during the client handshake. #### Handshake Response: `server_accept()` Generates the server's response for the WebSocket handshake. #### Frame Decoding: `read()` Decodes incoming WebSocket frames. #### Frame Encoding: `write()` Encodes outgoing WebSocket frames. #### Lifecycle: `close()` Initiates the WebSocket connection closing handshake. #### State Access: `state()` Returns the current state of the WebSocket connection. ``` -------------------------------- ### Framer Convenience (Recommended) Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Convenience functions for using the stream-based Framer, which simplifies reading and writing complete WebSocket frames. ```APIDOC ## Framer Convenience (Recommended) ### Description Convenience functions for using the stream-based Framer, which simplifies reading and writing complete WebSocket frames. ### Functions - `Framer::new()`: Create a new stream-based Framer instance. - `Framer::connect()`: Establish a client connection using the Framer (async-ready). - `Framer::accept()`: Accept a server connection using the Framer (async-ready). - `Framer::read()`: Read a complete WebSocket frame using the Framer. - `Framer::write()`: Send a complete WebSocket frame using the Framer. - `Framer::close()`: Send a close frame using the Framer. ``` -------------------------------- ### Low-Level WebSocket: Client Handshake Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/README.md Perform the initial client handshake for a low-level WebSocket connection. This involves sending a connection request and receiving a response to establish the connection. ```rust // Handshake let (len, key) = ws.client_connect(&options, &mut buffer)?; // ... send buffer, receive response ... ws.client_accept(&key, &response)?; ``` -------------------------------- ### No-Panic Error Recovery for Writes Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/errors.md Demonstrates writing data to a WebSocket connection without panicking, even when encountering errors like a buffer being too small. This ensures fault tolerance by returning an error that can be handled, such as retrying with a larger buffer or fragmenting the message. ```rust // This will not panic; it returns an error let result = websocket.write( WebSocketSendMessageType::Text, true, large_message, small_buffer // Too small )?; // Error: WriteToBufferTooSmall // Safe to retry with larger buffer or fragment the message ``` -------------------------------- ### WebSocket Lifecycle (Handshake) Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/INDEX.md Functions for initiating and managing the WebSocket handshake process, essential for establishing a connection. ```APIDOC ## WebSocket Lifecycle (Handshake) ### Description Functions for initiating and managing the WebSocket handshake process, essential for establishing a connection. ### Functions - `WebSocket::new_client(rng)`: Create a new client WebSocket instance. - `WebSocket::new_server()`: Create a new server WebSocket instance. - `WebSocket::client_connect()`: Send the client's opening handshake request. - `WebSocket::client_accept()`: Validate the server's response to a client handshake. - `WebSocket::server_accept()`: Send the server's opening handshake response. - `read_http_header()`: Parse the client's handshake request. ``` -------------------------------- ### Initiate WebSocket Close Handshake Source: https://github.com/ninjasource/embedded-websocket/blob/master/_autodocs/framer.md Initiates a close handshake and writes the close frame to the stream. An optional UTF-8 description can be provided, with a maximum length of 254 bytes. ```rust pub fn close( &mut self, stream: &mut impl Stream, close_status: WebSocketCloseStatusCode, status_description: Option<&str>, ) -> Result<(), FramerError> ``` ```rust framer.close( &mut stream, WebSocketCloseStatusCode::NormalClosure, Some("Goodbye"), )?; ```