use futures::future;
use futures::{Future, Stream};
use hyper::client::{Client as HyperClient, Connect};
use hyper::error::Error as HyperError;
use hyper::header::Authorization;
use hyper::{Method, Request, Uri};
use serde_json;
use std::str::FromStr;
use ::model::*;
use ::{Error, ImageParams, constants};
macro_rules! try_uri {
($uri:ident) => {
match Uri::from_str($uri) {
Ok(v) => v,
Err(why) => return Box::new(future::err(Error::Uri(why))),
}
};
}
pub trait WeebApiRequester {
fn get_images(&self) -> Box<Future<Item = ApiResponse, Error = Error>>;
fn get_image_info<S: Into<String>>(&self, auth: S, id: &str)
-> Box<Future<Item = Image, Error = Error>>;
fn get_image_random<S: Into<String>>(&self, auth: S, params: ImageParams)
-> Box<Future<Item = Image, Error = Error>>;
fn get_image_tags<S: Into<String>>(&self, auth: S, hidden: bool)
-> Box<Future<Item = Vec<String>, Error = Error>>;
fn get_image_types<S: Into<String>>(&self, auth: S, hidden: bool)
-> Box<Future<Item = Vec<String>, Error = Error>>;
}
impl<B, C: Connect> WeebApiRequester for HyperClient<C, B>
where B: Stream<Error = HyperError> + 'static, B::Item: AsRef<[u8]> {
fn get_images(&self) -> Box<Future<Item = ApiResponse, Error = Error>> {
let c = constants::GET_IMAGES;
let uri = try_uri!(c);
Box::new(self.get(uri)
.and_then(|res| res.body().concat2())
.map_err(From::from)
.and_then(|body| serde_json::from_slice(&body).map_err(From::from)))
}
fn get_image_info<S: Into<String>>(&self, auth: S, id: &str)
-> Box<Future<Item = Image, Error = Error>> {
let url = format!("{}{}", constants::GET_IMAGE_INFO, id);
let c = &url;
let uri = try_uri!(c);
Box::new(self.request(make_request(auth, uri))
.and_then(|res| res.body().concat2())
.map_err(From::from)
.and_then(|body| serde_json::from_slice(&body).map_err(From::from)))
}
fn get_image_random<S: Into<String>>(&self, auth: S, params: ImageParams)
-> Box<Future<Item = Image, Error = Error>> {
let built: Vec<(&str, String)> = params.into_data();
if built.is_empty() {
return Box::new(future::err(Error::NoParamsSpecified));
}
let params = built.iter().map(|&(query, ref value)| {
format!("{}={}", query, value)
}).collect::<Vec<String>>().join("&");
let url = format!("{}?{}", constants::GET_IMAGE_RANDOM, params);
let url = &url;
let uri = try_uri!(url);
Box::new(self.request(make_request(auth, uri))
.and_then(|res| res.body().concat2())
.map_err(From::from)
.and_then(|body| serde_json::from_slice(&body).map_err(From::from)))
}
fn get_image_tags<S: Into<String>>(&self, auth: S, hidden: bool)
-> Box<Future<Item = Vec<String>, Error = Error>> {
let url = format!("{}?{}",
constants::GET_IMAGE_TAGS,
hidden.to_string(),
);
let c = &url;
let uri = try_uri!(c);
Box::new(self.request(make_request(auth, uri))
.and_then(|res| res.body().concat2())
.map_err(From::from)
.and_then(|body| {
serde_json::from_slice::<ImageTagsResponse>(&body)
.map_err(From::from)
})
.map(|x| x.tags))
}
fn get_image_types<S: Into<String>>(&self, auth: S, hidden: bool)
-> Box<Future<Item = Vec<String>, Error = Error>> {
let url = format!("{}?{}",
constants::GET_IMAGE_TYPES,
hidden.to_string(),
);
let c = &url;
let uri = try_uri!(c);
Box::new(self.request(make_request(auth, uri))
.and_then(|res| res.body().concat2())
.map_err(From::from)
.and_then(|body| {
serde_json::from_slice::<ImageTypesResponse>(&body)
.map_err(From::from)
})
.map(|x| x.types))
}
}
fn make_request<B, S>(auth: S, uri: Uri)
-> Request<B> where B: Stream<Error = HyperError> + 'static,
B::Item: AsRef<[u8]>,
S: Into<String> {
let mut request = Request::new(Method::Get, uri);
request.headers_mut().set(Authorization(auth.into()));
request
}