1
1
use arc_cell:: ArcCell ;
2
- use futures:: { self , Future , Stream } ;
2
+ use futures:: { self , BoxFuture , Future , Stream } ;
3
3
use futures_cpupool:: CpuPool ;
4
4
use hyper:: { self , Get , Post , StatusCode } ;
5
5
use hyper:: header:: { ContentLength , ContentType } ;
6
6
use hyper:: server:: { Http , Request , Response , Service } ;
7
+ use route_recognizer:: { Match , Params , Router } ;
7
8
8
9
use serde:: Serialize ;
9
10
use serde:: de:: DeserializeOwned ;
10
11
use serde_json;
11
12
use std:: env;
12
- use std:: fs:: File ;
13
- use std:: io:: Read ;
14
13
use std:: net:: SocketAddr ;
15
- use std:: path:: Path ;
16
14
use std:: str;
17
15
use std:: sync:: Arc ;
18
16
19
17
mod api;
20
18
21
19
pub struct Data ;
22
20
21
+ type Handler = fn ( & Server , Request , Params ) -> BoxFuture < Response , hyper:: Error > ;
23
22
struct Server {
23
+ router : Router < Handler > ,
24
24
data : ArcCell < Data > ,
25
25
pool : CpuPool ,
26
26
}
27
27
28
28
impl Server {
29
- fn handle_get < F , S > ( & self , req : & Request , handler : F ) -> <Server as Service >:: Future
29
+ fn handle_get < F , S > ( & self ,
30
+ req : Request ,
31
+ _params : Params ,
32
+ handler : F )
33
+ -> <Server as Service >:: Future
30
34
where F : FnOnce ( & Data ) -> S ,
31
35
S : Serialize
32
36
{
33
- assert_eq ! ( * req. method( ) , Get ) ;
37
+ if * req. method ( ) != Get {
38
+ return self . error ( StatusCode :: BadRequest ) ;
39
+ } ;
34
40
let data = self . data . get ( ) ;
35
41
let result = handler ( & data) ;
36
42
let response = Response :: new ( )
@@ -39,12 +45,31 @@ impl Server {
39
45
futures:: future:: ok ( response) . boxed ( )
40
46
}
41
47
42
- fn handle_post < F , D , S > ( & self , req : Request , handler : F ) -> <Server as Service >:: Future
48
+ fn handle_static ( & self ,
49
+ req : Request ,
50
+ _params : Params ,
51
+ content_type : ContentType ,
52
+ body : & ' static str )
53
+ -> <Server as Service >:: Future {
54
+ if * req. method ( ) != Get {
55
+ return self . error ( StatusCode :: BadRequest ) ;
56
+ } ;
57
+ let response = Response :: new ( ) . with_header ( content_type) . with_body ( body) ;
58
+ futures:: future:: ok ( response) . boxed ( )
59
+ }
60
+
61
+ fn handle_post < F , D , S > ( & self ,
62
+ req : Request ,
63
+ _params : Params ,
64
+ handler : F )
65
+ -> <Server as Service >:: Future
43
66
where F : FnOnce ( D , & Data ) -> S + Send + ' static ,
44
67
D : DeserializeOwned ,
45
68
S : Serialize
46
69
{
47
- assert_eq ! ( * req. method( ) , Post ) ;
70
+ if * req. method ( ) != Post {
71
+ return self . error ( StatusCode :: BadRequest ) ;
72
+ } ;
48
73
let length = req. headers ( )
49
74
. get :: < ContentLength > ( )
50
75
. expect ( "content-length to exist" )
@@ -82,59 +107,62 @@ impl Server {
82
107
} )
83
108
. boxed ( )
84
109
}
110
+
111
+ fn error ( & self , status : StatusCode ) -> <Server as Service >:: Future {
112
+ futures:: future:: ok ( Response :: new ( )
113
+ . with_header ( ContentType :: html ( ) )
114
+ . with_status ( status) )
115
+ . boxed ( )
116
+ }
85
117
}
86
118
87
119
impl Service for Server {
88
120
type Request = Request ;
89
121
type Response = Response ;
90
122
type Error = hyper:: Error ;
91
- type Future = Box < Future < Item = Self :: Response , Error = Self :: Error > > ;
123
+ type Future = BoxFuture < Self :: Response , Self :: Error > ;
92
124
93
125
fn call ( & self , req : Request ) -> Self :: Future {
94
- let fs_path = format ! ( "static{}" ,
95
- if req. path( ) == "" || req. path( ) == "/" {
96
- "/index.html"
97
- } else {
98
- req. path( )
99
- } ) ;
100
-
101
- info ! ( "handling: req.path()={:?}, fs_path={:?}" ,
102
- req. path( ) ,
103
- fs_path) ;
104
-
105
- if fs_path. contains ( "./" ) | fs_path. contains ( "../" ) {
106
- return futures:: future:: ok ( Response :: new ( )
107
- . with_header ( ContentType :: html ( ) )
108
- . with_status ( StatusCode :: NotFound ) )
109
- . boxed ( ) ;
110
- }
126
+ info ! ( "handling: req.path()={:?}" , req. path( ) ) ;
111
127
112
- if Path :: new ( & fs_path) . is_file ( ) {
113
- return self . pool
114
- . spawn_fn ( move || {
115
- let mut f = File :: open ( & fs_path) . unwrap ( ) ;
116
- let mut source = Vec :: new ( ) ;
117
- f. read_to_end ( & mut source) . unwrap ( ) ;
118
- futures:: future:: ok ( Response :: new ( ) . with_body ( source) )
119
- } )
120
- . boxed ( ) ;
128
+ match self . router . recognize ( req. path ( ) ) {
129
+ Ok ( Match { handler, params } ) => handler ( self , req, params) ,
130
+ Err ( _) => self . error ( StatusCode :: NotFound ) ,
121
131
}
122
132
123
- match req. path ( ) {
124
- "/api/get" => self . handle_get ( & req, api:: get:: handler) ,
125
- "/api/post" => self . handle_post ( req, api:: post:: handler) ,
126
- _ => {
127
- futures:: future:: ok ( Response :: new ( )
128
- . with_header ( ContentType :: html ( ) )
129
- . with_status ( StatusCode :: NotFound ) )
130
- . boxed ( )
131
- }
132
- }
133
+
133
134
}
134
135
}
135
136
137
+ macro_rules! route {
138
+ ( $router: ident, $path: expr, $method: ident, $( $handler: tt) * ) => (
139
+ $router. add( $path,
140
+ |server: & Server , req, params| server. $method( req, params, $( $handler) * ) ) ;
141
+ )
142
+ }
143
+
136
144
pub fn start ( data : Data ) {
145
+ let mut router = Router :: < Handler > :: new ( ) ;
146
+ route ! ( router, "/api/get" , handle_get, api:: get:: handler) ;
147
+ route ! ( router, "/api/post" , handle_post, api:: post:: handler) ;
148
+ route ! ( router,
149
+ "/static/report.html" ,
150
+ handle_static,
151
+ ContentType :: html( ) ,
152
+ include_str!( "../../static/report.html" ) ) ;
153
+ route ! ( router,
154
+ "/static/report.js" ,
155
+ handle_static,
156
+ ContentType ( mime!( Application / Javascript ) ) ,
157
+ include_str!( "../../static/report.js" ) ) ;
158
+ route ! ( router,
159
+ "/static/report.css" ,
160
+ handle_static,
161
+ ContentType ( mime!( Text / Css ) ) ,
162
+ include_str!( "../../static/report.css" ) ) ;
163
+
137
164
let server = Arc :: new ( Server {
165
+ router,
138
166
data : ArcCell :: new ( Arc :: new ( data) ) ,
139
167
pool : CpuPool :: new_num_cpus ( ) ,
140
168
} ) ;
0 commit comments