#![cfg(feature="dual_server")]
use std::prelude::v1::*;
use core::error::Error;
use product_os_net::SocketAddr;
use hyper::service::Service;
use product_os_async_executor::{Executor, TokioExecutor};
use product_os_router::{Request, Service as RouterService, Router, UpgradeHttpLayer, Protocol};
use product_os_security::certificates::Certificates;
pub async fn create_dual_tokio_service(socket_address: SocketAddr, certs: Option<Certificates>, router: Router, with_connect_info: bool) -> Result<(), Box<dyn Error + Send + Sync>> {
let tls_config = crate::https_server::create_rustls_config(certs)?;
tracing::info!("Starting HTTPS server listening on {}", socket_address);
let tls_acceptor = tokio_rustls::TlsAcceptor::from(tls_config);
let listener = tokio::net::TcpListener::bind(socket_address).await
.map_err(|e| -> Box<dyn Error + Send + Sync> { Box::new(e) })?;
match with_connect_info {
true => {
let router_service = router.clone()
.layer(UpgradeHttpLayer {})
.layer(tower::util::MapRequestLayer::new(|mut req: Request<hyper::body::Incoming>| {
req.extensions_mut().insert(Protocol::Tls);
req
}))
.into_make_service_with_connect_info::<SocketAddr>();
let make_service = hyper_util::service::TowerToHyperService::new(router_service);
let tower_service = make_service.call(socket_address).await
.map_err(|e| -> Box<dyn Error + Send + Sync> { Box::new(e) })?;
loop {
let (cnx, addr) = match listener.accept().await {
Ok(conn) => conn,
Err(e) => {
tracing::error!("Failed to accept connection: {:?}", e);
continue;
}
};
let tls_acceptor = tls_acceptor.clone();
let tower_service = tower_service.clone();
tokio::spawn(async move {
let stream = match tls_acceptor.accept(cnx).await {
Ok(s) => s,
Err(e) => {
tracing::error!("error during tls handshake connection from {}: {:?}", addr, e);
return;
}
};
let stream = hyper_util::rt::TokioIo::new(stream);
let hyper_service = hyper::service::service_fn(move |request: Request<hyper::body::Incoming>| {
tower_service.clone().call(request)
});
match TokioExecutor::context_sync() {
Ok(executor) => {
let _ret = hyper_util::server::conn::auto::Builder::new(executor)
.serve_connection_with_upgrades(stream, hyper_service)
.await;
if let Err(err) = _ret {
tracing::warn!("error serving connection from {}: {}", addr, err);
}
}
Err(e) => tracing::error!("Failed to get executor for connection from {}: {:?}", addr, e)
}
});
}
}
false => {
let tower_service = router
.layer(UpgradeHttpLayer {})
.layer(tower::util::MapRequestLayer::new(|mut req: Request<hyper::body::Incoming>| {
req.extensions_mut().insert(Protocol::Tls);
req
}));
loop {
let (cnx, addr) = match listener.accept().await {
Ok(conn) => conn,
Err(e) => {
tracing::error!("Failed to accept connection: {:?}", e);
continue;
}
};
let tls_acceptor = tls_acceptor.clone();
let tower_service = tower_service.clone();
tokio::spawn(async move {
let Ok(stream) = tls_acceptor.accept(cnx).await else {
tracing::error!("error during tls handshake connection from {}", addr);
return;
};
let stream = hyper_util::rt::TokioIo::new(stream);
let hyper_service = hyper::service::service_fn(move |request: Request<hyper::body::Incoming>| {
tower_service.clone().call(request)
});
match TokioExecutor::context_sync() {
Ok(executor) => {
let _ret = hyper_util::server::conn::auto::Builder::new(executor)
.serve_connection_with_upgrades(stream, hyper_service)
.await;
if let Err(err) = _ret {
tracing::warn!("error serving connection from {}: {}", addr, err);
}
}
Err(e) => tracing::error!("Failed to get executor for connection from {}: {:?}", addr, e)
}
});
}
}
}
}