Expand description
zerocopy, async, no_std and autobahn compliant websockets implementation.
§Traits
This library is based on embedded_io_async’s
Read and Write and rand_core’s RngCore traits.
It’s recommended to use embedded_io_adapters if you are using other async Read and Write traits like tokio’s AsyncRead and AsyncWrite.
See the examples folder for more information.
§Examples
In the following examples, Noop is a mock type that implements the required traits for using a WebSocket.
- A
streamis anything that implementsembedded_io_async::Read+embedded_io_async::Write. - An
rngis anything that implementsrand_core::RngCore.
§Client
use websocketz::{Message, WebSocket, http::Header, next, options::ConnectOptions};
// An already connected stream.
// Impl embedded_io_async Read + Write.
let stream = Noop;
let read_buffer = &mut [0u8; 1024];
let write_buffer = &mut [0u8; 1024];
let fragments_buffer = &mut [0u8; 1024];
// Impl rand_core RngCore.
let rng = Noop;
// Perform a WebSocket handshake as a client.
// 16 is the max number of headers to allocate space for.
let mut websocketz = WebSocket::connect::<16>(
// Set the connection options.
// The path for the WebSocket endpoint as well as any additional HTTP headers.
ConnectOptions::default()
.with_path("/ws")
.expect("Valid path")
.with_headers(&[
Header {
name: "Host",
value: b"example.com",
},
Header {
name: "User-Agent",
value: b"WebSocketz",
},
]),
stream,
rng,
read_buffer,
write_buffer,
fragments_buffer,
)
.await
.expect("Handshake failed");
// Send a text message.
websocketz
.send(Message::Text("Hello, WebSocket!"))
.await
.expect("Failed to send message");
// Receive messages in a loop.
loop {
match next!(websocketz) {
None => {
// Connection closed.
break;
}
Some(Ok(msg)) => {
// Handle received message.
let _ = msg;
}
Some(Err(err)) => {
// Handle error.
let _ = err;
break;
}
}
}§Server
use websocketz::{Message, WebSocket, http::Header, next, options::AcceptOptions};
// An already connected stream.
// Impl embedded_io_async Read + Write.
let stream = Noop;
let read_buffer = &mut [0u8; 1024];
let write_buffer = &mut [0u8; 1024];
let fragments_buffer = &mut [0u8; 1024];
// Impl rand_core RngCore.
let rng: Noop = Noop;
// Perform a WebSocket handshake as a server.
// 16 is the max number of headers to allocate space for.
let mut websocketz = WebSocket::accept::<16>(
// Set the acceptance options.
// Any additional HTTP headers.
AcceptOptions::default().with_headers(&[Header {
name: "Server",
value: b"WebSocketz",
}]),
stream,
rng,
read_buffer,
write_buffer,
fragments_buffer,
)
.await
.expect("Handshake failed");
// Receive messages in a loop.
loop {
match next!(websocketz) {
None => {
// Connection closed.
break;
}
Some(Ok(msg)) => {
// Handle received message.
let _ = msg;
// Send a binary message.
if let Err(err) = websocketz.send(Message::Binary(b"Hello, WebSocket!")).await {
let _ = err;
break;
}
}
Some(Err(err)) => {
// Handle error.
let _ = err;
break;
}
}
}§Laziness
This library is lazy, meaning that the WebSocket connection is managed as long as you read from the connection.
Managing the connection consists of two parts:
- Sending Message::Pong messages in response to Message::Ping messages.
- Responding to Message::Close messages by sending the appropriate Message::Close response and closing the connection.
auto_pong and auto_close are enabled by default, but can be set using WebSocket::with_auto_pong and WebSocket::with_auto_close respectively.
§Reading from the connection
This library allocates nothing. It only uses exclusive references and stack memory. It is quite challenging to offer a clean API while adhering to rust’s borrowing rules.
That’s why a WebSocket does not offer any method to read messages directly.
Instead, you can use the next! macro to read messages from the connection.
next! unpacks the internal private structure of the WebSocket to obtain mutable references and perform reads.
let mut websocketz = existing_websocket();
while let Some(Ok(msg)) = next!(websocketz) {
// Messages hold references to the websocket buffers.
let _ = msg;
}§Writing to the connection
WebSocket offers two methods to send messages, WebSocket::send and WebSocket::send_fragmented.
These methods take &mut self, which might be problematic in some situations. E.g., echoing back a received message.
let mut websocketz = existing_websocket();
while let Some(Ok(msg)) = next!(websocketz) {
// Messages hold references to the websocket buffers.
// So this will not compile:
// cannot borrow `websocketz` as mutable more than once at a time.
websocketz.send(msg).await.expect("Failed to send message");
}To work around this limitation, the library offers the send! and send_fragmented! macros, which work similarly to the next! macro by unpacking the internal private structure of the WebSocket.
let mut websocketz = existing_websocket();
while let Some(Ok(msg)) = next!(websocketz) {
send!(websocketz, msg).expect("Failed to send message");
}§Splitting the connection
In some cases, you might want to split the WebSocket connection into a read half and a write half.
This can be achieved using the WebSocket::split_with method, which returns a WebSocketRead and WebSocketWrite tuple.
fn split(stream: Noop) -> (Noop, Noop) {
// Let's assume we split the stream here.
(Noop, Noop)
}
let websocketz = existing_websocket();
let (mut websocketz_read, mut websocketz_write) = websocketz.split_with(split);
websocketz_write
.send(Message::Text("Hello, WebSocket!"))
.await
.expect("Failed to send message");
while let Some(Ok(msg)) = next!(websocketz_read) {
// `send` method works here,
// because `websocketz_read` and `websocketz_write` do not hold the same references.
websocketz_write
.send(msg)
.await
.expect("Failed to send message");
}Modules§
- error
- Crate’s error module.
- http
- HTTP request and response types.
- options
- Options for establishing and accepting WebSocket connections.
Macros§
- next
- Read a
Messagefrom aWebSocketorWebSocketRead. - send
- Send a
Messagethrough aWebSocketorWebSocketWrite. - send_
fragmented - Send a fragmented
Messagethrough aWebSocketorWebSocketWrite.
Structs§
- Close
Frame - A WebSocket Close frame.
- WebSocket
- A WebSocket connection.
- WebSocket
Read - Read half of a WebSocket connection.
- WebSocket
Write - Write half of a WebSocket connection.