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// }