huehue 0.5.0

Rust wrapper for Hue v2 API.
Documentation
use reqwest::header::HeaderMap;
use reqwest::{Certificate, Client, ClientBuilder, Error, StatusCode};
use serde::de::DeserializeOwned;
use serde::Serialize;
use url::Url;

use crate::certificate::CERTIFICATE;
use crate::models::error::ErrorCode;

const HUE_APPLICATION_KEY_HEADER: &str = "hue-application-key";

#[derive(Debug)]
pub enum HueError {
	Unauthorized,
	AlreadyAuthorized,
	Connection,
	Response(reqwest::Error),
	Unsupported,
	Unexpected,
	Unknown,
}

fn build_base() -> ClientBuilder {
	reqwest::Client::builder()
		.add_root_certificate(Certificate::from_pem(CERTIFICATE.as_bytes()).unwrap())
		.danger_accept_invalid_hostnames(true)
}

pub fn build() -> Client {
	build_base().build().unwrap()
}

pub fn build_with_key(application_key: String) -> Client {
	let mut headers = HeaderMap::new();
	headers.insert(HUE_APPLICATION_KEY_HEADER, application_key.parse().unwrap());

	build_base().default_headers(headers).build().unwrap()
}

pub async fn get_auth<R>(application_key: String, url: Url) -> Result<R, HueError>
where
	R: DeserializeOwned,
{
	let client = build_with_key(application_key);

	let response = match client.get(url).send().await {
		Ok(response) => response,
		Err(e) => return Err(HueError::from(e)),
	};

	match response.json::<R>().await {
		Ok(payload) => Ok(payload),
		Err(e) => Err(HueError::from(e)),
	}
}

#[allow(unused)]
pub async fn get_auth_text(application_key: String, url: Url) -> Result<String, HueError> {
	let client = build_with_key(application_key);

	let response = match client.get(url).send().await {
		Ok(response) => response,
		Err(e) => return Err(HueError::from(e)),
	};

	match response.text().await {
		Ok(payload) => Ok(payload),
		Err(e) => Err(HueError::from(e)),
	}
}

pub async fn put_auth<R, T>(application_key: String, url: Url, object: &T) -> Result<R, HueError>
where
	T: Serialize,
	R: DeserializeOwned,
{
	let client = build_with_key(application_key);

	let response = match client.put(url).json(&object).send().await {
		Ok(response) => response,
		Err(e) => return Err(HueError::from(e)),
	};

	match response.json::<R>().await {
		Ok(payload) => Ok(payload),
		Err(e) => Err(HueError::from(e)),
	}
}

impl From<Error> for HueError {
	fn from(e: Error) -> Self {
		if e.is_status() {
			match e.status().unwrap() {
				StatusCode::UNAUTHORIZED => HueError::Unauthorized,
				_ => HueError::Unknown,
			}
		} else if e.is_connect() {
			return HueError::Connection;
		} else if e.is_decode() {
			return HueError::Response(e);
		} else {
			HueError::Unknown
		}
	}
}

impl From<ErrorCode> for HueError {
	fn from(ec: ErrorCode) -> Self {
		match ec {
			ErrorCode::Unauthorized => HueError::Unauthorized,
			ErrorCode::LinkButtonNotPressed => HueError::Unauthorized,
			_ => HueError::Unknown,
		}
	}
}