use base64::prelude::*;
use reqwest::{header, Client};
use super::Awtrix3Error;
pub struct Awtrix3HttpClient {
host: String,
port: u16,
username: Option<String>,
password: Option<String>,
client: Client,
}
impl Awtrix3HttpClient {
pub fn new<S: Into<String>>(host: S, port: u16) -> Awtrix3HttpClient {
Awtrix3HttpClient {
host: host.into(),
port,
username: None,
password: None,
client: reqwest::Client::new(),
}
}
pub fn with_credentials<S: Into<String>>(self, username: S, password: S) -> Self {
let mut headers = header::HeaderMap::new();
let username: String = username.into();
let password: String = password.into();
let mut auth_header_value = header::HeaderValue::from_str(&format!(
"Basic {}",
BASE64_STANDARD.encode(format!("{}:{}", username, password))
))
.unwrap();
auth_header_value.set_sensitive(true);
headers.insert(header::AUTHORIZATION, auth_header_value);
Self {
client: reqwest::Client::builder()
.default_headers(headers)
.build()
.unwrap(),
username: Some(username),
password: Some(password),
..self
}
}
pub async fn get_request<T>(&self, path: &str) -> Result<T, Awtrix3Error>
where
T: serde::de::DeserializeOwned,
{
if !path.starts_with("/") {
return Err(Awtrix3Error::InvalidPath(path.to_string()));
}
let resp = self.client.get(format!("{}{}", self.base_url(), path));
let resp = resp.send().await?;
if !resp.status().is_success() {
return Err(Awtrix3Error::HttpError(resp.status()));
}
let resp = resp.json::<T>().await?;
Ok(resp)
}
pub async fn post_request_response<T, R>(&self, path: &str, body: T) -> Result<R, Awtrix3Error>
where
T: serde::Serialize,
R: serde::de::DeserializeOwned,
{
if !path.starts_with("/") {
return Err(Awtrix3Error::InvalidPath(path.to_string()));
}
let resp = self.client.post(format!("{}{}", self.base_url(), path));
let resp = resp.json(&body);
let resp = resp.send().await?;
if !resp.status().is_success() {
return Err(Awtrix3Error::HttpError(resp.status()));
}
if resp.content_length().unwrap_or(0) == 0 {
return Ok(serde_json::from_str("null")?);
}
let resp = resp.json::<R>().await?;
Ok(resp)
}
pub async fn post_request<T>(&self, path: &str, body: T) -> Result<(), Awtrix3Error>
where
T: serde::Serialize,
{
if !path.starts_with("/") {
return Err(Awtrix3Error::InvalidPath(path.to_string()));
}
let resp = self.client.post(format!("{}{}", self.base_url(), path));
let resp = resp.json(&body);
let resp = resp.send().await?;
if !resp.status().is_success() {
return Err(Awtrix3Error::HttpError(resp.status()));
}
Ok(())
}
pub async fn post_empty_request(&self, path: &str) -> Result<(), Awtrix3Error> {
if !path.starts_with("/") {
return Err(Awtrix3Error::InvalidPath(path.to_string()));
}
let resp = self.client.post(format!("{}{}", self.base_url(), path));
let resp = resp.send().await?;
if !resp.status().is_success() {
return Err(Awtrix3Error::HttpError(resp.status()));
}
Ok(())
}
pub fn is_authenticated(&self) -> bool {
self.username.is_some() && self.password.is_some()
}
pub fn base_url(&self) -> String {
format!("http://{}:{}", self.host, self.port)
}
}