tic/
http.rs

1use controller::Controller;
2use receiver::Receiver;
3use std::fmt::Display;
4use std::hash::Hash;
5use std::net::ToSocketAddrs;
6use tiny_http::{Response, Server};
7
8/// an HTTP-based endpoint for viewing all registered metrics on a `Receiver`
9pub struct HttpReporter<T> {
10    server: Server,
11    controller: Controller<T>,
12}
13
14impl<T: Eq + Hash + Send + Clone + Display> HttpReporter<T> {
15    /// creates a new `HttpReporter` from the given `Receiver`, listening on the given address
16    pub fn new<U: ToSocketAddrs>(receiver: &Receiver<T>, listen: U) -> HttpReporter<T> {
17        let address = listen
18            .to_socket_addrs()
19            .expect("SocketAddr lookup failed")
20            .next()
21            .expect("SocketAddr resolved to empty set");
22
23        let controller = receiver.get_controller();
24        let server = Server::http(address).unwrap();
25
26        HttpReporter {
27            server: server,
28            controller: controller,
29        }
30    }
31
32    /// runs the HTTP server loop, this will block the calling thread until the process exists
33    ///
34    /// you should run this via `thread::spawn`
35    pub fn run(&mut self) {
36        for request in self.server.incoming_requests() {
37            let response = match self.controller.get_meters() {
38                Ok(meters) => {
39                    let mut output = "".to_owned();
40                    match request.url() {
41                        "/vars" | "/metrics" => {
42                            for (stat, value) in &meters.data {
43                                output = output + &format!("{} {}\n", stat, value);
44                            }
45                            for (stat, value) in &meters.data_float {
46                                output = output + &format!("{} {}\n", stat, value);
47                            }
48                        }
49                        _ => {
50                            output += "{";
51                            for (stat, value) in &meters.data {
52                                output = output + &format!("\"{}\":{},", stat, value);
53                            }
54                            for (stat, value) in &meters.data_float {
55                                output = output + &format!("\"{}\":{},", stat, value);
56                            }
57                            if output.len() > 1 {
58                                output.pop();
59                            }
60                            output += "}";
61                        }
62                    }
63
64                    Response::from_string(output)
65                }
66                Err(_) => {
67                    let response = Response::from_string("failed to read meters from receiver");
68                    response.with_status_code(500)
69                }
70            };
71
72            let _ = request.respond(response);
73        }
74    }
75}