1use hyper::header::{self, HeaderName, HeaderValue};
2use hyper::server::conn::AddrStream;
3use hyper::service::{make_service_fn, service_fn};
4use hyper::{Body, Request, Response, Server, StatusCode};
5use log::{debug, error, info, trace, warn};
6use regex::Regex;
7use std::cell::{RefCell, RefMut};
8use std::collections::HashMap;
9use std::fmt::{Debug, Display};
10use std::str::FromStr;
11use std::sync::Arc;
12use std::{convert::Infallible, net::SocketAddr};
13use url::form_urlencoded;
14use urlencoding::decode;
15
16pub type Ctx<'a> = RefMut<'a, Context>;
18
19pub type Json = serde_json::Value;
21
22pub use serde_json::json;
24
25pub use serde::Deserialize;
27
28pub use serde::Serialize;
30
31type Handler = dyn Fn(&mut Ctx) + 'static + Send + Sync;
33
34#[derive(Debug, PartialEq, Eq)]
36pub enum Method {
37 TRACE,
38 HEAD,
39 GET,
40 POST,
41 PUT,
42 PATCH,
43 DELETE,
44 OPTIONS,
45 ANY,
46}
47
48impl From<Method> for String {
49 fn from(v: Method) -> Self {
50 format!("{:?}", v)
51 }
52}
53
54impl From<&str> for Method {
55 fn from(s: &str) -> Self {
56 match s.to_uppercase().as_str() {
57 "TRACE" => Self::TRACE,
58 "HEAD" => Self::HEAD,
59 "GET" => Self::GET,
60 "POST" => Self::POST,
61 "PUT" => Self::PUT,
62 "PATCH" => Self::PATCH,
63 "DELETE" => Self::DELETE,
64 "OPTIONS" => Self::OPTIONS,
65 "ANY" => Self::ANY,
66 v => panic!("不存在这个类型:{}", v),
67 }
68 }
69}
70
71#[derive(Default)]
73pub struct Context {
74 headers: HashMap<String, String>,
75 params: HashMap<String, String>,
76 queries: HashMap<String, String>,
77
78 forms: HashMap<String, String>,
80
81 datas: HashMap<String, String>,
83
84 response: Response<Body>,
85
86 is_finished: bool,
90
91 is_skip_before_filters: bool,
93
94 is_skip_after_filters: bool,
96
97 ip: String,
99}
100
101impl Context {
102 pub fn param<T>(&self, name: &str) -> Option<T>
104 where
105 T: FromStr,
106 <T as FromStr>::Err: Debug,
107 {
108 self.params
109 .get(name.into())
110 .map(|v| v.as_str().parse().unwrap())
111 }
112
113 pub fn query<T>(&self, name: &str) -> Option<T>
115 where
116 T: FromStr,
117 <T as FromStr>::Err: Debug,
118 {
119 self.queries
120 .get(name.into())
121 .map(|v| v.as_str().parse().unwrap())
122 }
123
124 pub fn header(&self, name: &str) -> Option<String> {
126 self.headers
127 .get(name.to_lowercase().as_str())
128 .map(|v| v.as_str().parse().unwrap())
129 }
130
131 pub fn form<T>(&self, name: &str) -> Option<T>
133 where
134 T: FromStr,
135 <T as FromStr>::Err: Debug,
136 {
137 self.forms
138 .get(name.into())
139 .map(|v| v.as_str().parse().unwrap())
140 }
141
142 pub fn data<T>(&self, name: &str) -> Option<T>
145 where
146 T: FromStr,
147 <T as FromStr>::Err: Debug,
148 {
149 self.datas
150 .get(name.into())
151 .map(|v| v.as_str().parse().unwrap())
152 }
153
154 pub fn set_data<T>(&mut self, name: &str, data: T)
156 where
157 T: FromStr + Display,
158 <T as FromStr>::Err: Debug,
159 {
160 if self.datas.contains_key(name) {
161 self.datas.remove(name);
162 }
163 self.datas.insert(name.to_string(), data.to_string());
164 }
165
166 pub fn ip(&self) -> String {
168 self.ip.clone()
169 }
170}
171
172impl Context {
173 pub fn skip_before_filters(&mut self) {
175 self.is_skip_before_filters = true;
176 }
177
178 pub fn is_skip_before_filters(&self) -> bool {
180 self.is_skip_before_filters
181 }
182
183 pub fn skip_after_filters(&mut self) {
185 self.is_skip_after_filters = true;
186 }
187
188 pub fn is_skip_after_filters(&self) -> bool {
190 self.is_skip_after_filters
191 }
192
193 pub fn is_finished(&self) -> bool {
195 self.is_finished
196 }
197}
198
199impl Context {
200 pub fn set_header(&mut self, name: &str, value: &str) {
202 let headers = self.response.headers_mut();
203 headers.insert(
204 HeaderName::from_str(name).unwrap(),
205 HeaderValue::from_str(value).unwrap(),
206 );
207 }
208
209 pub fn string(&mut self, data: &str) {
211 self.string_raw(data, "text/html; charset=utf-8");
212 }
213
214 pub fn text(&mut self, data: &str) {
216 self.string_raw(data, "text/plain; charset=utf-8");
217 }
218
219 #[inline]
222 fn string_raw(&mut self, data: &str, content_type: &str) {
223 self.is_finished = true;
225 self.set_header(header::CONTENT_TYPE.as_str(), content_type);
226 *self.response.body_mut() = Body::from(data.to_string());
227 }
228
229 pub fn json<T>(&mut self, json: T)
242 where
243 T: Serialize,
244 {
245 let data = serde_json::to_string(&json).unwrap();
246 self.string_raw(data.as_str(), "application/json; charset=utf-8");
247 }
248}
249
250#[derive(Default, Debug)]
252pub struct Router {
253 before_fileters: Vec<Route>,
255
256 routes: Vec<Route>,
258
259 after_fileters: Vec<Route>,
261
262 has_slash: bool,
264}
265
266impl Router {
267 async fn shutdown_signal() {
268 tokio::signal::ctrl_c()
269 .await
270 .expect("安装 CTRL+C 处理器失败");
271 }
272
273 pub fn static_dir(path: &str, dir: &str) {}
275
276 pub fn static_file(uri: &str, filepath: &str) {}
278
279 async fn handle(
280 router: Arc<Router>,
281 addr: SocketAddr,
282 req: Request<Body>,
283 ) -> Result<Response<Body>, Infallible> {
284 let routes = router.match_route(req.method().as_str().into(), req.uri().path());
285
286 if routes.is_none() {
288 let response = Response::builder()
289 .status(StatusCode::NOT_FOUND)
290 .header(header::CONTENT_TYPE, "text/html; charset=utf-8")
291 .body(Body::from("没匹配到路由"))
292 .unwrap();
293 return Ok(response);
294 }
295
296 trace!("匹配到的路由:{:?}", routes);
297
298 let r = routes.unwrap();
300
301 let mut context = Context::default();
305
306 context.ip = format!("{}:{}", addr.ip(), addr.port());
308
309 let mut tm = HashMap::new();
311 for (k, v) in r.params.as_ref().unwrap() {
312 tm.insert(k.to_string(), v.to_string());
313 }
314 context.params = tm;
315
316 let qs = req.uri().query();
318
319 if let Some(qs) = qs {
320 let queries = form_urlencoded::parse(qs.as_ref())
321 .into_owned()
322 .collect::<HashMap<String, String>>();
323
324 context.queries = queries;
325 }
326
327 for (k, v) in req.headers() {
329 context.headers.insert(
330 k.to_string().to_lowercase(),
331 v.to_str().unwrap_or_default().to_string(),
332 );
333 }
334
335 if let Ok(body) = hyper::body::to_bytes(req).await {
339 let form = form_urlencoded::parse(body.as_ref())
340 .into_owned()
341 .collect::<HashMap<String, String>>();
342
343 context.forms = form;
344 }
345
346 let context = RefCell::new(context);
348
349 for r in r.before {
351 let mut context1 = context.borrow_mut();
353
354 if context1.is_skip_before_filters || context1.is_finished() {
356 break;
357 }
358
359 (r.handler)(&mut context1);
361 }
362
363 if let Some(r) = r.route {
365 trace!("路由规则:{:?}", r);
367
368 let mut context1 = context.borrow_mut();
369
370 if !context1.is_finished() {
372 (r.handler)(&mut context1);
373 }
374 }
375
376 for r in r.after {
378 let mut context1 = context.borrow_mut();
379
380 if context1.is_finished() || context1.is_skip_after_filters {
382 break;
383 }
384
385 (r.handler)(&mut context1);
387 }
388
389 if context.borrow_mut().is_finished() {
392 Ok(Response::from(context.take().response))
393 } else {
394 let response = Response::builder()
395 .status(StatusCode::NOT_FOUND)
396 .header(header::CONTENT_TYPE, "text/html; charset=utf-8")
397 .body(Body::from("没匹配到处理函数"))
398 .unwrap();
399 Ok(response)
400 }
401 }
402
403 pub fn run(self, host: &str) {
414 let rt = tokio::runtime::Runtime::new().unwrap();
415 rt.block_on(async {
416 let addr = match SocketAddr::from_str(host) {
417 Ok(v) => v,
418 Err(_) => {
419 error!("解析地址失败,请确认格式为(ip:port),你的地址是:{}", host);
420 return;
421 }
422 };
423
424 let router: Arc<Router> = Arc::new(self);
426
427 debug!("路由表:{:#?}", router.clone());
428
429 let make_service = make_service_fn(move |conn: &AddrStream| {
431 let addr = conn.remote_addr();
433
434 let router = router.clone();
436 let service = service_fn(move |req| Self::handle(router.clone(), addr, req));
437 async move { Ok::<_, Infallible>(service) }
438 });
439 let server = Server::bind(&addr).serve(make_service);
440
441 let graceful = server.with_graceful_shutdown(Self::shutdown_signal());
442
443 info!("启动成功: {}", host);
444
445 if let Err(e) = graceful.await {
446 eprintln!("server error: {}", e);
447 }
448 });
449 }
450
451 pub fn run_tls(host: &str, pem: &str, key: &str) {}
453}
454
455impl Router {
456 pub fn new() -> Self {
458 Self::default()
459 }
460
461 pub fn group(&mut self, path: &str) -> RouterGroup {
463 RouterGroup::new(path, self)
464 }
465
466 pub fn has_slash(&mut self) {
468 self.has_slash = true;
469 }
470
471 fn match_route(&self, method: Method, path: &str) -> Option<MatchedRoute> {
474 let path = if !self.has_slash && path.len() > 0 && &path[path.len() - 1..] == "/" {
476 &path[..path.len() - 1]
477 } else {
478 path
479 };
480
481 let mut params: HashMap<String, String> = HashMap::new();
487
488 trace!("查找路由:{}", path);
489 let mut matched_route = None;
491 for route in &self.routes {
492 if (method == route.method || route.method == Method::ANY) && route.re.is_match(path) {
493 matched_route = Some(route);
495
496 let cps = route.re.captures(path).unwrap();
498 trace!("参数列表:{:?}", route.param_names);
499 for name in &route.param_names {
500 match decode(cps.name(name.as_str()).unwrap().as_str()) {
502 Ok(value) => {
503 params.insert(name.to_string(), value.to_string());
504 }
505 Err(e) => {
506 warn!("路由参数值urldecode解码出错:{:?}", e)
507 }
508 }
509 }
510
511 break;
512 }
513 }
514
515 let mut before_filters = vec![];
517 for route in &self.before_fileters {
518 if (method == route.method || route.method == Method::ANY) && route.re.is_match(path) {
519 before_filters.push(route);
521
522 let cps = route.re.captures(path).unwrap();
524 trace!("参数列表:{:?}", route.param_names);
525 for name in &route.param_names {
526 match decode(cps.name(name.as_str()).unwrap().as_str()) {
527 Ok(value) => {
528 params.insert(name.to_string(), value.to_string());
529 }
530 Err(e) => {
531 warn!("路由参数值urldecode解码出错:{:?}", e)
532 }
533 }
534 }
535 }
536 }
537
538 trace!("路径中的参数值:{:?}", params);
540
541 let mut after_filters = vec![];
543 for route in &self.after_fileters {
544 if (method == route.method || route.method == Method::ANY) && route.re.is_match(path) {
545 after_filters.push(route);
547 }
548 }
549
550 if matched_route.is_none() && before_filters.len() == 0 && after_filters.len() == 0 {
552 return None;
553 }
554
555 Some(MatchedRoute {
556 before: before_filters,
557 route: matched_route,
558 after: after_filters,
559 params: Some(params),
560 })
561 }
562}
563
564impl Router {
565 fn add<F>(&mut self, method: Method, path: &str, handler: F)
566 where
567 F: Fn(&mut Ctx) + 'static + Send + Sync,
568 {
569 let route = Route::new(
572 method,
573 path.to_owned(),
574 Box::new(handler),
575 None,
576 self.has_slash,
577 );
578
579 self.routes.push(route);
580 }
581
582 pub fn before<F>(&mut self, method: Method, path: &str, handler: F)
584 where
585 F: Fn(&mut Ctx) + 'static + Send + Sync,
586 {
587 let route = Route::new_filter(
588 method,
589 path.to_owned(),
590 Box::new(handler),
591 None,
592 self.has_slash,
593 );
594
595 self.before_fileters.push(route);
596 }
597
598 pub fn after<F>(&mut self, method: Method, path: &str, handler: F)
600 where
601 F: Fn(&mut Ctx) + 'static + Send + Sync,
602 {
603 let route = Route::new_filter(
604 method,
605 path.to_owned(),
606 Box::new(handler),
607 None,
608 self.has_slash,
609 );
610
611 self.after_fileters.push(route);
612 }
613
614 pub fn get<F>(&mut self, path: &str, handler: F)
616 where
617 F: Fn(&mut Ctx) + 'static + Send + Sync,
618 {
619 self.add(Method::GET, path, handler);
620 }
621
622 pub fn post<F>(&mut self, path: &str, handler: F)
623 where
624 F: Fn(&mut Ctx) + 'static + Send + Sync,
625 {
626 self.add(Method::POST, path, handler);
627 }
628
629 pub fn trace<F>(&mut self, path: &str, handler: F)
630 where
631 F: Fn(&mut Ctx) + 'static + Send + Sync,
632 {
633 self.add(Method::TRACE, path, handler);
634 }
635
636 pub fn head<F>(&mut self, path: &str, handler: F)
637 where
638 F: Fn(&mut Ctx) + 'static + Send + Sync,
639 {
640 self.add(Method::HEAD, path, handler);
641 }
642
643 pub fn put<F>(&mut self, path: &str, handler: F)
644 where
645 F: Fn(&mut Ctx) + 'static + Send + Sync,
646 {
647 self.add(Method::PUT, path, handler);
648 }
649
650 pub fn patch<F>(&mut self, path: &str, handler: F)
651 where
652 F: Fn(&mut Ctx) + 'static + Send + Sync,
653 {
654 self.add(Method::PATCH, path, handler);
655 }
656
657 pub fn delete<F>(&mut self, path: &str, handler: F)
658 where
659 F: Fn(&mut Ctx) + 'static + Send + Sync,
660 {
661 self.add(Method::DELETE, path, handler);
662 }
663
664 pub fn options<F>(&mut self, path: &str, handler: F)
665 where
666 F: Fn(&mut Ctx) + 'static + Send + Sync,
667 {
668 self.add(Method::OPTIONS, path, handler);
669 }
670
671 pub fn any<F>(&mut self, path: &str, handler: F)
672 where
673 F: Fn(&mut Ctx) + 'static + Send + Sync,
674 {
675 self.add(Method::ANY, path, handler);
676 }
677}
678
679#[derive(Debug)]
681struct MatchedRoute<'a> {
682 before: Vec<&'a Route>,
683 route: Option<&'a Route>,
684 after: Vec<&'a Route>,
685 params: Option<HashMap<String, String>>,
687}
688
689pub struct RouterGroup<'a> {
691 path: String,
692 router: &'a mut Router,
693}
694
695impl<'a> RouterGroup<'a> {
696 fn new(path: &str, router: &'a mut Router) -> Self {
697 Self {
698 path: path.to_string(),
699 router: router,
700 }
701 }
702
703 fn concat_path(path1: &str, path2: &str) -> String {
705 let l1 = path1.replace("/", "").len();
707 let l2 = path2.replace("/", "").len();
708
709 if l1 == 0 && l2 > 0 {
710 return path2.to_string();
712 } else if l2 == 0 && l1 > 0 {
713 return path1.to_string();
715 } else if l1 == 0 && l2 == 0 {
716 return "".to_string();
717 }
718
719 match (&path1[path1.len() - 1..], &path2[0..1]) {
720 ("/", "/") => path1.to_string() + &path2[1..],
722
723 (p1, p2) if p1 != "/" && p2 != "/" => path1.to_string() + "/" + path2,
725
726 _ => path1.to_string() + path2,
728 }
729 }
730
731 fn add<F>(&mut self, method: Method, path: &str, handler: F)
732 where
733 F: Fn(&mut Ctx) + 'static + Send + Sync,
734 {
735 let path = Self::concat_path(self.path.as_str(), path);
736
737 self.router.add(method, path.as_str(), Box::new(handler));
738 }
739
740 pub fn group(&mut self, path: &str) -> RouterGroup {
742 let path = Self::concat_path(self.path.as_str(), path);
743 RouterGroup::new(path.as_str(), self.router)
744 }
745
746 pub fn before<F>(&mut self, method: Method, path: &str, handler: F)
748 where
749 F: Fn(&mut Ctx) + 'static + Send + Sync,
750 {
751 let path = Self::concat_path(self.path.as_str(), path);
752
753 self.router.before(method, path.as_str(), handler);
754 }
755
756 pub fn after<F>(&mut self, method: Method, path: &str, handler: F)
758 where
759 F: Fn(&mut Ctx) + 'static + Send + Sync,
760 {
761 let path = Self::concat_path(self.path.as_str(), path);
762
763 self.router.after(method, path.as_str(), handler);
764 }
765
766 pub fn get<F>(&mut self, path: &str, handler: F)
768 where
769 F: Fn(&mut Ctx) + 'static + Send + Sync,
770 {
771 self.add(Method::GET, path, handler);
772 }
773
774 pub fn post<F>(&mut self, path: &str, handler: F)
775 where
776 F: Fn(&mut Ctx) + 'static + Send + Sync,
777 {
778 self.add(Method::POST, path, handler);
779 }
780
781 pub fn trace<F>(&mut self, path: &str, handler: F)
782 where
783 F: Fn(&mut Ctx) + 'static + Send + Sync,
784 {
785 self.add(Method::TRACE, path, handler);
786 }
787
788 pub fn head<F>(&mut self, path: &str, handler: F)
789 where
790 F: Fn(&mut Ctx) + 'static + Send + Sync,
791 {
792 self.add(Method::HEAD, path, handler);
793 }
794
795 pub fn put<F>(&mut self, path: &str, handler: F)
796 where
797 F: Fn(&mut Ctx) + 'static + Send + Sync,
798 {
799 self.add(Method::PUT, path, handler);
800 }
801
802 pub fn patch<F>(&mut self, path: &str, handler: F)
803 where
804 F: Fn(&mut Ctx) + 'static + Send + Sync,
805 {
806 self.add(Method::PATCH, path, handler);
807 }
808
809 pub fn delete<F>(&mut self, path: &str, handler: F)
810 where
811 F: Fn(&mut Ctx) + 'static + Send + Sync,
812 {
813 self.add(Method::DELETE, path, handler);
814 }
815
816 pub fn options<F>(&mut self, path: &str, handler: F)
817 where
818 F: Fn(&mut Ctx) + 'static + Send + Sync,
819 {
820 self.add(Method::OPTIONS, path, handler);
821 }
822
823 pub fn any<F>(&mut self, path: &str, handler: F)
824 where
825 F: Fn(&mut Ctx) + 'static + Send + Sync,
826 {
827 self.add(Method::ANY, path, handler);
828 }
829}
830
831struct Route {
833 method: Method,
835
836 name: Option<String>,
838
839 path: String,
841
842 re: Regex,
844
845 handler: Box<Handler>,
847
848 has_slash: bool,
850
851 param_names: Vec<String>,
853}
854
855impl Debug for Route {
856 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
857 f.debug_struct("Route")
858 .field("method", &self.method)
859 .field("name", &self.name)
860 .field("path", &self.path)
861 .field("re", &self.re)
862 .field("has_slash", &self.has_slash)
863 .field("param_names", &self.param_names)
864 .finish()
865 }
866}
867
868impl Route {
869 fn new(
871 method: Method,
872 path: String,
873 handler: Box<Handler>,
874 name: Option<String>,
875 has_slash: bool,
876 ) -> Self {
877 Self::build(method, path, handler, name, has_slash, false)
878 }
879
880 fn new_filter(
882 method: Method,
883 path: String,
884 handler: Box<Handler>,
885 name: Option<String>,
886 has_slash: bool,
887 ) -> Self {
888 Self::build(method, path, handler, name, has_slash, true)
889 }
890 fn build(
891 method: Method,
892 path: String,
893 handler: Box<Handler>,
894 name: Option<String>,
895 has_slash: bool,
896
897 is_filter: bool,
899 ) -> Self {
900 let path = if !has_slash && !path.is_empty() && &path[path.len() - 1..] == "/" {
902 path[..path.len() - 1].to_string()
903 } else {
904 path
905 };
906
907 let path = Self::path_param_type_to_regex(path.as_str());
909
910 let path_and_names = Self::path2regex(path.as_str());
912
913 trace!("路由参数列表:{:?}", path_and_names.1);
914
915 let mut re_str = format!("^{}", path_and_names.0);
916
917 if !is_filter {
919 re_str += "$";
920 }
921
922 let re = Regex::new(re_str.as_str()).unwrap();
923 Self {
924 method,
925 path: path.clone(),
926 name,
927 re,
928 handler,
929 has_slash,
930 param_names: path_and_names.1,
931 }
932 }
933
934 #[inline]
936 fn type_to_regex(type_name: &str) -> String {
937 match type_name {
939 "i8" => r"[\-]{0,1}\d{1,3}",
940 "i16" => r"[\-]{0,1}\d{1,5}",
941 "i32" => r"[\-]{0,1}\d{1,10}",
942 "i64" => r"[\-]{0,1}\d{1,19}",
943 "i128" => r"[\-]{0,1}\d{1,39}",
944 "u8" => r"\d{1,3}",
945 "u16" => r"\d{1,5}",
946 "u32" => r"\d{1,10}",
947 "u64" => r"\d{1,20}",
948 "u128" => r"\d{1,39}",
949 "bool" => r"true|false",
950 v => {
951 panic!("路由不支持该参数类型:{}", v);
952 }
953 }
954 .to_string()
955 }
956
957 #[inline]
967 fn path_param_type_to_regex(path: &str) -> String {
968 let mut p = String::new();
969
970 let re = Regex::new(r#"^:(?P<name>[a-zA-a_]{1}[a-zA-Z_0-9]*?):(?P<type>i32|u32|i8|u8|i64|u64|i128|u128|bool)$"#).unwrap();
971
972 for node in path.split("/") {
973 if node.is_empty() {
974 continue;
975 }
976
977 if re.is_match(node) {
978 let cms = re.captures(node).unwrap();
979 let name = cms.name("name").unwrap().as_str();
980 let tp = cms.name("type").unwrap().as_str();
981
982 let type_reg = Self::type_to_regex(tp);
983 p += format!("/:{}:({})", name, type_reg).as_str();
984 } else if &node[0..1] == ":" && &node[node.len() - 1..] != ")" {
985 p = p + "/" + node + r#":([\w\-%_\.~:;'"@=+,]+)"#;
988 } else {
989 p = p + "/" + node;
991 }
992 }
993 if path.len() > 0 && &path[path.len() - 1..] == "/" {
995 p += "/";
996 }
997
998 p
999 }
1000
1001 #[inline]
1007 fn path2regex(path: &str) -> (String, Vec<String>) {
1008 let mut p = String::new();
1009
1010 let re = Regex::new(r#"^:(?P<name>[a-zA-a_]{1}[a-zA-Z_0-9]*?):\((?P<reg>.*)\)$"#).unwrap();
1011
1012 let mut names = vec![];
1013
1014 for node in path.split("/") {
1015 if node.is_empty() {
1016 continue;
1017 }
1018
1019 if re.is_match(node) {
1020 let cms = re.captures(node).unwrap();
1021 let name = cms.name("name").unwrap().as_str();
1022 names.push(name.to_string());
1023
1024 p += re
1025 .replace(node, "/(?P<${name}>${reg})")
1026 .to_string()
1027 .as_str();
1028 } else {
1029 p += "/";
1030 p += node;
1031 }
1032 }
1033 if path.len() > 0 && &path[path.len() - 1..] == "/" {
1035 p += "/";
1036 }
1037
1038 (p, names)
1039 }
1040}
1041
1042#[cfg(test)]
1043mod tests {
1044
1045 use std::cell::RefCell;
1046 use std::cell::RefMut;
1047 use std::str::FromStr;
1048
1049 use regex::Regex;
1050
1051 use crate::router::Route;
1052
1053 use super::Method;
1054 use super::Router;
1055 use super::RouterGroup;
1056
1057 #[test]
1058 fn test_concat() {
1059 assert_eq!("a/b".to_string(), RouterGroup::concat_path("a/", "/b"));
1060 assert_eq!("a/b".to_string(), RouterGroup::concat_path("a", "/b"));
1061 assert_eq!("a/b".to_string(), RouterGroup::concat_path("a/", "b"));
1062 assert_eq!("a/b".to_string(), RouterGroup::concat_path("a", "b"));
1063 assert_eq!("a".to_string(), RouterGroup::concat_path("a", ""));
1064 assert_eq!("".to_string(), RouterGroup::concat_path("", ""));
1065 assert_eq!("b".to_string(), RouterGroup::concat_path("", "b"));
1066 }
1067
1068 #[test]
1069 fn test_router() {
1070 }
1103
1104 #[test]
1105 fn test_router1() {
1106 let mut r = Router::default();
1107
1108 let mut g = r.group("/a1/");
1109 {
1110 let s = "aa".to_string();
1111 g.add(Method::GET, "/admin/login", move |c| {
1112 let t = &s;
1113 });
1114 g.add(Method::DELETE, "/admin/login1", |c| {});
1115
1116 let mut g1 = g.group("/test1/");
1117 {
1118 g1.add(Method::OPTIONS, "/admin/login", |c| {});
1119 g1.add(Method::ANY, "/admin/login1", |c| {});
1120 }
1121 }
1122
1123 for v in r.routes {
1124 println!("{:?}", v);
1125 }
1126 }
1127 #[test]
1128 fn test_regex() {
1129 let re = Regex::new(r"^/user/(?P<name>\w+)/(?P<id>\d{1,10})$").unwrap();
1130
1131 let v = re.captures("/user/zhangsan/123").unwrap();
1132 let r = v.name("name").unwrap();
1133 println!("{:?}", r.as_str());
1134 let r = v.name("id").unwrap();
1135 println!("{:?}", r.as_str());
1136 }
1137
1138 #[test]
1139 fn test_path2regex() {
1140 let s = r#"/admin/:name:(.*+?)/info/:id:(\d+?)/name/"#;
1146 let p = Route::path2regex(s);
1147
1148 assert_eq!(
1149 r"/admin/(?P<name>.*+?)/info/(?P<id>\d+?)/name/",
1150 p.0.as_str()
1151 );
1152 }
1153
1154 #[test]
1155 fn test_path_param_to_regex() {
1156 let path = "/user/:id:(.*)/:page:u32";
1157 let p = Route::path_param_type_to_regex(path);
1158 assert_eq!(r"/user/:id:(.*)/:page:(\d{1,10})", p.as_str());
1159 }
1160
1161 #[test]
1162 fn test_router_match() {
1163 }
1180
1181 #[test]
1182 fn test_filters() {}
1183
1184 #[test]
1185 fn test_fnonce() {
1186 struct Context {
1187 data: String,
1188 }
1189
1190 type Ctx<'a> = RefMut<'a, Context>;
1191 type Hander = dyn Fn(Ctx) + 'static;
1192
1193 struct Route {
1194 handler: Box<Hander>,
1195 }
1196
1197 fn get<F>(f: F)
1198 where
1199 F: Fn(Ctx) + 'static,
1200 {
1201 let r = &Route {
1202 handler: Box::new(f),
1203 };
1204
1205 let c = RefCell::new(Context {
1206 data: "".to_string(),
1207 });
1208 let v = c.borrow_mut();
1209 (r.handler)(v);
1210 let v = c.borrow_mut();
1211 (r.handler)(v);
1212 }
1213
1214 let s = String::new();
1215 get(move |mut c| {
1217 let v = &s;
1218 c.data = "xxx".to_string();
1219 });
1220 }
1221}