socketeer 0.3.0

Simplified websocket client based on Tokio-Tungstenite
Documentation

socketeer

Crates.io Version docs.rs GitHub branch status Codecov

socketeer is a simplified async WebSocket client built on tokio-tungstenite. It manages the underlying connection and exposes a clean API for sending and receiving messages, with support for:

  • Automatic connection management with configurable keepalive
  • Type-safe JSON message serialization/deserialization via serde
  • Raw message support for non-JSON protocols
  • Custom HTTP headers on the WebSocket upgrade request
  • Connection lifecycle hooks for auth handshakes and subscriptions
  • Transparent handling of WebSocket protocol messages (ping/pong/close)
  • Reconnection with automatic re-authentication

Usage

Simple JSON messages

use socketeer::Socketeer;

#[derive(Debug, serde::Serialize, serde::Deserialize)]
struct SocketMessage {
    message: String,
}

#[tokio::main]
async fn main() {
    let mut socketeer: Socketeer<SocketMessage, SocketMessage> =
        Socketeer::connect("ws://127.0.0.1:80")
            .await
            .unwrap();
    socketeer
        .send(SocketMessage {
            message: "Hello, world!".to_string(),
        })
        .await
        .unwrap();
    let response = socketeer.next_message().await.unwrap();
    println!("{response:#?}");
    socketeer.close_connection().await.unwrap();
}

Custom headers and connection options

use socketeer::{Socketeer, ConnectOptions};
use std::time::Duration;

# #[derive(Debug, serde::Serialize, serde::Deserialize)]
# struct Msg { text: String }
# #[tokio::main]
# async fn main() {
let mut options = ConnectOptions::default();
options.extra_headers.insert("Authorization", "Bearer my-token".parse().unwrap());
options.keepalive_interval = Some(Duration::from_secs(10));

let socketeer: Socketeer<Msg, Msg> =
    Socketeer::connect_with("wss://api.example.com/ws", options)
        .await
        .unwrap();
# }

Connection lifecycle hooks

use socketeer::{Socketeer, ConnectOptions, ConnectionHandler, HandshakeContext, Error};

struct MyAuthHandler { api_key: String }

impl ConnectionHandler for MyAuthHandler {
    async fn on_connected(&mut self, ctx: &mut HandshakeContext<'_>) -> Result<(), Error> {
        ctx.send_text(&format!(r#"{{"action":"auth","key":"{}"}}"#, self.api_key)).await?;
        let _response = ctx.recv_text().await?;
        Ok(())
    }
}

# #[derive(Debug, serde::Serialize, serde::Deserialize)]
# struct Msg { text: String }
# #[tokio::main]
# async fn main() {
let handler = MyAuthHandler { api_key: "secret".into() };
let socketeer: Socketeer<Msg, Msg, MyAuthHandler> =
    Socketeer::connect_with_handler(
        "wss://stream.example.com",
        ConnectOptions::default(),
        handler,
    )
    .await
    .unwrap();
// Handler's on_connected runs again automatically on reconnect
# }