use rama::{
Context, Layer,
graceful::Shutdown,
layer::ConsumeErrLayer,
net::forwarded::Forwarded,
net::stream::{SocketInfo, Stream},
proxy::haproxy::{
client::HaProxyLayer as HaProxyClientLayer, server::HaProxyLayer as HaProxyServerLayer,
},
service::service_fn,
tcp::{
client::service::{Forwarder, TcpConnector},
server::TcpListener,
},
tls::rustls::server::{TlsAcceptorDataBuilder, TlsAcceptorLayer},
};
use rama_net::tls::server::SelfSignedData;
use std::{convert::Infallible, time::Duration};
use tokio::io::AsyncWriteExt;
use tracing::metadata::LevelFilter;
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
#[tokio::main]
async fn main() {
tracing_subscriber::registry()
.with(fmt::layer())
.with(
EnvFilter::builder()
.with_default_directive(LevelFilter::DEBUG.into())
.from_env_lossy(),
)
.init();
let acceptor_data = TlsAcceptorDataBuilder::new_self_signed(SelfSignedData::default())
.expect("tls acceptor with self signed data")
.with_env_key_logger()
.expect("with env key logger")
.build();
let shutdown = Shutdown::default();
shutdown.spawn_task_fn(async move |guard| {
let tcp_service = TlsAcceptorLayer::new(acceptor_data).into_layer(
Forwarder::new(([127, 0, 0, 1], 62800)).connector(
HaProxyClientLayer::tcp().into_layer(TcpConnector::new()),
),
);
TcpListener::bind("127.0.0.1:63800")
.await
.expect("bind TCP Listener: tls")
.serve_graceful(guard, tcp_service)
.await;
});
shutdown.spawn_task_fn(async |guard| {
let tcp_service = (ConsumeErrLayer::default(), HaProxyServerLayer::new())
.into_layer(service_fn(internal_tcp_service_fn));
TcpListener::bind("127.0.0.1:62800")
.await
.expect("bind TCP Listener: http")
.serve_graceful(guard, tcp_service)
.await;
});
shutdown
.shutdown_with_limit(Duration::from_secs(30))
.await
.expect("graceful shutdown");
}
async fn internal_tcp_service_fn<S>(ctx: Context<()>, mut stream: S) -> Result<(), Infallible>
where
S: Stream + Unpin,
{
let client_addr = ctx
.get::<Forwarded>()
.unwrap()
.client_socket_addr()
.unwrap();
let proxy_addr = ctx.get::<SocketInfo>().unwrap().peer_addr();
let payload = format!(
"hello client {client_addr}, you were served by tls terminator proxy {proxy_addr}\r\n"
);
let response = format!(
"HTTP/1.0 200 ok\r\n\
Connection: close\r\n\
Content-length: {}\r\n\
\r\n\
{}",
payload.len(),
payload
);
stream
.write_all(response.as_bytes())
.await
.expect("write to stream");
Ok(())
}