puzz_server/actix/
mod.rs

1use std::convert::Infallible;
2use std::fmt;
3use std::net::SocketAddr;
4
5use actix_http::HttpService;
6use actix_service::IntoService;
7use puzz_core::response::IntoResponse;
8use puzz_core::service::Service;
9use puzz_core::{BoxError, Request};
10use tokio::net::TcpStream;
11
12mod compat;
13
14struct ServerOptions {
15    workers: Option<usize>,
16    addr: Vec<SocketAddr>,
17}
18
19/// HTTP服务器
20///
21/// # 例子
22///
23/// ```ignore
24/// use puzz_core::service_fn;
25/// use puzz_server::Server;
26///
27/// Server::new(|| service_fn(|_| async { Ok("hi!") }))
28///     .bind(([127, 0, 0, 1], 80))
29///     .run()
30///     .await
31///     .unwrap();
32/// ```
33pub struct Server<F> {
34    factory: F,
35    options: Result<ServerOptions, BoxError>,
36}
37
38impl<F, S> Server<F>
39where
40    F: Fn() -> S + Clone + Send + 'static,
41    S: Service<Request, Error = Infallible> + 'static,
42    S::Response: IntoResponse,
43    S::Future: 'static,
44{
45    /// 创建一个新的HTTP服务器。
46    pub fn new(factory: F) -> Self {
47        Self {
48            factory,
49            options: Ok(ServerOptions {
50                workers: None,
51                addr: vec![],
52            }),
53        }
54    }
55
56    /// 设置HTTP服务器的工作线程数。
57    ///
58    /// 服务器的工作线程数默认设置为处理器的物理内核数。
59    pub fn workers(mut self, num: usize) -> Self {
60        self.options = self.options.and_then(|mut options| {
61            options.workers = Some(num);
62            Ok(options)
63        });
64        self
65    }
66
67    /// 设置HTTP服务器的监听地址。
68    pub fn bind<A>(mut self, addr: A) -> Self
69    where
70        A: Into<SocketAddr>,
71    {
72        self.options = self.options.and_then(|mut options| {
73            options.addr.push(addr.into());
74            Ok(options)
75        });
76        self
77    }
78
79    /// 启动HTTP服务器。
80    pub async fn run(self) -> Result<(), BoxError> {
81        let options = self.options?;
82        let factory = self.factory;
83
84        let factory = move || {
85            let service = compat::into_actix_service(factory());
86            let service = move |request: actix_http::Request| service.call(request);
87
88            async move { Ok::<_, Infallible>(service.into_service()) }
89        };
90
91        let mut server = actix_server::Server::build();
92
93        if let Some(workers) = options.workers {
94            server = server.workers(workers);
95        }
96
97        server
98            .bind("puzz", &options.addr[..], move || {
99                HttpService::<TcpStream, _, _, _, _>::build()
100                    .finish(factory.clone())
101                    .tcp()
102            })?
103            .run()
104            .await
105            .map_err(From::from)
106    }
107}
108
109impl<F> fmt::Debug for Server<F> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        f.debug_struct("Server").finish()
112    }
113}