monoio-tungstenite

Crates.iomonoio-tungstenite
lib.rsmonoio-tungstenite
version0.3.0
created_at2025-07-25 12:32:55.843199+00
updated_at2025-09-15 10:47:48.339223+00
descriptionAsynchronous WebSocket implementation for monoio runtime, adapted from tungstenite.
homepage
repositoryhttps://github.com/pikanohup/monoio-tungstenite
max_upload_size
id1767575
size384,055
pika (pikanohup)

documentation

https://docs.rs/monoio-tungstenite

README

monoio-tungstenite

Lightweight, asynchronous WebSocket implementation for monoio runtime, adapted from tungstenite-rs.

use monoio::{
    io::{sink::SinkExt, stream::Stream},
    net::TcpListener,
};
use monoio_tungstenite::accept;

/// A WebSocket echo server.
#[monoio::main]
async fn main() {
    let server = TcpListener::bind("127.0.0.1:9001").unwrap();

    while let Ok((stream, _)) = server.accept().await {
        monoio::spawn(async move {
            let mut websocket = accept(stream).await.unwrap();

            while let Some(Ok(msg)) = websocket.next().await {
                // We do not want to send back ping/pong messages.
                if msg.is_binary() || msg.is_text() {
                    websocket.send_and_flush(msg).await.unwrap();
                }
            }
        });
    }
}

For more examples, please refer to the examples/ directory.

[!IMPORTANT] This project was initially developed for personal use and has not been battle-tested in large-scale production environments. Please use it with caution, especially in production systems.

Crates.io Docs.rs License Build Status

Introduction

This crate offers a native WebSocket implementation for monoio, based on the widely-used and reliable tungstenite-rs. Instead of relying on IntoPollIo to simply wrap and reuse tokio-tungstenite or other poll-based libraries, it is built directly on monoio's native IO model (AsyncReadRent/AsyncWriteRent), fully utilizing io_uring's capabilities while ensuring seamless ecosystem integration.

Features

monoio-tungstenite provides a complete implementation of the WebSocket specification. TLS is supported on all platforms using native-tls or rustls . The following features are available:

  • native-tls: Enables TLS support using the native-tls crate.
  • native-tls-vendored: Same as native-tls but vendors OpenSSL for Linux builds.
  • rustls-tls: Enables TLS support using the rustls crate.
  • rustls-tls-native-roots: Enables rustls with native root certificates.
  • rustls-tls-webpki-roots: Enables rustls with root certificates from the webpki-roots crate.
  • rustls-tls-unsafe-io: Exposes the unsafe_io feature in monoio-rustls to work around a known io-cancellation issue. Please read the "Known Issues" section carefully for crucial details before using this feature.

Choose the one that is appropriate for your needs.

By default no TLS feature is activated, so make sure you use one of the TLS features, otherwise you won't be able to communicate with the TLS endpoints.

Please note that permessage-deflate is not supported at this time.

Testing

monoio-tungstenite passes the Autobahn Testsuite. It is also covered by internal unit tests as well as possible.

Known Issues

Concurrency with TLS and Cancellation Safety

When using select! for concurrent reads and writes on a WebSocket<Stream> with any TLS backend (rustls or native-tls), you may encounter a runtime panic. This is due to an upstream issue in monoio-io-wrapper, a crate used by both monoio-rustls and monoio-native-tls, where its default SafeRead is not cancellation-safe. Concurrent operations in select! can lead to one operation being cancelled, which triggers the panic.

For more details and the original discussion, please see this issue.

Workaround

For users of the rustls backend, a workaround is available. It requires enabling the rustls-tls-unsafe-io feature in monoio-tungstenite, which in turn allows you to use the unsafe_io() method on a TlsConnector to create a connector configured for the alternative IO mode. For example:

use monoio_tungstenite::client::connect_tls_with_config;
use monoio_tungstenite::tls::rustls::default_connector;

...

let connector = default_connector()?;
let connector = unsafe { connector.unsafe_io(true) };
let (mut ws, _) = connect_tls_with_config("wss://example.com", None, false, Some(connector.into())).await?;

[!WARNING] While it resolves the immediate panic, the unsafe designation implies there may be potential side effects or subtle bugs that have not been fully investigated within the context of this library. By calling the unsafe method, you are opting into this mode and acknowledging these potential unknown risks. Please use this feature with caution. The recommended long-term solution remains a proper fix in the upstream dependency.

Currently, this workaround is not available for the native-tls backend as the underlying monoio-native-tls crate does not expose the unsafe_io option.

License

This project is dual-licensed, allowing you to choose between either the MIT License or the Apache-2.0 License at your option.

For details on third-party library attributions, please see the NOTICE file.

Commit count: 16

cargo fmt