Skip to main content

trillium_async_std/server/
unix.rs

1use crate::AsyncStdTransport;
2use async_std::{
3    net::{TcpListener, TcpStream},
4    os::unix::net::{UnixListener, UnixStream},
5    stream::StreamExt,
6    task::{block_on, spawn},
7};
8use std::{env, future::Future, io::Result, pin::Pin};
9use trillium::{log_error, Info};
10use trillium_server_common::{
11    Binding::{self, *},
12    Server, Stopper,
13};
14
15/// Tcp/Unix Trillium server adapter for Async-Std
16#[derive(Debug)]
17pub struct AsyncStdServer(Binding<TcpListener, UnixListener>);
18impl From<TcpListener> for AsyncStdServer {
19    fn from(value: TcpListener) -> Self {
20        Self(Tcp(value))
21    }
22}
23
24impl From<UnixListener> for AsyncStdServer {
25    fn from(value: UnixListener) -> Self {
26        Self(Unix(value))
27    }
28}
29impl From<std::net::TcpListener> for AsyncStdServer {
30    fn from(value: std::net::TcpListener) -> Self {
31        TcpListener::from(value).into()
32    }
33}
34impl From<std::os::unix::net::UnixListener> for AsyncStdServer {
35    fn from(value: std::os::unix::net::UnixListener) -> Self {
36        UnixListener::from(value).into()
37    }
38}
39
40#[cfg(unix)]
41impl Server for AsyncStdServer {
42    type Transport = Binding<AsyncStdTransport<TcpStream>, AsyncStdTransport<UnixStream>>;
43    const DESCRIPTION: &'static str = concat!(
44        " (",
45        env!("CARGO_PKG_NAME"),
46        " v",
47        env!("CARGO_PKG_VERSION"),
48        ")"
49    );
50
51    fn handle_signals(stop: Stopper) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
52        Box::pin(async move {
53            use signal_hook::consts::signal::*;
54            use signal_hook_async_std::Signals;
55
56            let signals = Signals::new([SIGINT, SIGTERM, SIGQUIT]).unwrap();
57            let mut signals = signals.fuse();
58            while signals.next().await.is_some() {
59                if stop.is_stopped() {
60                    eprintln!("\nSecond interrupt, shutting down harshly");
61                    std::process::exit(1);
62                } else {
63                    println!("\nShutting down gracefully.\nControl-C again to force.");
64                    stop.stop();
65                }
66            }
67        })
68    }
69
70    fn accept(&mut self) -> Pin<Box<dyn Future<Output = Result<Self::Transport>> + Send + '_>> {
71        Box::pin(async move {
72            match &self.0 {
73                Tcp(t) => t
74                    .accept()
75                    .await
76                    .map(|(t, _)| Tcp(AsyncStdTransport::from(t))),
77
78                Unix(u) => u
79                    .accept()
80                    .await
81                    .map(|(u, _)| Unix(AsyncStdTransport::from(u))),
82            }
83        })
84    }
85
86    fn listener_from_tcp(tcp: std::net::TcpListener) -> Self {
87        Self(Tcp(tcp.into()))
88    }
89
90    fn listener_from_unix(tcp: std::os::unix::net::UnixListener) -> Self {
91        Self(Unix(tcp.into()))
92    }
93
94    fn info(&self) -> Info {
95        match &self.0 {
96            Tcp(t) => t.local_addr().unwrap().into(),
97            Unix(u) => u.local_addr().unwrap().into(),
98        }
99    }
100
101    fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
102        spawn(fut);
103    }
104
105    fn block_on(fut: impl Future<Output = ()> + 'static) {
106        block_on(fut);
107    }
108
109    fn clean_up(self) -> Pin<Box<dyn Future<Output = ()> + Send + 'static>> {
110        Box::pin(async move {
111            if let Unix(u) = &self.0 {
112                if let Ok(local) = u.local_addr() {
113                    if let Some(path) = local.as_pathname() {
114                        log::info!("deleting {:?}", &path);
115                        log_error!(async_std::fs::remove_file(path).await);
116                    }
117                }
118            }
119        })
120    }
121}