pub use reqwest::Client;
use DigitalOcean;
use api::{HasPagination, HasResponse, HasValue, MAX_PER_PAGE};
use error::*;
use method::{Create, Delete, Get, List, Update};
use request::Request;
use reqwest::{RequestBuilder, Response};
use reqwest::StatusCode;
use reqwest::header::{Authorization, Bearer};
impl DigitalOcean {
pub(crate) fn get<V>(&self, request: Request<Get, V>) -> Result<V>
where
V: HasResponse,
{
info!("GET {:?}", request.url());
let req = self.client.get(request.url().clone())?;
let mut response = self.fetch(req)?;
match response.status() {
StatusCode::Ok => (),
StatusCode::NotFound => Err(ErrorKind::NotFound)?,
e => Err(ErrorKind::UnexpectedStatus(e))?,
};
let deserialized: V::Response = response.json()?;
Ok(deserialized.value())
}
pub(crate) fn list<V>(&self, request: Request<List, Vec<V>>) -> Result<Vec<V>>
where
Vec<V>: HasResponse,
<Vec<V> as HasResponse>::Response: HasPagination,
{
info!("LIST {:?}", request.url());
let mut buffer = Vec::new();
let mut current_url = request.url().clone();
match request.method().0 {
Some(limit) if limit < MAX_PER_PAGE => {
current_url.query_pairs_mut().append_pair(
"per_page",
&limit.to_string(),
);
},
_ => {
current_url.query_pairs_mut().append_pair(
"per_page",
&MAX_PER_PAGE.to_string(),
);
},
};
loop {
let req = self.client.get(current_url.clone())?;
let mut response = self.fetch(req)?;
match response.status() {
StatusCode::Ok => (),
StatusCode::NotFound => Err(ErrorKind::NotFound)?,
e => Err(ErrorKind::UnexpectedStatus(e))?,
};
let deserialized: <Vec<V> as HasResponse>::Response = response.json()?;
let next_page = deserialized.next_page();
buffer.extend(deserialized.value());
current_url = match next_page {
Some(v) => v,
None => break,
};
if let Some(limit) = request.method().0 {
let buffer_size = buffer.len();
let remaining = limit - buffer_size;
if buffer_size >= limit {
break;
} else if remaining < MAX_PER_PAGE {
current_url.query_pairs_mut().append_pair(
"per_page",
&remaining.to_string(),
);
}
}
info!("Fetching next page...")
}
Ok(buffer)
}
pub(crate) fn delete<V>(&self, request: Request<Delete, V>) -> Result<()> {
info!("DELETE {:?}", request.url());
let req = self.client.delete(request.url().clone())?;
let response = self.fetch(req)?;
match response.status() {
StatusCode::NoContent => (), e => Err(ErrorKind::UnexpectedStatus(e))?,
};
Ok(())
}
pub(crate) fn post<V>(&self, request: Request<Create, V>) -> Result<V>
where
V: HasResponse,
{
info!("POST {:?}", request.url());
let mut req = self.client.post(request.url().clone())?;
req.json(&request.body().clone())?;
let mut response = self.fetch(req)?;
match response.status() {
StatusCode::Created => (), StatusCode::UnprocessableEntity => {
Err(ErrorKind::UnprocessableEntity(response.json()?))?
},
e => Err(ErrorKind::UnexpectedStatus(e))?,
};
let deserialized: V::Response = response.json()?;
Ok(deserialized.value())
}
pub(crate) fn put<V>(&self, request: Request<Update, V>) -> Result<V>
where
V: HasResponse,
{
info!("PUT {:?}", request.url());
let mut req = self.client.put(request.url().clone())?;
req.json(&request.body().clone())?;
let mut response = self.fetch(req)?;
match response.status() {
StatusCode::Ok => (), StatusCode::UnprocessableEntity => {
Err(ErrorKind::UnprocessableEntity(response.json()?))?
},
e => Err(ErrorKind::UnexpectedStatus(e))?,
};
let deserialized: V::Response = response.json()?;
Ok(deserialized.value())
}
fn fetch(&self, mut dispatch: RequestBuilder) -> Result<Response> {
let response = dispatch
.header(Authorization(Bearer { token: self.token.clone() }))
.send()?;
info!("Response status: {:?}", response.status());
Ok(response)
}
}