use std::{net::SocketAddr, sync::Arc};
use hyper::{Request, body::Incoming, service::service_fn};
use hyper_util::rt::{TokioExecutor, TokioIo};
use rustls::ServerConfig;
use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;
use crate::{CertLoader, LoadCert, Result, Route, proxy};
pub async fn srv<D: LoadCert>(
addr: SocketAddr,
route: Arc<Route>,
cert_loader: Arc<CertLoader<D>>,
) -> Result<()> {
let listener = TcpListener::bind(addr).await?;
let mut tls_config = ServerConfig::builder()
.with_no_client_auth()
.with_cert_resolver(cert_loader);
tls_config.alpn_protocols = vec![b"h2".to_vec()];
let tls_acceptor = TlsAcceptor::from(Arc::new(tls_config));
loop {
let (stream, _remote_addr) = listener.accept().await?;
let tls_acceptor = tls_acceptor.clone();
let route = route.clone();
tokio::spawn(async move {
let stream = match tls_acceptor.accept(stream).await {
Ok(stream) => stream,
Err(err) => {
eprintln!("tls accept error: {}", err);
return;
}
};
let io = TokioIo::new(stream);
let service = service_fn(move |req: Request<Incoming>| {
let route = route.clone();
async move { Ok::<_, hyper::Error>(proxy(req, route).await) }
});
let conn_builder = hyper::server::conn::http2::Builder::new(TokioExecutor::new());
if let Err(err) = conn_builder.serve_connection(io, service).await {
eprintln!("h2 error: {}", err);
}
});
}
}