distant_net/server/builder/
unix.rs

1use std::io;
2use std::path::Path;
3
4use distant_auth::Verifier;
5use serde::de::DeserializeOwned;
6use serde::Serialize;
7
8use crate::common::{UnixSocketListener, Version};
9use crate::server::{Server, ServerConfig, ServerHandler, UnixSocketServerRef};
10
11pub struct UnixSocketServerBuilder<T>(Server<T>);
12
13impl<T> Server<T> {
14    /// Consume [`Server`] and produce a builder for a Unix socket variant.
15    pub fn into_unix_socket_builder(self) -> UnixSocketServerBuilder<T> {
16        UnixSocketServerBuilder(self)
17    }
18}
19
20impl Default for UnixSocketServerBuilder<()> {
21    fn default() -> Self {
22        Self(Server::new())
23    }
24}
25
26impl<T> UnixSocketServerBuilder<T> {
27    pub fn config(self, config: ServerConfig) -> Self {
28        Self(self.0.config(config))
29    }
30
31    pub fn handler<U>(self, handler: U) -> UnixSocketServerBuilder<U> {
32        UnixSocketServerBuilder(self.0.handler(handler))
33    }
34
35    pub fn verifier(self, verifier: Verifier) -> Self {
36        Self(self.0.verifier(verifier))
37    }
38
39    pub fn version(self, version: Version) -> Self {
40        Self(self.0.version(version))
41    }
42}
43
44impl<T> UnixSocketServerBuilder<T>
45where
46    T: ServerHandler + Sync + 'static,
47    T::Request: DeserializeOwned + Send + Sync + 'static,
48    T::Response: Serialize + Send + 'static,
49{
50    pub async fn start<P>(self, path: P) -> io::Result<UnixSocketServerRef>
51    where
52        P: AsRef<Path> + Send,
53    {
54        let path = path.as_ref();
55        let listener = UnixSocketListener::bind(path).await?;
56        let path = listener.path().to_path_buf();
57        let inner = self.0.start(listener)?;
58        Ok(UnixSocketServerRef { path, inner })
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use async_trait::async_trait;
65    use distant_auth::DummyAuthHandler;
66    use tempfile::NamedTempFile;
67    use test_log::test;
68
69    use super::*;
70    use crate::client::Client;
71    use crate::common::Request;
72    use crate::server::RequestCtx;
73
74    pub struct TestServerHandler;
75
76    #[async_trait]
77    impl ServerHandler for TestServerHandler {
78        type Request = String;
79        type Response = String;
80
81        async fn on_request(&self, ctx: RequestCtx<Self::Request, Self::Response>) {
82            // Echo back what we received
83            ctx.reply.send(ctx.request.payload.to_string()).unwrap();
84        }
85    }
86
87    #[test(tokio::test)]
88    async fn should_invoke_handler_upon_receiving_a_request() {
89        // Generate a socket path and delete the file after so there is nothing there
90        let path = NamedTempFile::new()
91            .expect("Failed to create socket file")
92            .path()
93            .to_path_buf();
94
95        let server = UnixSocketServerBuilder::default()
96            .handler(TestServerHandler)
97            .verifier(Verifier::none())
98            .start(path)
99            .await
100            .expect("Failed to start Unix socket server");
101
102        let mut client: Client<String, String> = Client::unix_socket(server.path())
103            .auth_handler(DummyAuthHandler)
104            .connect()
105            .await
106            .expect("Client failed to connect");
107
108        let response = client
109            .send(Request::new("hello".to_string()))
110            .await
111            .expect("Failed to send message");
112        assert_eq!(response.payload, "hello");
113    }
114}