use hyper::{
body::{Body, Incoming},
service::service_fn,
Request, Response,
};
use hyper_util::rt::TokioIo;
use std::{future::Future, io, path::Path};
use uds_windows::UnixListener;
use crate::windows::convert_unix_stream_to_nb_tcp_stream;
#[derive(Debug)]
pub struct CommonUnixListener(UnixListener);
impl CommonUnixListener {
pub fn bind(path: impl AsRef<Path>) -> io::Result<Self> {
UnixListener::bind(path).map(Self)
}
}
pub trait UnixListenerExt {
fn serve<MakeResponseFn, ResponseFn, ResponseFuture, B, E>(
self,
f: MakeResponseFn,
) -> impl Future<Output = Result<(), Box<dyn std::error::Error + Send + Sync>>>
where
MakeResponseFn: Fn() -> ResponseFn,
ResponseFn: Fn(Request<Incoming>) -> ResponseFuture,
ResponseFuture: Future<Output = Result<Response<B>, E>>,
B: Body + 'static,
<B as Body>::Error: std::error::Error + Send + Sync,
E: std::error::Error + Send + Sync + 'static;
}
impl UnixListenerExt for UnixListener {
fn serve<MakeServiceFn, ResponseFn, ResponseFuture, B, E>(
self,
f: MakeServiceFn,
) -> impl Future<Output = Result<(), Box<dyn std::error::Error + Send + Sync>>>
where
MakeServiceFn: Fn() -> ResponseFn,
ResponseFn: Fn(Request<Incoming>) -> ResponseFuture,
ResponseFuture: Future<Output = Result<Response<B>, E>>,
B: Body + 'static,
<B as Body>::Error: std::error::Error + Send + Sync,
E: std::error::Error + Send + Sync + 'static,
{
let (tx, mut rx) = tokio::sync::mpsc::channel(32);
std::thread::spawn(move || {
loop {
let result = self.accept();
let result_was_err = result.is_err();
if tx.blocking_send(result).is_err() {
break;
}
if result_was_err {
break;
}
}
});
async move {
while let Some(result) = rx.recv().await {
let (stream, _addr) = result?;
let stream =
tokio::net::TcpStream::from_std(convert_unix_stream_to_nb_tcp_stream(stream))
.unwrap();
let io = TokioIo::new(stream);
let svc_fn = service_fn(f());
hyper::server::conn::http1::Builder::new()
.keep_alive(false)
.serve_connection(io, svc_fn)
.await?;
}
Err("UnixListener closed".into())
}
}
}
impl UnixListenerExt for CommonUnixListener {
fn serve<MakeServiceFn, ResponseFn, ResponseFuture, B, E>(
self,
f: MakeServiceFn,
) -> impl Future<Output = Result<(), Box<dyn std::error::Error + Send + Sync>>>
where
MakeServiceFn: Fn() -> ResponseFn,
ResponseFn: Fn(Request<Incoming>) -> ResponseFuture,
ResponseFuture: Future<Output = Result<Response<B>, E>>,
B: Body + 'static,
<B as Body>::Error: std::error::Error + Send + Sync,
E: std::error::Error + Send + Sync + 'static,
{
self.0.serve(f)
}
}