sincere/app/mod.rs
1//! App container.
2use hyper::{self, Server, Request, Response, Body, Method};
3use hyper::service::service_fn;
4use futures::future::Future;
5use futures_cpupool::CpuPool;
6
7use queen_log::color::Print;
8
9pub use self::route::Route;
10pub use self::group::Group;
11use self::middleware::Middleware;
12use self::context::Context;
13use crate::error::Result;
14
15#[macro_use]
16mod macros;
17mod route;
18mod group;
19pub mod middleware;
20pub mod context;
21
22pub type Handle = Fn(&mut Context) + Send + Sync + 'static;
23
24/// App container.
25///
26/// ```no_run
27/// use sincere::App;
28///
29/// fn main() {
30/// let mut app = App::new();
31///
32/// app.get("/", |context| {
33/// context.response.from_text("Hello world!").unwrap();
34/// });
35///
36/// app.run("0.0.0.0:10001", 4).unwrap();
37/// }
38/// ```
39///
40#[derive(Default)]
41pub struct App {
42 groups: Vec<Group>,
43 begin: Vec<Middleware>,
44 before: Vec<Middleware>,
45 after: Vec<Middleware>,
46 finish: Vec<Middleware>,
47 not_found: Option<Middleware>
48}
49
50impl App {
51 /// Create an app container.
52 ///
53 /// # Examples
54 ///
55 /// ```
56 /// use sincere::App;
57 ///
58 /// let app = App::new();
59 /// ```
60 ///
61 pub fn new() -> App {
62 App {
63 groups: vec![Group::new("")],
64 begin: Vec::new(),
65 before: Vec::new(),
66 after: Vec::new(),
67 finish: Vec::new(),
68 not_found: None
69 }
70 }
71
72 /// Add route handle to app.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// use sincere::App;
78 /// use sincere::http::Method;
79 ///
80 /// let mut app = App::new();
81 ///
82 /// app.add(Method::GET, "/", |context| {
83 /// context.response.from_text("Get method!").unwrap();
84 /// });
85 /// ```
86 pub fn add<H>(&mut self, method: Method, pattern: &str, handle: H) -> &mut Route
87 where H: Fn(&mut Context) + Send + Sync + 'static
88 {
89 self.groups.get_mut(0).unwrap().add(method, pattern, handle)
90 }
91
92 route!(
93 /// Add route handle to app with GET method.
94 ///
95 /// # Examples
96 ///
97 /// ```
98 /// use sincere::App;
99 /// use sincere::http::Method;
100 ///
101 /// let mut app = App::new();
102 ///
103 /// app.get("/", |context| {
104 /// context.response.from_text("Get method!").unwrap();
105 /// });
106 /// ```
107 get
108 );
109
110 route!(
111 /// Add route handle to app with PUT method.
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use sincere::App;
117 /// use sincere::http::Method;
118 ///
119 /// let mut app = App::new();
120 ///
121 /// app.put("/", |context| {
122 /// context.response.from_text("Put method!").unwrap();
123 /// });
124 /// ```
125 put
126 );
127
128 route!(
129 /// Add route handle to app with POST method.
130 ///
131 /// # Examples
132 ///
133 /// ```
134 /// use sincere::App;
135 /// use sincere::http::Method;
136 ///
137 /// let mut app = App::new();
138 ///
139 /// app.post("/", |context| {
140 /// context.response.from_text("Post method!").unwrap();
141 /// });
142 /// ```
143 post
144 );
145
146 route!(
147 /// Add route handle to app with HEAD method.
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// use sincere::App;
153 /// use sincere::http::Method;
154 ///
155 /// let mut app = App::new();
156 ///
157 /// app.head("/", |context| {
158 /// // no body?
159 /// // context.response.from_text("Head method!").unwrap();
160 /// });
161 /// ```
162 head
163 );
164
165 route!(
166 /// Add route handle to app with PATCH method.
167 ///
168 /// # Examples
169 ///
170 /// ```
171 /// use sincere::App;
172 /// use sincere::http::Method;
173 ///
174 /// let mut app = App::new();
175 ///
176 /// app.patch("/", |context| {
177 /// context.response.from_text("Patch method!").unwrap();
178 /// });
179 /// ```
180 patch
181 );
182
183 route!(
184 /// Add route handle to app with TRACE method.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// use sincere::App;
190 /// use sincere::http::Method;
191 ///
192 /// let mut app = App::new();
193 ///
194 /// app.trace("/", |context| {
195 /// context.response.from_text("Trace method!").unwrap();
196 /// });
197 /// ```
198 trace
199 );
200
201 route!(
202 /// Add route handle to app with DELETE method.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// use sincere::App;
208 /// use sincere::http::Method;
209 ///
210 /// let mut app = App::new();
211 ///
212 /// app.delete("/", |context| {
213 /// context.response.from_text("Delete method!").unwrap();
214 /// });
215 /// ```
216 delete
217 );
218
219 route!(
220 /// Add route handle to app with OPTIONS method.
221 ///
222 /// # Examples
223 ///
224 /// ```
225 /// use sincere::App;
226 /// use sincere::http::Method;
227 ///
228 /// let mut app = App::new();
229 ///
230 /// app.options("/", |context| {
231 /// context.response.from_text("Options method!").unwrap();
232 /// });
233 /// ```
234 options
235 );
236
237 route!(
238 /// Add route handle to app with CONNECT method.
239 ///
240 /// # Examples
241 ///
242 /// ```
243 /// use sincere::App;
244 /// use sincere::http::Method;
245 ///
246 /// let mut app = App::new();
247 ///
248 /// app.connect("/", |context| {
249 /// context.response.from_text("Connect method!").unwrap();
250 /// });
251 /// ```
252 connect
253 );
254
255 /// Mount router group to app.
256 ///
257 /// # Examples
258 ///
259 /// ```
260 /// use sincere::App;
261 ///
262 /// let mut app = App::new();
263 ///
264 /// app.mount("/app", |group| {
265 ///
266 /// group.get("/", |context| {
267 /// context.response.from_text("Get method!").unwrap();
268 /// });
269 ///
270 /// group.post("/", |context| {
271 /// context.response.from_text("Post method!").unwrap();
272 /// });
273 ///
274 /// });
275 /// ```
276 pub fn mount<F>(&mut self, prefix: &str, func: F) -> &mut App
277 where F: Fn(&mut Group)
278 {
279 let mut group = Group::new(prefix);
280
281 func(&mut group);
282
283 self.groups.push(group);
284 self
285 }
286
287 /// Mount router group to app.
288 ///
289 /// # Examples
290 ///
291 /// ```
292 /// use sincere::App;
293 /// use sincere::app::Group;
294 ///
295 /// let mut group = Group::new("/app");
296 ///
297 /// group.get("/", |context| {
298 /// context.response.from_text("Get method!").unwrap();
299 /// });
300 ///
301 /// group.post("/", |context| {
302 /// context.response.from_text("Post method!").unwrap();
303 /// });
304 ///
305 /// let mut app = App::new();
306 ///
307 /// app.mount_group(group);
308 ///
309 pub fn mount_group(&mut self, group: Group) -> &mut App {
310 self.groups.push(group);
311 self
312 }
313
314 middleware!(
315 /// Add `begin handle` to app.
316 ///
317 /// # Examples
318 ///
319 /// ```
320 /// use sincere::App;
321 ///
322 /// let mut app = App::new();
323 ///
324 /// app.begin(|context| {
325 /// context.response.from_text("begin!").unwrap();
326 /// });
327 /// ```
328 begin
329 );
330
331 middleware!(
332 /// Add `before handle` to app.
333 ///
334 /// # Examples
335 ///
336 /// ```
337 /// use sincere::App;
338 ///
339 /// let mut app = App::new();
340 ///
341 /// app.before(|context| {
342 /// context.response.from_text("before!").unwrap();
343 /// });
344 /// ```
345 before
346 );
347
348 middleware!(
349 /// Add `after handle` to app.
350 ///
351 /// # Examples
352 ///
353 /// ```
354 /// use sincere::App;
355 ///
356 /// let mut app = App::new();
357 ///
358 /// app.after(|context| {
359 /// context.response.from_text("after!").unwrap();
360 /// });
361 /// ```
362 after
363 );
364
365 middleware!(
366 /// Add `finish handle` to app.
367 ///
368 /// # Examples
369 ///
370 /// ```
371 /// use sincere::App;
372 ///
373 /// let mut app = App::new();
374 ///
375 /// app.finish(|context| {
376 /// context.response.from_text("finish!").unwrap();
377 /// });
378 /// ```
379 finish
380 );
381
382 /// Use middleware
383 ///
384 /// # Example
385 ///
386 /// ```
387 /// use sincere::App;
388 ///
389 /// let mut app = App::new();
390 ///
391 /// app.middleware(|app| {
392 ///
393 /// app.begin(|context| {
394 /// context.response.from_text("Hello world!").unwrap();
395 /// });
396 ///
397 /// app.finish(|context| {
398 /// context.response.from_text("Hello world!").unwrap();
399 /// });
400 ///
401 /// });
402 /// ```
403 pub fn middleware<F>(&mut self, func: F) -> &mut App
404 where F: Fn(&mut App)
405 {
406 func(self);
407 self
408 }
409
410 /// Add `not-found handle` to app.
411 ///
412 /// # Examples
413 ///
414 /// ```
415 /// use sincere::App;
416 ///
417 /// let mut app = App::new();
418 ///
419 /// app.not_found(|context| {
420 /// context.response.status_code(404).from_text("Not Found!").unwrap();
421 /// });
422 /// ```
423 pub fn not_found<H>(&mut self, handle: H)
424 where H: Fn(&mut Context) + Send + Sync + 'static
425 {
426 self.not_found = Some(Middleware {
427 inner: Box::new(handle),
428 });
429 }
430
431 /// handle
432 fn handle(&self, request: Request<Body>) -> Response<Body> {
433
434 let mut context = Context::new(self, request);
435
436 let mut route_found = false;
437
438 for begin in self.begin.iter() {
439 begin.execute_always(&mut context);
440 }
441
442 if context.next() {
443 let path = {
444 let path = context.request.uri().path();
445 if path != "/" {
446 path.trim_end_matches('/').to_owned()
447 } else {
448 path.to_owned()
449 }
450 };
451
452 'outer: for group in self.groups.iter() {
453
454 if let Some(routes) = group.routes.get(context.request.method()) {
455
456 for route in routes.iter() {
457 if let Some(ref regex) = route.regex {
458 let caps = regex.captures(&path);
459
460 if let Some(caps) = caps {
461 route_found = true;
462
463 let matches = route.path();
464
465 for (key, value) in matches.iter() {
466 context.request.params().insert(key.to_owned(), caps.get(*value).unwrap().as_str().to_owned());
467 }
468 }
469 } else {
470 let pattern = {
471 let pattern = route.pattern();
472 if pattern != "/" {
473 pattern.trim_end_matches('/').to_owned()
474 } else {
475 pattern.to_owned()
476 }
477 };
478
479 if pattern == path {
480 route_found = true;
481 }
482 }
483
484 if route_found {
485
486 for before in self.before.iter() {
487 before.execute(&mut context);
488 }
489
490 for before in group.before.iter() {
491 before.execute(&mut context);
492 }
493
494 route.execute(&mut context);
495
496 for after in group.after.iter() {
497 after.execute(&mut context);
498 }
499
500 for after in self.after.iter() {
501 after.execute(&mut context);
502 }
503
504 break 'outer;
505 }
506 }
507 }
508 }
509
510 if !route_found {
511 if let Some(ref not_found) = self.not_found {
512 not_found.execute(&mut context);
513 } else {
514 context.response.status_code(404).from_text("Not Found").unwrap();
515 }
516 }
517 }
518
519 for finish in self.finish.iter() {
520 finish.execute_always(&mut context);
521 }
522
523 context.finish()
524 }
525
526 /// Run app.
527 ///
528 /// ```no_run
529 /// use sincere::App;
530 ///
531 /// fn main() {
532 /// let mut app = App::new();
533 ///
534 /// app.get("/", |context| {
535 /// context.response.from_text("Hello world!").unwrap();
536 /// });
537 ///
538 /// app.run("0.0.0.0:10001", 4).unwrap();
539 /// }
540 /// ```
541 ///
542 pub fn run(&self, addr: &str, thread_size: usize) -> Result<()> {
543 type BoxFut = Box<Future<Item = Response<Body>, Error = hyper::Error> + Send>;
544
545 let app = unsafe {
546 let a: *const App = &*self;
547 &*a
548 };
549
550 let sincere_logo = Print::green(
551 r"
552 __.._.. . __ .___.__ .___
553 (__ | |\ |/ `[__ [__)[__
554 .__)_|_| \|\__.[___| \[___
555 "
556 );
557
558 println!("{}", sincere_logo);
559 println!(
560 " {}{} {} {} {}",
561 Print::green("Server running at http://"),
562 Print::green(addr),
563 Print::green("on"),
564 Print::green(thread_size),
565 Print::green("threads.")
566 );
567
568 let addr = addr.parse().expect("Address is not valid");
569 let thread_pool = CpuPool::new(thread_size);
570
571 let new_svc = move || {
572
573 let pool = thread_pool.clone();
574
575 service_fn(move |req| -> BoxFut {
576 let rep = pool.spawn_fn(move || {
577 let response = app.handle(req);
578 Ok(response)
579 });
580
581 Box::new(rep)
582 })
583 };
584
585 let server = Server::bind(&addr).serve(new_svc).map_err(|e| eprintln!("server error: {}", e));
586 hyper::rt::run(server);
587
588 Ok(())
589 }
590}
591
592// pub fn leak<T>(v: T) -> &'static T {
593// unsafe {
594// let b = Box::new(v);
595// let p: *const T = &*b;
596// std::mem::forget(b); // leak our reference, so that `b` is never freed
597// &*p
598// }
599// }