use futures::{Future, TryFutureExt};
use hyper::{server::Server, service::make_service_fn};
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
use std::{convert::Infallible, net::SocketAddr};
use warp::{filters::BoxedFilter, Reply};
fn make_listener<T: Into<SocketAddr>>(addr: T) -> Result<std::net::TcpListener, anyhow::Error> {
let addr = addr.into();
let is_ipv4 = addr.is_ipv4();
let domain = if is_ipv4 { Domain::IPV4 } else { Domain::IPV6 };
let addr: SockAddr = addr.into();
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
socket.set_reuse_address(true)?;
if !is_ipv4 {
socket.set_only_v6(true)?;
}
socket.bind(&addr)?;
socket.listen(1024)?;
Ok(socket.into())
}
pub(crate) fn serve_it<T: Into<SocketAddr>>(
addr: T,
filter: BoxedFilter<(impl Reply + 'static,)>,
) -> anyhow::Result<(SocketAddr, impl Future<Output = anyhow::Result<()>>)> {
let filtered_service = warp::service(filter);
let make_svc = make_service_fn(move |_| {
let filtered_service = filtered_service.clone();
async move { Ok::<_, Infallible>(filtered_service) }
});
let listener = make_listener(addr)?;
let bound_to = listener.local_addr()?;
let builder = Server::from_tcp(listener)?;
let fut = builder.tcp_nodelay(true).serve(make_svc).map_err(|e| e.into());
Ok((bound_to, fut))
}