1
use std::{net::SocketAddr, path::Path};
2

            
3
use jetstream_rpc::Framed;
4

            
5
use {
6
    echo_protocol::EchoChannel,
7
    jetstream::prelude::*,
8
    jetstream_macros::service,
9
    okstd::prelude::*,
10
    s2n_quic::{client::Connect, provider::tls, Client, Server},
11
};
12

            
13
#[service]
14
pub trait Echo {
15
    async fn ping(&mut self) -> Result<(), Error>;
16
}
17

            
18
struct EchoImpl {}
19

            
20
impl Echo for EchoImpl {
21
    async fn ping(&mut self) -> Result<(), Error> {
22
        eprintln!("Ping received");
23
        eprintln!("Pong sent");
24
        Ok(())
25
    }
26
}
27

            
28
pub static CA_CERT_PEM: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/certs/ca-cert.pem");
29
pub static CLIENT_CERT_PEM: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/certs/client-cert.pem");
30
pub static CLIENT_KEY_PEM: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/certs/client-key.pem");
31
pub static SERVER_CERT_PEM: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/certs/server-cert.pem");
32
pub static SERVER_KEY_PEM: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/certs/server-key.pem");
33

            
34
async fn server() -> Result<(), Box<dyn std::error::Error>> {
35
    let tls = tls::default::Server::builder()
36
        .with_trusted_certificate(Path::new(CA_CERT_PEM))?
37
        .with_certificate(Path::new(SERVER_CERT_PEM), Path::new(SERVER_KEY_PEM))?
38
        .with_client_authentication()?
39
        .build()?;
40

            
41
    let mut server = Server::builder()
42
        .with_tls(tls)?
43
        .with_io("127.0.0.1:4433")?
44
        .start()?;
45

            
46
    while let Some(mut connection) = server.accept().await {
47
        // spawn a new task for the connection
48
        tokio::spawn(async move {
49
            eprintln!("Connection accepted from {:?}", connection.remote_addr());
50

            
51
            while let Ok(Some(stream)) = connection.accept_bidirectional_stream().await {
52
                // spawn a new task for the stream
53
                tokio::spawn(async move {
54
                    eprintln!(
55
                        "Stream opened from {:?}",
56
                        &stream.connection().remote_addr()
57
                    );
58
                    let echo = EchoImpl {};
59
                    let servercodec: jetstream::prelude::server::service::ServerCodec<
60
                        echo_protocol::EchoService<EchoImpl>,
61
                    > = Default::default();
62
                    let framed = Framed::new(stream, servercodec);
63
                    let mut serv = echo_protocol::EchoService { inner: echo };
64
                    server::service::run(&mut serv, framed).await.unwrap();
65
                });
66
            }
67
        });
68
    }
69

            
70
    Ok(())
71
}
72

            
73
async fn client() -> Result<(), Box<dyn std::error::Error>> {
74
    let tls = tls::default::Client::builder()
75
        .with_certificate(Path::new(CA_CERT_PEM))?
76
        .with_client_identity(Path::new(CLIENT_CERT_PEM), Path::new(CLIENT_KEY_PEM))?
77
        .build()?;
78

            
79
    let client = Client::builder()
80
        .with_tls(tls)?
81
        .with_io("0.0.0.0:0")?
82
        .start()?;
83

            
84
    let addr: SocketAddr = "127.0.0.1:4433".parse()?;
85
    let connect = Connect::new(addr).with_server_name("localhost");
86
    let mut connection = client.connect(connect).await?;
87

            
88
    // ensure the connection doesn't time out with inactivity
89
    connection.keep_alive(true)?;
90

            
91
    // open a new stream and split the receiving and sending sides
92
    let stream = connection.open_bidirectional_stream().await?;
93
    let client_codec: jetstream_client::ClientCodec<EchoChannel> = Default::default();
94
    let mut framed = Framed::new(stream, client_codec);
95
    let mut chan = EchoChannel {
96
        inner: Box::new(&mut framed),
97
    };
98
    eprintln!("Ping sent");
99
    chan.ping().await?;
100
    eprintln!("Pong received");
101
    Ok(())
102
}
103

            
104
#[okstd::main]
105
async fn main() {
106
    tokio::select! {
107
      _ = server() => {},
108
      _ = client() => {},
109
    }
110
}