use anyhow::{ensure, Result};
use hyper::body::Buf;
use hyper::client::HttpConnector;
use hyper::header::CONTENT_TYPE;
use hyper::{Body, Client, Request};
use serde::de::DeserializeOwned;
use serde_json::Value;
#[derive(Clone)]
pub struct CadreClient {
client: Client<HttpConnector>,
origin: String,
secret: String,
}
impl CadreClient {
pub fn new(origin: &str, secret: &str) -> Self {
let mut connector = HttpConnector::new();
connector.set_nodelay(true);
Self {
client: Client::builder().build(connector),
origin: origin.into(),
secret: secret.into(),
}
}
async fn send(&self, req: Request<Body>) -> Result<impl Buf> {
let resp = self.client.request(req).await?;
let status = resp.status();
ensure!(!status.is_server_error(), "cadre server error: {status}");
ensure!(status.is_success(), "cadre get request failed: {status}");
Ok(hyper::body::aggregate(resp).await?)
}
async fn get<T: DeserializeOwned>(&self, uri: &str) -> Result<T> {
let req = Request::builder()
.method("GET")
.header("X-Cadre-Secret", &self.secret)
.uri(uri)
.body(Body::empty())?;
let resp = self.send(req).await?;
Ok(serde_json::from_reader(resp.reader())?)
}
pub async fn read_template(&self, env: &str) -> Result<Value> {
self.get(&format!("{}/t/{}", self.origin, env)).await
}
pub async fn write_template(&self, env: &str, template: &Value) -> Result<()> {
let req = Request::builder()
.method("PUT")
.uri(format!("{}/t/{}", self.origin, env))
.header(CONTENT_TYPE, "application/json")
.header("X-Cadre-Secret", &self.secret)
.body(serde_json::to_string(template)?.into())?;
self.send(req).await?;
Ok(())
}
pub async fn load_config(&self, env: &str) -> Result<Value> {
self.get(&format!("{}/c/{}", self.origin, env)).await
}
pub async fn list_configs(&self) -> Result<Vec<String>> {
self.get(&format!("{}/c", self.origin)).await
}
}