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
135
136
137
138
139
140
141
142
extern crate hyper;
extern crate hyper_native_tls;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;

static URL: &'static str = "http://api.openaq.org";

mod entities;
pub use entities::*;

pub mod json {
    use hyper::Client;
    use hyper::net::HttpsConnector;
    use hyper_native_tls::NativeTlsClient;
    use std::io::Read;

    use super::*;

    pub mod requests {
        pub const CITIES: &str = "/v1/cities";
        pub const COUNTRIES: &str = "/v1/countries";
        pub const PARAMETERS: &str = "/v1/parameters";
        pub const FETCHES: &str = "/v1/fetches";
    }

    pub struct GetOpts {
        pub query: Option<String>,
    }

    pub fn get_cities_query(opts: GetCitiesQueryOpts) -> String {
        return String::from("page=") + &opts.page.to_string() + "&limit=" +
               &opts.limit.to_string() + "&country=" + opts.country;
    }

    pub fn get_countries_query(opts: GetCountriesQueryOpts) -> String {
        return String::from("page=") + &opts.page.to_string() + "&limit=" + &opts.limit.to_string();
    }

    pub fn get_fetches_query(opts: GetFetchesQueryOpts) -> String {
        return String::from("page=") + &opts.page.to_string() + "&limit=" + &opts.limit.to_string();
    }

    pub fn get(req: &str, opts: Option<GetOpts>) -> String {
        let ssl = NativeTlsClient::new().unwrap();
        let connector = HttpsConnector::new(ssl);
        let client = Client::with_connector(connector);
        let full_url = match &opts {
            &None => String::from(URL) + req,
            &Some(ref o) => {
                match &o.query {
                    &None => String::from(URL) + req,
                    &Some(ref q) => String::from(URL) + req + "?" + q,
                }
            }
        };

        let mut res = client.get(&full_url).send().unwrap();

        assert_eq!(res.status, hyper::Ok);
        let mut s = String::new();
        res.read_to_string(&mut s).unwrap();

        return s;
    }
}

pub struct GetCitiesQueryOpts<'a> {
    pub page: u32,
    pub limit: u32,
    pub country: &'a str,
}

pub struct GetCountriesQueryOpts {
    pub page: u32,
    pub limit: u32,
}

pub struct GetFetchesQueryOpts {
    pub page: u32,
    pub limit: u32,
}

macro_rules! extract_results {
    ($T: ty, $endpoint: expr, $opts: expr) => {
        #[derive(Debug, Serialize, Deserialize)]
        struct RequestResult {
            results: Vec<$T>,
        }
        let result = json::get($endpoint, $opts);
        let v: RequestResult = serde_json::from_str(&result).unwrap();

        return v.results;
    };
}

macro_rules! extract_results_with_opts {
    ($get_query: expr, $T: ty, $endpoint: expr, $opts: expr) => {
        let get_opts = match $opts {
            None => None,
            Some(o) => {
                let query = $get_query(o);
                let opts = json::GetOpts { query: Some(query) };
                Some(opts)
            }
        };

        extract_results!($T, $endpoint, get_opts);
    };
}

pub fn get_cities(cities_query_opts: Option<GetCitiesQueryOpts>) -> Vec<City> {
    extract_results_with_opts!(json::get_cities_query,
                               City,
                               json::requests::CITIES,
                               cities_query_opts);
}

pub fn get_fetches(fetches_query_opts: Option<GetFetchesQueryOpts>) -> Vec<Fetch> {
    extract_results_with_opts!(json::get_fetches_query,
                               Fetch,
                               json::requests::FETCHES,
                               fetches_query_opts);
}

pub fn get_countries(countries_query_opts: Option<GetCountriesQueryOpts>) -> Vec<Country> {
    let get_opts = match countries_query_opts {
        None => None,
        Some(o) => {
            let countries_query = json::get_countries_query(o);
            let opts = json::GetOpts { query: Some(countries_query) };
            Some(opts)
        }
    };

    extract_results!(Country, json::requests::COUNTRIES, get_opts);
}

pub fn get_parameters() -> Vec<Parameter> {
    extract_results!(Parameter, json::requests::PARAMETERS, None);
}