chitey_server/
web_server.rs

1use async_trait::async_trait;
2use fnv::FnvHashMap;
3use tokio::sync::Mutex;
4use urlpattern::UrlPatternMatchInput;
5use core::fmt;
6use std::{
7    io,
8    net::{SocketAddr, ToSocketAddrs},
9    path::PathBuf, pin::Pin, sync::Arc, any::{Any, TypeId}, ops::Deref, fmt::Formatter,
10};
11
12use hyper::Body;
13
14use crate::{server::{util::{get_certs_and_key, process_result}, http_server::{launch_http_server, HttpServerOpt}, https_server::{launch_https_server, HttpsServerOpt}, http3_server::{launch_http3_server, Http3ServerOpt}}, process::save_pid, resource::{Resource, Responder}};
15
16
17#[derive(Default)]
18pub struct Data (FnvHashMap<TypeId, Box<dyn Any + Sync + Send>>);
19
20impl Deref for Data {
21    type Target = FnvHashMap<TypeId, Box<dyn Any + Sync + Send>>;
22
23    fn deref(&self) -> &Self::Target {
24        &self.0
25    }
26}
27
28impl Data {
29    pub fn new(data: FnvHashMap<TypeId, Box<dyn Any + Sync + Send>>) -> Self {
30        Self(data)
31    }
32
33    pub fn default() -> Self {
34        Self(FnvHashMap::default())
35    }
36
37    pub fn insert<D>(&mut self, data: D)
38    where
39        D: Any + Send + Sync,
40    {
41        self.0.insert(TypeId::of::<D>(), Box::new(data));
42    }
43}
44
45impl fmt::Debug for Data {
46    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
47        f.debug_tuple("Data").finish()
48    }
49}
50
51pub type Result<T, E = ChiteyError> = std::result::Result<T, E>;
52
53pub struct ContextImpl {
54    pub(crate) data: Data,
55}
56
57impl ContextImpl {
58    pub fn new() -> Self {
59        ContextImpl { data: Data::new(FnvHashMap::default()) }
60    }
61
62    #[must_use]
63    pub fn insert<D>(mut self, data: D) -> Self
64    where
65        D: Any + Send + Sync,
66    {
67        self.data.insert(data);
68        self
69    }
70}
71
72#[derive(Clone)]
73pub struct Context {
74    data: Arc<ContextImpl>,
75}
76
77impl Context {
78    pub fn new(data: ContextImpl) -> Self {
79        Self {
80            data: Arc::new(data),
81        }
82    }
83
84    pub fn get<D>(&self) -> &D
85    where
86        D: Any + Send + Sync,
87    {
88        self.data_opt::<D>().unwrap_or_else(|| panic!("Data `{}` does not exist.", std::any::type_name::<D>()))
89    }
90
91    pub fn data_opt<D>(&self) -> Option<&D>
92    where
93        D: Any + Send + Sync,
94    {
95        self.data.data.get(&TypeId::of::<D>()).and_then(|d| d.downcast_ref::<D>())
96    }
97}
98
99#[derive(Clone)]
100pub struct Factories {
101    pub(crate) factories: Vec<(Arc<Resource>, Arc<Mutex<Pin<Box<dyn HttpServiceFactory + 'static + Send + Sync>>>>)>,
102    pub(crate) contexts: Context,
103}
104unsafe impl Send for Factories {}
105unsafe impl Sync for Factories {}
106
107#[derive(Clone)]
108pub struct Certs {
109    pub cert: PathBuf,
110    pub key: PathBuf,
111}
112
113#[async_trait]
114pub trait HttpServiceFactory: Sync
115{
116    fn register(&self) -> Resource;
117    fn analyze_types(&self, url: UrlPatternMatchInput) -> bool;
118    async fn handler_func(&self, url: UrlPatternMatchInput, req: Request) -> Responder;
119}
120
121pub struct WebServer {
122    cert: Option<Certs>,
123    listen: Option<SocketAddr>,
124    tls_listen: Option<SocketAddr>,
125    redirect: Option<String>,
126    factories: Vec<(Resource, Pin<Box<dyn HttpServiceFactory + 'static + Send + Sync>>)>,
127    data: Data,
128}
129
130impl WebServer
131{
132    pub fn new() -> Self {
133        Self {
134            cert: None,
135            listen: None,
136            tls_listen: None,
137            redirect: None,
138            factories: Vec::new(),
139            data: Data::default(),
140        }
141    }
142
143    pub fn service<F>(mut self, factory: F) -> Self
144    where
145        F: HttpServiceFactory + 'static + Send + Sync,
146    {
147        let resource = factory.register();
148        self.factories.push((resource, Box::pin(factory)));
149        self
150    }
151
152    pub fn bind<A>(mut self, address: A) -> io::Result<Self>
153    where
154        A: ToSocketAddrs,
155    {
156        match address.to_socket_addrs() {
157            Ok(v) => {
158                for addr in v.collect::<Vec<SocketAddr>>() {
159                    self.listen = Some(addr);
160                }
161            }
162            Err(e) => return Err(e),
163        };
164
165        Ok(self)
166    }
167
168    pub fn tls_bind<A>(mut self, address: A) -> io::Result<Self>
169    where
170        A: ToSocketAddrs,
171    {
172        match address.to_socket_addrs() {
173            Ok(v) => {
174                for addr in v.collect::<Vec<SocketAddr>>() {
175                    self.tls_listen = Some(addr);
176                }
177            }
178            Err(e) => return Err(e),
179        };
180
181        Ok(self)
182    }
183
184    pub fn redirect<U: std::ops::Deref<Target=str>>(mut self, url: U) -> Self {
185        self.redirect = Some(url.to_string());
186        self
187    }
188
189    pub fn tls(mut self, cert: Certs) -> Self {
190        self.cert = Some(cert);
191        self
192    }
193
194    pub async fn run(self) -> Result<(), ChiteyError> {
195        let mut factories = Vec::new();
196        let mut factories2 = Vec::new();
197        for factory in self.factories {
198            let (res, fact) = factory;
199            let fac = Arc::new(Mutex::new(fact));
200            factories.push((Arc::new(res.clone()), fac.clone()));
201            factories2.push((Arc::new(res), fac.clone()));
202        }
203
204        let contexts = Context::new(ContextImpl { data: self.data });
205        let factories = Factories{ factories, contexts: contexts.clone() };
206        let factories2 = Factories{ factories: factories2, contexts: contexts.clone() };
207
208        if let Some(cert) = self.cert {
209            let tls_certs_key = match get_certs_and_key(cert) {
210                Ok(v) => v,
211                Err(e) => return Err(ChiteyError::KeyAnalyzeError(e.to_string())),
212            };
213            let tls_certs_key2 = tls_certs_key.clone();
214            let handle_http = async {
215                let factories = factories.clone();
216                if let Some(li) = self.listen {
217                    let http_server_opt = HttpServerOpt{ listen: li, redirect: self.redirect };
218                    let _ = tokio::spawn(async move {
219                        loop {
220                            process_result(launch_http_server(http_server_opt.clone(), save_pid, factories.clone()).await);
221                        };
222                    }).await;
223                }
224            };
225            let factories = factories.clone();
226            let handle_https = async {
227                if let Some(li) = self.tls_listen {
228                    let https_server_opt = HttpsServerOpt{listen: li};
229                    let http3_server_opt = Http3ServerOpt{listen: li};
230                    let handle_https = tokio::spawn(async move {
231                        loop {
232                            process_result(launch_https_server(tls_certs_key.clone(), https_server_opt.clone(), factories.clone()).await);
233                        }
234                    });
235                    let handle_http3 = tokio::spawn(async move {
236                        loop {
237                            process_result(launch_http3_server(tls_certs_key2.clone(), http3_server_opt.clone(), factories2.clone()).await);
238                        }
239                    });
240                    let (_, _) = tokio::join!(handle_https, handle_http3);
241                }
242            };
243
244            let (_, _) = tokio::join!(
245                handle_http,
246                handle_https,
247            );
248        };
249
250        eprintln!("You must set key always!! Right or Fake or not!!");
251
252        Ok(())
253    }
254
255    #[must_use]
256    pub fn data<D>(mut self, data: D) -> Self
257    where
258        D: Any + Send + Sync
259    {
260        self.data.insert(data);
261        self
262    }
263}
264
265pub type Request = (http::Request<Body>, bool, Context);
266
267use thiserror::Error;
268#[derive(Error, Debug)]
269pub enum ChiteyError {
270    #[error("extract value failed")]
271    UrlPatternError,
272    #[error("server failed: {0}")]
273    InternalServerError(String),
274    #[error("cannot analyze key: {0}")]
275    KeyAnalyzeError(String),
276    #[error("failed kill server: {0}")]
277    ServerKillError(String),
278}