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
use iron::headers::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};
use iron::modifiers::Header;
use iron::{Iron, Request, Response, IronResult};
use iron::status;
use mount::Mount;
use std::path::Path;
use std::thread::{spawn, JoinHandle};
use iron::middleware::Handler;
use staticfile::Static;
#[allow(unused_imports)] use std::fs::File;
#[allow(unused_imports)] use std::io::Read;
#[allow(unused_imports)] use std::str::from_utf8;
use Dashboard;
use WsServer;

include!(concat!(env!("OUT_DIR"), "/public.rs"));

pub struct Server {
    dashboard: Dashboard,
}

lazy_static! {
}

impl Server {
    pub fn serve_dashboard(dashboard: Dashboard) -> JoinHandle<()> {
        let join = Server{ dashboard: dashboard }.start();
        WsServer::send_message("start".to_owned());
        join
    }

    fn get_static_file(req: &mut Request) -> IronResult<Response> {
        let request_path = format!("./public/{}", req.url.path().join("/"));
        let file_path = match request_path.as_ref() {
            "./public/" => "./public/index.html",
            path => path
        };

        let content_result = Server::get_file_content(&file_path); 

        match content_result {
            Ok(content) => {
                let content_type = match Path::new(&file_path).extension().unwrap().to_str().unwrap() {
                    "html" => ContentType::html(),
                    "css" => ContentType(Mime(TopLevel::Text, SubLevel::Css, vec![])),
                    "js" | "json" => ContentType(Mime(TopLevel::Application, SubLevel::Javascript, vec![])),
                    "ico" => ContentType("image/x-icon".parse().unwrap()),
                    _ => ContentType(Mime(TopLevel::Text, SubLevel::Plain, vec![]))
                };

                let response = Response::with((status::Ok, content, Header(content_type)));
                Ok(response)
            },
            Err(_error) => Ok(Response::with(status::NotFound))
        }
    }

    #[cfg(feature = "serve_static")]
    fn get_file_content(file_path: &str) -> Result<String, String> {
        match PUBLIC.get(&file_path) {
            Err(_) => Server::path_not_found(file_path),
            file => Ok(file.map( |file_content| from_utf8(&file_content).unwrap().to_owned()).unwrap())
        }
    }

    #[cfg(feature = "debug_static")]
    fn get_file_content(file_path: &str) -> Result<String, String> {
        match PUBLIC.get(&file_path) {
            Err(_) => Server::path_not_found(file_path),
            _ => {
                let mut file = File::open(file_path).unwrap();
                let mut contents = String::new();
                file.read_to_string(&mut contents).unwrap();
                Ok(contents)
            }
        }
    }

    fn path_not_found(file_path: &str) -> Result<String, String>{
        println!("File not found: {}", file_path);
        Err("File not found".to_string())
    }

    fn start(&self) -> JoinHandle<()> {
        let dashboard = DashboardMount{dashboard: self.dashboard.get_init_script().to_owned()};
        let server = spawn(move || {
            let mut mount = Mount::new();
            mount
                .mount("/", Server::get_static_file)
                .mount("/graphs/", Static::new(Path::new("graphs")))
                .mount("/js/rusty-dashed.js", dashboard);
            Iron::new(mount).http("0.0.0.0:3000").unwrap();
        }); 
        server
    }

}

struct DashboardMount {
    pub dashboard: String
}

impl Handler for DashboardMount {
    fn handle(&self, _req: &mut Request) -> IronResult<Response>{
        Ok(Response::with((status::Ok, self.dashboard.to_owned())))
    }
}