blunt 0.0.8

Highly opinionated way to build asynchronous Websocket servers with Rust.
Documentation
use blunt::websocket::{WebSocketHandler, WebSocketMessage, WebSocketSession};
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use std::time::{Duration, Instant};
use tokio::task::JoinHandle;

#[derive(Debug, Default)]
pub struct EchoServer;

#[blunt::async_trait]
impl WebSocketHandler for EchoServer {
    async fn on_open(&mut self, _ws: &WebSocketSession) {}
    async fn on_message(&mut self, ws: &WebSocketSession, msg: WebSocketMessage) {
        match ws.send(msg) {
            Ok(_) => (),
            Err(e) => eprintln!("Unable to send: {:?}", e),
        };
    }

    async fn on_close(&mut self, _ws: &WebSocketSession, _msg: WebSocketMessage) {}
}

fn start_echo_server() -> JoinHandle<()> {
    tokio::spawn(async {
        let handler = EchoServer::default();
        let _ = ::blunt::builder()
            .for_path("/echo", handler)
            .build()
            .bind("127.0.0.1:9999".parse().expect("Invalid Socket Addr"))
            .await;
    })
}

fn single_echo_benchmark(c: &mut Criterion) {
    use tungstenite::{connect, Message};

    let rt = tokio::runtime::Runtime::new().unwrap();
    rt.block_on(async {
        let _server_handle = start_echo_server();
        let (mut socket, _response) = connect("ws://localhost:9999/echo").expect("Can't connect");

        let mut group = c.benchmark_group("single echo server");
        group.throughput(Throughput::Elements(100));
        group.bench_function("100 - Send only", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for _n in 0..iters {
                    socket.write_message(black_box(ws_message.clone())).unwrap();
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("single echo server");
        group.throughput(Throughput::Elements(100));
        group.bench_function("100 - Send and receive", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for _n in 0..iters {
                    socket.write_message(black_box(ws_message.clone())).unwrap();
                    let _ = socket.read_message().expect("Error reading message");
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("single echo server");
        group.throughput(Throughput::Elements(1000));
        group.bench_function("1000 - Send only", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for _n in 0..iters {
                    socket.write_message(black_box(ws_message.clone())).unwrap();
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("single echo server");
        group.throughput(Throughput::Elements(1000));
        group.bench_function("1000 - Send and receive", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for _n in 0..iters {
                    socket.write_message(black_box(ws_message.clone())).unwrap();
                    let _ = socket.read_message().expect("Error reading message");
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("single echo server");
        group.throughput(Throughput::Elements(10000));
        group.bench_function("10000 - Send only", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for _n in 0..iters {
                    socket.write_message(black_box(ws_message.clone())).unwrap();
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("single echo server");
        group.throughput(Throughput::Elements(10000));
        group.bench_function("10000 - Send and receive", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for _n in 0..iters {
                    socket.write_message(black_box(ws_message.clone())).unwrap();
                    let _ = socket.read_message().expect("Error reading message");
                }

                start.elapsed()
            })
        });

        group.finish();
    });
}

fn start_multi_echo_server() -> JoinHandle<()> {
    tokio::spawn(async {
        let handler = EchoServer::default();
        let handler2 = EchoServer::default();
        let _ = ::blunt::builder()
            .for_path("/echo", handler)
            .for_path("/echo2", handler2)
            .build()
            .bind("127.0.0.1:9999".parse().expect("Invalid Socket Addr"))
            .await;
    })
}

fn multi_echo_benchmark(c: &mut Criterion) {
    use tungstenite::{connect, Message};

    let rt = tokio::runtime::Runtime::new().unwrap();
    rt.block_on(async {
        let _multi_server_handle = start_multi_echo_server();
        let (mut socket, _response) = connect("ws://localhost:9999/echo").expect("Can't connect");
        let (mut socket2, _response) = connect("ws://localhost:9999/echo2").expect("Can't connect");

        let mut group = c.benchmark_group("multi echo server");
        group.throughput(Throughput::Elements(100));
        group.bench_function("100 - Send only", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for n in 0..iters {
                    if n % 2 == 0 {
                        socket.write_message(black_box(ws_message.clone())).unwrap();
                    } else {
                        socket2
                            .write_message(black_box(ws_message.clone()))
                            .unwrap();
                    }
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("multi echo server");
        group.throughput(Throughput::Elements(100));
        group.bench_function("100 - Send and receive", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for n in 0..iters {
                    if n % 2 == 0 {
                        socket.write_message(black_box(ws_message.clone())).unwrap();
                        let _ = socket.read_message().expect("Error reading message");
                    } else {
                        socket2
                            .write_message(black_box(ws_message.clone()))
                            .unwrap();
                        let _ = socket2.read_message().expect("Error reading message");
                    }
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("multi echo server");
        group.measurement_time(Duration::from_secs(15));
        group.throughput(Throughput::Elements(1000));
        group.bench_function("1000 - Send only", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for n in 0..iters {
                    if n % 2 == 0 {
                        socket.write_message(black_box(ws_message.clone())).unwrap();
                    } else {
                        socket2
                            .write_message(black_box(ws_message.clone()))
                            .unwrap();
                    }
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("multi echo server");
        group.measurement_time(Duration::from_secs(15));
        group.throughput(Throughput::Elements(1000));
        group.bench_function("1000 - Send and receive", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for n in 0..iters {
                    if n % 2 == 0 {
                        socket.write_message(black_box(ws_message.clone())).unwrap();
                        let _ = socket.read_message().expect("Error reading message");
                    } else {
                        socket2
                            .write_message(black_box(ws_message.clone()))
                            .unwrap();
                        let _ = socket2.read_message().expect("Error reading message");
                    }
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("multi echo server");
        group.measurement_time(Duration::from_secs(100));
        group.throughput(Throughput::Elements(10000));
        group.bench_function("10000 - Send only", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for n in 0..iters {
                    if n % 2 == 0 {
                        socket.write_message(black_box(ws_message.clone())).unwrap();
                    } else {
                        socket2
                            .write_message(black_box(ws_message.clone()))
                            .unwrap();
                    }
                }

                start.elapsed()
            })
        });

        group.finish();

        let mut group = c.benchmark_group("multi echo server");
        group.measurement_time(Duration::from_secs(100));
        group.throughput(Throughput::Elements(10000));
        group.bench_function("10000 - Send and receive", |b| {
            b.iter_custom(|iters| {
                let ws_message = Message::Text(String::from("Hello World!"));
                let start = Instant::now();
                for n in 0..iters {
                    if n % 2 == 0 {
                        socket.write_message(black_box(ws_message.clone())).unwrap();
                        let _ = socket.read_message().expect("Error reading message");
                    } else {
                        socket2
                            .write_message(black_box(ws_message.clone()))
                            .unwrap();
                        let _ = socket2.read_message().expect("Error reading message");
                    }
                }

                start.elapsed()
            })
        });

        group.finish();
    });
}

criterion_group!(benches, single_echo_benchmark, multi_echo_benchmark);
criterion_main!(benches);