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
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
extern crate regex;

pub mod config;
pub mod connection;
pub mod http;
pub mod router;
pub mod server_states;
pub mod thread_utils;

use std::net::{SocketAddr, TcpListener};
use std::time::Duration;
use config::*;
use connection::*;
use router::*;
use server_states::*;
use thread_utils::ThreadPool;

//TODO: handle errors with grace...

pub struct HttpServer {
    router: Route,
    config: ServerConfig,
    states: ServerStates,
}

pub trait ServerDef {
    fn def_router(&mut self, router: Route);
    fn set_pool_size(&mut self, size: usize);
    fn set_read_timeout(&mut self, timeout: u8);
    fn set_write_timeout(&mut self, timeout: u8);
}

impl HttpServer {
    pub fn new() -> Self {
        HttpServer {
            router: Route::new(),
            config: ServerConfig::new(),
            states: ServerStates::new(),
        }
    }

    pub fn listen(&self, port: u16) {
        let server_address = SocketAddr::from(([127, 0, 0, 1], port));
        if let Ok(listener) = TcpListener::bind(server_address) {
            println!("Listening for connections on port {}", port);

            start_with(&listener, &self.router, &self.config, &self.states);
            drop(listener);
        } else {
            panic!("Unable to start the http server...");
        }

        println!("Shutting down...");
    }

    pub fn terminate(&mut self) {
        println!("Requested to shutdown...");
        self.states.set_to_terminate();
    }
}

impl Router for HttpServer {
    fn get(&mut self, uri: RequestPath, callback: Callback) {
        self.router.get(uri, callback);
    }

    fn put(&mut self, uri: RequestPath, callback: Callback) {
        self.router.put(uri, callback);
    }

    fn post(&mut self, uri: RequestPath, callback: Callback) {
        self.router.post(uri, callback);
    }

    fn delete(&mut self, uri: RequestPath, callback: Callback) {
        self.router.delete(uri, callback);
    }

    fn other(&mut self, uri: RequestPath, callback: Callback) {
        self.router.other(uri, callback);
    }
}

impl ServerDef for HttpServer {
    fn def_router(&mut self, router: Route) {
        self.router = router;
    }

    fn set_pool_size(&mut self, size: usize) {
        self.config.pool_size = size;
    }

    fn set_read_timeout(&mut self, timeout: u8) {
        self.config.read_timeout = timeout;
    }

    fn set_write_timeout(&mut self, timeout: u8) {
        self.config.write_timeout = timeout;
    }
}

fn start_with(listener: &TcpListener, router: &Route, config: &ServerConfig, server_states: &ServerStates) {

    let pool = ThreadPool::new(config.pool_size);
    let read_timeout = Some(Duration::new(config.read_timeout as u64, 0));
    let write_timeout = Some(Duration::new(config.write_timeout as u64, 0));

    for stream in listener.incoming() {
        if let Ok(s) = stream {
            if let Err(e) = s.set_read_timeout(read_timeout) {
                println!("Unable to set read timeout: {}", e);
                continue;
            }

            if let Err(e) = s.set_write_timeout(write_timeout) {
                println!("Unable to set write timeout: {}", e);
                continue;
            }

            // clone the router so it can out live the closure.
            let router = Route::from(&router);
            pool.execute(move || {
                handle_connection(s, &router);
            });
        }

        if server_states.is_terminating() {
            break;
        }
    }

    //close the listener with grace
    drop(pool);
}