A lightweight, async WebSocket protocol for Rust.
## Introduction `session-rs` is a small request/response + notification protocol that runs over WebSockets, with typed methods on both ends. - **Typed methods**: requests, responses and errors are (de)serialized for you. - **Both directions**: either peer can send requests and notifications. - **Transport-agnostic**: the protocol runs over any `Sink`/`Stream` of frames. Adapters ship for [tokio-tungstenite](https://docs.rs/tokio-tungstenite) and [axum](https://docs.rs/axum). - **Bounded**: the built-in server limits message and frame sizes (1 MiB by default). ## Installation ```bash cargo add session-rs ``` | Feature | Default | Enables | | --- | --- | --- | | `server` | yes | `SessionServer`, a standalone WebSocket server | | `client` | yes | `Session::connect` for `ws://` URLs | | `rustls` / `native-tls` | no | `wss://` URLs in `Session::connect` | | `axum` | no | `Session::from_axum` for axum WebSocket upgrades | ## Usage Define a method once and share it between both peers: ```rust #[derive(Debug, Serialize, Deserialize)] struct Data; impl Method for Data { const NAME: &'static str = "data"; type Request = String; type Response = String; type Error = String; } ``` ### Server ```rust let server = SessionServer::bind("127.0.0.1:8080").await?; server .session_loop(async |session, addr| { // Runs for every new client. Register handlers here; the session // starts reading once this returns, so no message arrives early. session .on_request::(async |_id, req| Ok(format!("echo: {req}"))) .await; Ok(()) }) .await?; ``` Use `SessionServer::with_config(ServerConfig { .. })` to change the size limits or the handshake timeout. ### Client ```rust let session = Session::connect("ws://127.0.0.1:8080").await?; session.start_receiver(); let reply = session.request::("Hello".to_string()).await?; // Ok("echo: Hello") ``` ### axum With the `axum` feature, a session can share a router with ordinary HTTP routes, such as a health check: ```rust async fn ws(upgrade: WebSocketUpgrade) -> Response { upgrade.max_message_size(1 << 20).on_upgrade(async |socket| { let session = Session::from_axum(socket); session.on_request::(async |_, req| Ok(req)).await; session.start_receiver(); }) } let app = Router::new() .route("/", get(ws)) .route("/health", get(async || "ok")); ``` ### Other transports `Session::from_transport(sink, stream)` accepts any `Sink` and `Stream