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

            
3
use echo_protocol::EchoChannel;
4
use jetstream::prelude::*;
5
use jetstream_macros::service;
6
use jetstream_rpc::{client::ClientCodec, server::run, Framed};
7
use okstd::prelude::*;
8
use s2n_quic::{client::Connect, provider::tls, Client, Server};
9

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

            
15
struct EchoImpl {}
16

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

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

            
36
#[cfg(not(windows))]
37
async fn server() -> Result<(), Box<dyn std::error::Error>> {
38
    #[cfg(windows)]
39
    return Ok(());
40

            
41
    #[cfg(not(windows))]
42
    let tls = tls::default::Server::builder()
43
        .with_trusted_certificate(Path::new(CA_CERT_PEM))?
44
        .with_certificate(
45
            Path::new(SERVER_CERT_PEM),
46
            Path::new(SERVER_KEY_PEM),
47
        )?
48
        .with_client_authentication()?
49
        .build()?;
50

            
51
    let mut server = Server::builder()
52
        .with_tls(tls)?
53
        .with_io("127.0.0.1:4433")?
54
        .start()?;
55

            
56
    while let Some(mut connection) = server.accept().await {
57
        // spawn a new task for the connection
58
        tokio::spawn(async move {
59
            eprintln!(
60
                "Connection accepted from {:?}",
61
                connection.remote_addr()
62
            );
63

            
64
            while let Ok(Some(stream)) =
65
                connection.accept_bidirectional_stream().await
66
            {
67
                // spawn a new task for the stream
68
                tokio::spawn(async move {
69
                    eprintln!(
70
                        "Stream opened from {:?}",
71
                        &stream.connection().remote_addr()
72
                    );
73
                    let echo = EchoImpl {};
74
                    let servercodec: jetstream::prelude::server::ServerCodec<
75
                        echo_protocol::EchoService<EchoImpl>,
76
                    > = Default::default();
77
                    let framed = Framed::new(stream, servercodec);
78
                    let mut serv = echo_protocol::EchoService { inner: echo };
79
                    run(&mut serv, framed).await.unwrap();
80
                });
81
            }
82
        });
83
    }
84

            
85
    Ok(())
86
}
87
#[cfg(not(windows))]
88
async fn client() -> Result<(), Box<dyn std::error::Error>> {
89
    let tls = tls::default::Client::builder()
90
        .with_certificate(Path::new(CA_CERT_PEM))?
91
        .with_client_identity(
92
            Path::new(CLIENT_CERT_PEM),
93
            Path::new(CLIENT_KEY_PEM),
94
        )?
95
        .build()?;
96

            
97
    let client = Client::builder()
98
        .with_tls(tls)?
99
        .with_io("0.0.0.0:0")?
100
        .start()?;
101

            
102
    let addr: SocketAddr = "127.0.0.1:4433".parse()?;
103
    let connect = Connect::new(addr).with_server_name("localhost");
104
    let mut connection = client.connect(connect).await?;
105

            
106
    // ensure the connection doesn't time out with inactivity
107
    connection.keep_alive(true)?;
108

            
109
    // open a new stream and split the receiving and sending sides
110
    let stream = connection.open_bidirectional_stream().await?;
111
    let client_codec: ClientCodec<EchoChannel> = Default::default();
112
    let mut framed = Framed::new(stream, client_codec);
113
    let mut chan = EchoChannel {
114
        inner: Box::new(&mut framed),
115
    };
116
    eprintln!("Ping sent");
117
    chan.ping().await?;
118
    eprintln!("Pong received");
119
    Ok(())
120
}
121

            
122
#[okstd::main]
123
#[cfg(not(windows))]
124
async fn main() {
125
    tokio::select! {
126
      _ = server() => {},
127
      _ = client() => {},
128
    }
129
}
130

            
131
#[cfg(windows)]
132
fn main() {}