async-rustls-stream 0.1.1

An async tls stream library based on rustls and futures-io. Both for server/client.
Documentation
use async_executor::Executor;
use async_rustls_stream::{TlsAccepted, TlsConnector};
use blocking::Unblock;
use futures_lite::{io::BufReader, AsyncBufReadExt, AsyncReadExt, AsyncWriteExt};
use rustls::ServerConfig;
use std::{
    io::{Cursor, Write},
    net::Ipv4Addr,
    sync::Arc,
    time::Duration,
};

static EX: Executor = Executor::new();

fn main() {
    let ca_cert: Vec<_> = rustls_pemfile::certs(&mut Cursor::new(include_bytes!("../cert/ca.crt")))
        .unwrap()
        .into_iter()
        .map(|x| rustls::Certificate(x))
        .collect();
    let ca_key: Vec<_> =
        rustls_pemfile::rsa_private_keys(&mut Cursor::new(include_bytes!("../cert/ca.key")))
            .unwrap()
            .into_iter()
            .map(|x| rustls::PrivateKey(x))
            .collect();

    let server_config = ServerConfig::builder()
        .with_safe_defaults()
        .with_no_client_auth()
        .with_single_cert(ca_cert.clone(), ca_key[0].clone())
        .unwrap();
    let server_config = Arc::new(server_config);
    EX.spawn(async move {
        let listener = async_net::TcpListener::bind((Ipv4Addr::LOCALHOST, 4443))
            .await
            .unwrap();
        loop {
            let (stream, remote_addr) = listener.accept().await.unwrap();
            let server_config = server_config.clone();
            EX.spawn(async move {
                println!("[Server] accept {}", remote_addr);
                let accept = TlsAccepted::accept(stream).await.unwrap();
                let mut stream = accept.into_stream(server_config).unwrap();
                stream.flush().await.unwrap();
                println!("[Server] Hello");

                let mut buf = [0; 1024];
                loop {
                    buf.fill(0);
                    let n = stream.read(&mut buf).await.unwrap();
                    let str = String::from_utf8_lossy(&buf[..n]);

                    if str == "q" {
                        println!("[Server] Exit");
                        break;
                    }
                    println!("[Server] {}", str);
                    stream.write_all(&buf[..n]).await.unwrap();
                    stream.flush().await.unwrap();
                }
            })
            .detach();
        }
    })
    .detach();

    let mut root_store = rustls::RootCertStore::empty();
    root_store.add(&ca_cert[0]).unwrap();
    let config = Arc::new(
        rustls::ClientConfig::builder()
            .with_safe_defaults()
            .with_root_certificates(root_store)
            .with_no_client_auth(),
    );
    let server_name = "test.com".try_into().unwrap();
    let client_task = EX.spawn(async move {
        let connector = TlsConnector::new(config.clone(), server_name).unwrap();
        let stream = async_net::TcpStream::connect((Ipv4Addr::LOCALHOST, 4443))
            .await
            .unwrap();
        let mut stream = connector.connect(stream);
        stream.flush().await.unwrap();
        println!("[Client] Hello");
        async_io::Timer::after(Duration::from_millis(1)).await;

        let stdin = Unblock::new(std::io::stdin());
        let mut stdin = BufReader::new(stdin);

        let mut buf = [0; 1024];
        let mut line = String::new();
        loop {
            line.clear();
            print!("you say (q to exit):");
            std::io::stdout().flush().unwrap();
            stdin.read_line(&mut line).await.unwrap();
            let line = line.trim_end();
            if line.is_empty() {
                continue;
            }
            stream.write_all(line.as_bytes()).await.unwrap();
            stream.flush().await.unwrap();

            if line == "q" {
                println!("[Client] Exit");
                break;
            }

            let n = stream.read(&mut buf).await.unwrap();
            let back = String::from_utf8_lossy(&buf[..n]);
            println!("[Client] {}", back);
        }
    });

    async_io::block_on(EX.run(client_task));
}