use std::{sync::OnceLock, time::Duration};
use anyhow::Context;
use api::read::GetVersion;
use serde::Deserialize;
pub mod api;
pub mod busy;
pub mod deserializers;
pub mod entities;
pub mod parsers;
pub mod terminal;
pub mod ws;
#[cfg(feature = "utoipa")]
pub mod openapi;
mod request;
pub fn komodo_client() -> &'static KomodoClient {
static KOMODO_CLIENT: OnceLock<KomodoClient> = OnceLock::new();
KOMODO_CLIENT.get_or_init(|| {
KomodoClient::new_from_env()
.context("Missing KOMODO_ADDRESS, KOMODO_API_KEY, KOMODO_API_SECRET from env")
.unwrap()
})
}
#[derive(Deserialize)]
pub struct KomodoEnv {
pub komodo_address: String,
pub komodo_api_key: String,
pub komodo_api_secret: String,
}
#[derive(Clone)]
pub struct KomodoClient {
#[cfg(not(feature = "blocking"))]
reqwest: reqwest::Client,
#[cfg(feature = "blocking")]
reqwest: reqwest::blocking::Client,
address: String,
key: String,
secret: String,
}
impl KomodoClient {
pub fn new(
address: impl Into<String>,
key: impl Into<String>,
secret: impl Into<String>,
) -> KomodoClient {
KomodoClient {
reqwest: Default::default(),
address: address.into(),
key: key.into(),
secret: secret.into(),
}
}
pub fn new_from_env() -> anyhow::Result<KomodoClient> {
let KomodoEnv {
komodo_address,
komodo_api_key,
komodo_api_secret,
} = envy::from_env()
.context("failed to parse environment for komodo client")?;
Ok(KomodoClient::new(
komodo_address,
komodo_api_key,
komodo_api_secret,
))
}
#[cfg(not(feature = "blocking"))]
pub async fn with_healthcheck(self) -> anyhow::Result<Self> {
self.health_check().await?;
Ok(self)
}
#[cfg(feature = "blocking")]
pub fn with_healthcheck(self) -> anyhow::Result<Self> {
self.health_check()?;
Ok(self)
}
#[cfg(not(feature = "blocking"))]
pub async fn core_version(&self) -> anyhow::Result<String> {
self.read(GetVersion {}).await.map(|r| r.version)
}
#[cfg(feature = "blocking")]
pub fn core_version(&self) -> anyhow::Result<String> {
self.read(GetVersion {}).map(|r| r.version)
}
#[cfg(not(feature = "blocking"))]
pub async fn health_check(&self) -> anyhow::Result<()> {
self.read(GetVersion {}).await.map(|_| ())
}
#[cfg(feature = "blocking")]
pub fn health_check(&self) -> anyhow::Result<()> {
self.read(GetVersion {}).map(|_| ())
}
#[cfg(not(feature = "blocking"))]
pub fn set_reqwest(mut self, reqwest: reqwest::Client) -> Self {
self.reqwest = reqwest;
self
}
#[cfg(feature = "blocking")]
pub fn set_reqwest(
mut self,
reqwest: reqwest::blocking::Client,
) -> Self {
self.reqwest = reqwest;
self
}
#[cfg(not(feature = "blocking"))]
pub async fn poll_update_until_complete(
&self,
update_id: impl Into<String>,
) -> anyhow::Result<entities::update::Update> {
let update_id = update_id.into();
loop {
let update = self
.read(api::read::GetUpdate {
id: update_id.clone(),
})
.await?;
if update.status == entities::update::UpdateStatus::Complete {
return Ok(update);
}
tokio::time::sleep(Duration::from_millis(500)).await;
}
}
#[cfg(feature = "blocking")]
pub fn poll_update_until_complete(
&self,
update_id: impl Into<String>,
) -> anyhow::Result<entities::update::Update> {
let update_id = update_id.into();
loop {
let update = self.read(api::read::GetUpdate {
id: update_id.clone(),
})?;
if update.status == entities::update::UpdateStatus::Complete {
return Ok(update);
}
}
}
}