rust_xfinal/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use std::collections::HashMap;
4use std::io::{self, Read, Write};
5use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpListener};
6use std::sync::Arc;
7
8mod thread_pool;
9
10mod http_parser;
11
12use http_parser::WsRouterValue;
13pub use http_parser::{
14    ConnectionData, MiddleWare, Request, Response, Router, RouterMap, RouterValue, ServerConfig,
15    Websocket, WebsocketEvent, WsMessage, WsRouter,
16};
17
18#[cfg_attr(docsrs, doc(cfg(feature = "macros")))]
19#[cfg(feature = "macros")]
20pub use xfinal_macro::end_point;
21
22pub use http_parser::connection::http_response_table::{
23    CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT, TRACE,
24};
25
26use http_parser::connection::http_response_table::get_httpmethod_from_code;
27
28pub use tera;
29
30pub use serde_json;
31
32pub type JsonValue = serde_json::Value;
33
34pub mod cookie;
35
36pub use cookie::Period;
37
38pub use chrono;
39pub use chrono_tz;
40pub use hmac;
41pub use sha2;
42
43pub use base64;
44
45pub use sha1;
46
47use hmac::{Hmac, Mac};
48use sha2::Sha256;
49pub use uuid;
50
51pub trait SerializationMethods {
52    fn serialize(&self) -> Vec<&'static str>;
53}
54
55impl SerializationMethods for u8 {
56    fn serialize(&self) -> Vec<&'static str> {
57        let m = get_httpmethod_from_code(*self);
58        let mut r = Vec::new();
59        r.push(m);
60        r
61    }
62}
63
64impl SerializationMethods for &[u8] {
65    fn serialize(&self) -> Vec<&'static str> {
66        let mut r = Vec::new();
67        for e in *self {
68            let m = get_httpmethod_from_code(*e);
69            r.push(m);
70        }
71        r
72    }
73}
74
75impl<const I: usize> SerializationMethods for [u8; I] {
76    fn serialize(&self) -> Vec<&'static str> {
77        let mut r = Vec::new();
78        for e in *self {
79            let m = get_httpmethod_from_code(e);
80            r.push(m);
81        }
82        r
83    }
84}
85
86#[derive(Debug)]
87pub struct EndPoint {
88    pub port: u16,
89    pub ip_address: [u8; 4],
90}
91
92pub struct HttpServer {
93    end_point: EndPoint,
94    thread_number: u16,
95    router: HashMap<String, RouterValue>,
96    ws_router: HashMap<String, WsRouterValue>,
97    config_: ServerConfig,
98}
99
100pub struct RouterRegister<'a> {
101    server: &'a mut HttpServer,
102    path: &'a str,
103    methods: Vec<&'a str>,
104}
105
106impl<'a> RouterRegister<'a> {
107    pub fn reg<F>(&mut self, f: F)
108    where
109        F: Router + Send + Sync + 'static + Clone,
110    {
111        for e in &self.methods {
112            let router_path = format!("{}{}", e, self.path);
113            self.server
114                .router
115                .insert(router_path, (None, Arc::new(f.clone())));
116        }
117    }
118
119    pub fn reg_with_middlewares<F>(
120        &mut self,
121        middlewares: Vec<Arc<dyn MiddleWare + Send + Sync>>,
122        f: F,
123    ) where
124        F: Router + Send + Sync + 'static + Clone,
125    {
126        for e in &self.methods {
127            let router_path = format!("{}{}", e, self.path);
128            self.server.router.insert(
129                router_path,
130                (Some(middlewares.clone()), Arc::new(f.clone())),
131            );
132        }
133    }
134}
135
136pub struct WsRouterRegister<'a> {
137    server: &'a mut HttpServer,
138    path: &'a str,
139}
140
141impl<'a> WsRouterRegister<'a> {
142    pub fn reg<F>(&mut self, f: F)
143    where
144        F: WsRouter + Send + Sync + 'static + Clone,
145    {
146        self.server
147            .ws_router
148            .insert(self.path.to_string(), (None, Arc::new(f.clone())));
149    }
150
151    pub fn reg_with_middlewares<F>(
152        &mut self,
153        middlewares: Vec<Arc<dyn MiddleWare + Send + Sync>>,
154        f: F,
155    ) where
156        F: WsRouter + Send + Sync + 'static + Clone,
157    {
158        self.server.ws_router.insert(
159            self.path.to_string(),
160            (Some(middlewares.clone()), Arc::new(f.clone())),
161        );
162    }
163}
164
165impl HttpServer {
166    /// > create an instance of http server
167    /// >> - end: use `end_point![0.0.0.0:8080]` to construct `EndPoint`
168    /// >> - count: specify the size of thread pool
169    pub fn create(end: EndPoint, count: u16) -> Self {
170        let key = match std::fs::OpenOptions::new()
171            .read(true)
172            .write(true)
173            .create(true)
174            .open("./secret.key")
175        {
176            Ok(mut file) => {
177                let mut s = String::new();
178                match file.read_to_string(&mut s) {
179                    Ok(size) => {
180                        if size == 0 {
181                            let s = uuid::Uuid::new_v4().to_string();
182                            file.write(s.as_bytes())
183                                .expect("write new secret key error");
184                            s
185                        } else {
186                            s
187                        }
188                    }
189                    Err(e) => {
190                        panic!("initial secret key error:{}", e.to_string())
191                    }
192                }
193            }
194            Err(e) => {
195                panic!("initial secret key error:{}", e.to_string())
196            }
197        };
198        type HmacSha256 = Hmac<Sha256>;
199        let mac = match HmacSha256::new_from_slice(key.as_bytes()) {
200            Ok(r) => r,
201            Err(e) => {
202                panic!("HmacSha256::new_from_slice error:{}", e.to_string())
203            }
204        };
205        Self {
206            end_point: end,
207            thread_number: count,
208            router: HashMap::new(),
209            ws_router: HashMap::new(),
210            config_: ServerConfig {
211                upload_directory: String::from("./upload"),
212                read_timeout: 5 * 1000,
213                chunk_size: 1024 * 5,
214                write_timeout: 5 * 1000,
215                open_log: false,
216                max_body_size: 3 * 1024 * 1024,
217                max_header_size: 3 * 1024 * 1024,
218                read_buff_increase_size: 1024,
219                secret_key: Arc::new(mac),
220                ws_read_timeout: 5 * 60 * 1000,
221                ws_write_timeout: 5 * 60 * 1000,
222                ws_frame_size: 65535,
223            },
224        }
225    }
226
227    fn create_directory(&self) -> io::Result<bool> {
228        let _ = std::fs::create_dir(self.config_.upload_directory.clone())?;
229        Ok(true)
230    }
231    /// > This method specifies the value of time when waiting for the read from the client.
232    /// >> - [unit: millisecond]
233    pub fn set_read_timeout(&mut self, millis: u32) {
234        self.config_.read_timeout = millis;
235    }
236
237    /// > This method specifies the value of time when waiting for the read of the client
238    /// >> - [unit: millisecond]
239    pub fn set_write_timeout(&mut self, millis: u32) {
240        self.config_.write_timeout = millis;
241    }
242
243    /// > Specifiy each chunk size when responding to the client by using Chunked Transfer,
244    /// >> - [unit: byte]
245    pub fn set_chunksize(&mut self, size: u32) {
246        self.config_.chunk_size = size;
247    }
248
249    /// > The switch to output the error in the connection the server has caught
250    pub fn open_server_log(&mut self, open: bool) {
251        self.config_.open_log = open;
252    }
253
254    /// > Specify the maximum size of body in a connection the server can handle
255    /// >> - [unit: byte]
256    pub fn set_max_body_size(&mut self, size: usize) {
257        self.config_.max_header_size = size;
258    }
259
260    /// > Specify the maximum size of http header in a connection the server can handle
261    /// >> - [unit: byte]
262    pub fn set_max_header_size(&mut self, size: usize) {
263        self.config_.max_body_size = size;
264    }
265
266    /// > Specify the increased size of buffers used for taking the content of the stream in a connection
267    /// >> - [unit: byte]
268    pub fn set_read_buff_increase_size(&mut self, size: usize) {
269        self.config_.read_buff_increase_size = size;
270    }
271
272    /// > This method specifies the value of time when waiting for the websocket read from the client.
273    /// >> - [unit: millisecond]
274    pub fn set_ws_readtimeout(&mut self, millis: u32) {
275        self.config_.ws_read_timeout = millis;
276    }
277
278    /// > This method specifies the value of time when waiting for the websocket write to the client.
279    /// >> - [unit: millisecond]
280    pub fn set_ws_writetimeout(&mut self, millis: u32) {
281        self.config_.ws_write_timeout = millis;
282    }
283
284    /// > This method specifies the size of the websocket's fragment
285    /// >> - [unit: byte]
286    pub fn set_ws_frame_size(&mut self, size: usize) {
287        if size < 126 {
288            panic!("shall be larger than or equal to 126");
289        }
290        self.config_.ws_frame_size = size;
291    }
292
293    /// > To start a http server
294    /// >> - This is a block method, which implies all set to the instance of HttpServer
295    ///  should precede the call of this method
296    pub fn run(&mut self) {
297        let [a, b, c, d] = self.end_point.ip_address;
298        let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(a, b, c, d)), self.end_point.port);
299        let listen = TcpListener::bind(socket);
300        self.not_found_default_if_not_set();
301        match self.create_directory() {
302            Ok(_) => {}
303            Err(e) => match e.kind() {
304                io::ErrorKind::AlreadyExists => {}
305                _ => {
306                    panic!("{}", e.to_string())
307                }
308            },
309        };
310        let safe_router = Arc::new(self.router.clone());
311        let safe_ws_router = Arc::new(self.ws_router.clone());
312        let conn_data = Arc::new(ConnectionData {
313            router_map: safe_router,
314            ws_router_map: safe_ws_router,
315            server_config: self.config_.clone(),
316        });
317        match listen {
318            Ok(x) => {
319                let mut pool =
320                    thread_pool::ThreadPool::new(self.thread_number, http_parser::handle_incoming);
321                for conn in x.incoming() {
322                    match conn {
323                        Ok(stream) => {
324                            let conn_data = conn_data.clone();
325                            match pool.poll((conn_data, stream)) {
326                                Ok(_) => {}
327                                Err(e) => {
328                                    if self.config_.open_log {
329                                        let now = http_parser::get_current_date();
330                                        println!(
331                                            "[{}] >>> error in send connection: {}",
332                                            now,
333                                            e.to_string()
334                                        );
335                                    }
336                                }
337                            }
338                        }
339                        Err(e) => {
340                            if self.config_.open_log {
341                                let now = http_parser::get_current_date();
342                                println!("[{}] >>> error on incoming:{}", now, e.to_string());
343                            }
344                        }
345                    }
346                }
347                pool.join();
348            }
349            Err(e) => {
350                panic!("listen error, the reason is: {}", e.to_string());
351            }
352        }
353    }
354
355    /// > Register a router
356    /// >> - methods: Http Method
357    /// >>> allow the form: single method `GET`, or multiple methods `[GET, HEAD]`
358    /// >> - path: Http Url to which the router respond
359    /// # Usage:
360    ///
361    /// > HttpServer::route(HttpServer::GET, "/").reg(...)
362    /// >> - the call of `reg` registers the action
363    /// >>> - the argument shall satisfy the trait Router
364    /// >>> - Router is automatically implemented for type fn and FnMut that takes two parameters `&Request` and `& mut Response`
365    ///
366    /// > HttpServer::route(HttpServer::GET, "/").reg_with_middlewares(...)
367    /// >> - register a router with a set of middlwares
368    /// >>> - The first argument is a set of middlwares
369    /// >>> - A middleware satisfies trait `MiddleWare`
370    ///
371    /// > In the above cases, the path can a wildcard url, such as `/path/*`
372    /// >> - A valid wildcard path cannot be `/*`
373    ///
374    pub fn route<'a, T: SerializationMethods>(
375        &'a mut self,
376        methods: T,
377        path: &'a str,
378    ) -> RouterRegister<'_> {
379        //let method = get_httpmethod_from_code(M);
380        if path.trim() == "/*" {
381            panic!("/* => wildcard of root path is not permitted!")
382        }
383        RouterRegister {
384            server: self,
385            methods: methods.serialize(),
386            path,
387        }
388    }
389
390    /// > Register a websocket router
391    pub fn route_ws<'a>(&'a mut self, path: &'a str) -> WsRouterRegister<'a> {
392        WsRouterRegister { server: self, path }
393    }
394
395    /// > Specify the action when a request does not have a corresponding registered router
396    /// >> - The framework has a preset action, you can overwrite it by using this method
397    /// >> - The argument shall satisfy constraint: Router + Send + Sync + 'static
398    pub fn set_not_found<F>(&mut self, f: F)
399    where
400        F: Router + Send + Sync + 'static,
401    {
402        self.router
403            .insert(String::from("NEVER_FOUND_FOR_ALL"), (None, Arc::new(f)));
404    }
405
406    fn not_found_default_if_not_set(&mut self) {
407        let r = &self.router.get(&String::from("NEVER_FOUND_FOR_ALL"));
408        if let None = *r {
409            self.set_not_found(|_req: &Request, res: &mut Response| {
410                res.write_state(404);
411            });
412        }
413    }
414}
415
416/// This macro is used to conveniently construct a set of middlwares
417#[macro_export]
418macro_rules! inject_middlewares {
419	($($m:expr),*) => {
420		{
421			use std::sync::Arc;
422			type T = Arc<dyn MiddleWare + Send + Sync>;
423			let x = vec![$( Arc::new($m) as T ,)*];
424			x
425		}
426	};
427}
428
429// #[macro_export]
430// macro_rules! end_point {
431//     ($a:expr,$b:expr,$c:expr,$d:expr ; $port:expr) => {{
432//         let x = http_server::EndPoint {
433//             port: $port as u16,
434//             ip_address: [$a as u8, $b as u8, $c as u8, $d as u8],
435//         };
436//         x
437//     }};
438// }