tonic/transport/channel/
uds_connector.rs

1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use http::Uri;
6use hyper_util::rt::TokioIo;
7
8use tower::Service;
9
10use crate::status::ConnectError;
11
12#[cfg(not(target_os = "windows"))]
13use tokio::net::UnixStream;
14
15#[cfg(not(target_os = "windows"))]
16async fn connect_uds(uds_path: String) -> Result<UnixStream, ConnectError> {
17    UnixStream::connect(uds_path)
18        .await
19        .map_err(|err| ConnectError(From::from(err)))
20}
21
22// Dummy type that will allow us to compile and match trait bounds
23// but is never used.
24#[cfg(target_os = "windows")]
25#[allow(dead_code)]
26type UnixStream = tokio::io::DuplexStream;
27
28#[cfg(target_os = "windows")]
29async fn connect_uds(_uds_path: String) -> Result<UnixStream, ConnectError> {
30    Err(ConnectError(
31        "uds connections are not allowed on windows".into(),
32    ))
33}
34
35pub(crate) struct UdsConnector {
36    uds_filepath: String,
37}
38
39impl UdsConnector {
40    pub(crate) fn new(uds_filepath: &str) -> Self {
41        UdsConnector {
42            uds_filepath: uds_filepath.to_string(),
43        }
44    }
45}
46
47impl Service<Uri> for UdsConnector {
48    type Response = TokioIo<UnixStream>;
49    type Error = ConnectError;
50    type Future = UdsConnecting;
51
52    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
53        Poll::Ready(Ok(()))
54    }
55
56    fn call(&mut self, _: Uri) -> Self::Future {
57        let uds_path = self.uds_filepath.clone();
58        let fut = async move {
59            let stream = connect_uds(uds_path).await?;
60            Ok(TokioIo::new(stream))
61        };
62        UdsConnecting {
63            inner: Box::pin(fut),
64        }
65    }
66}
67
68type ConnectResult = Result<TokioIo<UnixStream>, ConnectError>;
69
70pub(crate) struct UdsConnecting {
71    inner: Pin<Box<dyn Future<Output = ConnectResult> + Send>>,
72}
73
74impl Future for UdsConnecting {
75    type Output = ConnectResult;
76
77    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
78        self.get_mut().inner.as_mut().poll(cx)
79    }
80}