pub use reqwest::Client;
use crate::api::{HasPagination, HasResponse, HasValue, MAX_PER_PAGE};
use crate::error::Error;
use crate::method::{Create, Delete, Get, List, Update};
use crate::request::Request;
use crate::DigitalOcean;
use log::info;
use reqwest::StatusCode;
use reqwest::{RequestBuilder, Response};
impl DigitalOcean {
pub(crate) async fn get<V>(&self, request: Request<Get, V>) -> Result<V, Error>
where
V: HasResponse,
{
info!("GET {:?}", request.url());
let req = self.client.get(request.url().clone());
let response = self.fetch(req).await?;
match response.status() {
StatusCode::OK => {}
StatusCode::NOT_FOUND => Err(Error::NotFound)?,
e => Err(Error::UnexpectedStatus(e))?,
};
let deserialized: V::Response = response.json().await?;
Ok(deserialized.value())
}
pub(crate) async fn list<V>(&self, request: Request<List, Vec<V>>) -> Result<Vec<V>, Error>
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 response = self.fetch(req).await?;
match response.status() {
StatusCode::OK => {}
StatusCode::NOT_FOUND => Err(Error::NotFound)?,
e => Err(Error::UnexpectedStatus(e))?,
};
let deserialized: <Vec<V> as HasResponse>::Response = response.json().await?;
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) async fn delete<V>(&self, request: Request<Delete, V>) -> Result<(), Error> {
info!("DELETE {:?}", request.url());
let req = self.client.delete(request.url().clone());
let response = self.fetch(req).await?;
match response.status() {
StatusCode::NO_CONTENT => {} e => Err(Error::UnexpectedStatus(e))?,
};
Ok(())
}
pub(crate) async fn post<V>(&self, request: Request<Create, V>) -> Result<V, Error>
where
V: HasResponse,
{
info!("POST {:?}", request.url());
let req = self
.client
.post(request.url().clone())
.json(&request.body().clone());
let response = self.fetch(req).await?;
match response.status() {
StatusCode::CREATED => {} StatusCode::ACCEPTED => {} StatusCode::UNPROCESSABLE_ENTITY => {
return Err(Error::UnprocessableEntity(response.json().await?))?;
}
e => Err(Error::UnexpectedStatus(e))?,
};
let deserialized: V::Response = response.json().await?;
Ok(deserialized.value())
}
pub(crate) async fn put<V>(&self, request: Request<Update, V>) -> Result<V, Error>
where
V: HasResponse,
{
info!("PUT {:?}", request.url());
let req = self
.client
.put(request.url().clone())
.json(&request.body().clone());
let response = self.fetch(req).await?;
match response.status() {
StatusCode::OK => {} StatusCode::UNPROCESSABLE_ENTITY => {
return Err(Error::UnprocessableEntity(response.json().await?))?;
}
e => Err(Error::UnexpectedStatus(e))?,
};
let deserialized: V::Response = response.json().await?;
Ok(deserialized.value())
}
async fn fetch(&self, dispatch: RequestBuilder) -> Result<Response, Error> {
let response = dispatch.bearer_auth(self.token.clone()).send().await?;
info!("Response status: {:?}", response.status());
Ok(response)
}
}