1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//! Exposes the `Ferrum` type, the main entrance point of the `Ferrum` library.

use std::net::ToSocketAddrs;
use std::time::Duration;
use std::io::{Error, ErrorKind};

use hyper::Body;
use hyper::server::{Http, Server as HyperServer};

use error::HyperResult;
use service::InitialService;
use middleware::Handler;

pub type Server<H> = HyperServer<InitialService<H>, Body>;

/// The primary entrance point to `Ferrum`, a `struct` to instantiate a new server.
///
/// `Ferrum` contains the `Handler` which takes a `Request` and produces a `Response`.
pub struct Ferrum<H>
    where H: Handler
{
    /// Ferrum contains a `Handler`, which it uses to create responses for client requests.
    pub handler: H,

    /// Controls the timeout for keep alive connections.
    ///
    /// The default is `true`.
    pub keep_alive: bool,

    /// Server timeout.
    pub timeout: Option<Duration>,

    /// The number of request handling threads.
    ///
    /// Defaults to `num_cpus`.
    pub num_threads: usize,
}

impl<H> Ferrum<H>
    where H: Handler
{
    /// Instantiate a new instance of `Ferrum`.
    ///
    /// This will create a new `Ferrum`, the base unit of the server, using the
    /// passed in `Handler`.
    pub fn new(handler: H) -> Ferrum<H> {
        Ferrum {
            handler,
            keep_alive: true,
            timeout: Some(Duration::from_secs(30)),
            num_threads: ::num_cpus::get(),
        }
    }

    /// Kick off the server process using the HTTP protocol.
    ///
    /// Call this once to begin listening for requests on the server.
    /// This consumes the Ferrum instance. This method will block
    /// the current thread executing the HTTP server.
    pub fn http<A>(self, addr: A) -> HyperResult<()>
        where A: ToSocketAddrs
    {
        let server = self.server(addr)?;//server.bind(&addr, InitialService::new(self.handler, Some(self.num_threads)))?;
        server.run()
    }

    /// Bind the provided `addr` and return a server ready to handle
    /// connections.
    pub fn server<A>(self, addr: A) -> HyperResult<Server<H>>
        where A: ToSocketAddrs
    {
        let addr = addr.to_socket_addrs()?
            .next()
            .ok_or(Error::new(ErrorKind::Other, "Empty addrs"))?;

        let mut server = Http::new();
        server.keep_alive(self.keep_alive);
        server.bind(&addr, InitialService::new(self.handler, Some(self.num_threads)))
    }
}