use std::fmt::{Debug, Formatter};
use std::time::Duration;
use reqwest::Url;
use reqwest::redirect::Policy;
use spiral_contract::call::CallError;
use uuid::Uuid;
use crate::Error;
use crate::api::enrichments::{
CreateEnrichmentRequest, CreateEnrichmentResponse,
CreateVersionRequest as CreateEnrichmentVersionRequest,
CreateVersionResponse as CreateEnrichmentVersionResponse, EnrichmentsApi, EnrichmentsClient,
ReadVersionResponse as ReadEnrichmentVersionResponse,
StorageAccessRequest as EnrichmentStorageAccessRequest,
StorageAccessResponse as EnrichmentStorageAccessResponse,
StorageBinding as EnrichmentStorageBinding,
};
use crate::api::tables::objects::TableId;
use crate::api::tables::{
CreateTableRequest, CreateTableResponse, CreateVersionRequest, CreateVersionResponse,
ReadVersionResponse, StorageAccessRequest, StorageAccessResponse, StorageBinding, TablesApi,
TablesClient,
};
use crate::auth::TokenSource;
use crate::http::{HttpClient, http_client_builder};
#[derive(Clone)]
pub struct Client {
http: HttpClient,
tables: TablesClient,
enrichments: EnrichmentsClient,
}
impl Debug for Client {
fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
formatter
.debug_struct("Client")
.field("base_url", self.http.base_url())
.finish_non_exhaustive()
}
}
impl Client {
pub fn new(base_url: &str) -> Result<Self, Error> {
let base = Url::parse(base_url).map_err(Error::invalid)?;
let client = http_client_builder()
.gzip(true)
.redirect(Policy::none())
.timeout(Duration::from_secs(60))
.build()
.map_err(Error::invalid)?;
Self::from_http(HttpClient::new(base, client, None))
}
pub(crate) fn from_http(http: HttpClient) -> Result<Self, Error> {
let tables =
TablesClient::from_transport(http.base_url().as_str(), http.middleware_client())
.map_err(Error::from)?;
let enrichments =
EnrichmentsClient::from_transport(http.base_url().as_str(), http.middleware_client())
.map_err(Error::from)?;
Ok(Self {
http,
tables,
enrichments,
})
}
pub fn with_client(mut self, client: reqwest::Client) -> Self {
self.http = self.http.with_client(client);
self.tables = self.tables.with_transport(self.http.middleware_client());
self.enrichments = self
.enrichments
.with_transport(self.http.middleware_client());
self
}
pub fn with_token_source(mut self, provider: TokenSource) -> Self {
self.http = self.http.with_token_source(provider);
self
}
pub async fn create(&self, request: &CreateTableRequest) -> Result<CreateTableResponse, Error> {
self.tables
.create_table(self.http.auth_header().await?, request.clone())
.await
.map_err(Error::from)
}
pub async fn storage_access(
&self,
table_id: TableId,
request: &StorageAccessRequest,
) -> Result<StorageAccessResponse, Error> {
self.tables
.storage_access(self.http.auth_header().await?, table_id, request.clone())
.await
.map_err(Error::from)
}
pub async fn storage_binding(
&self,
table_id: TableId,
request: &StorageAccessRequest,
) -> Result<Option<StorageBinding>, Error> {
match self
.tables
.storage_binding(self.http.auth_header().await?, table_id, request.clone())
.await
{
Ok(binding) => Ok(Some(binding)),
Err(error) if missing(&error) => Ok(None),
Err(error) => Err(error.into()),
}
}
pub async fn create_version(
&self,
table_id: TableId,
request: &CreateVersionRequest,
) -> Result<CreateVersionResponse, Error> {
self.tables
.create_version(self.http.auth_header().await?, table_id, request.clone())
.await
.map_err(Error::from)
}
pub async fn get_version(
&self,
table_id: TableId,
version_id: Uuid,
) -> Result<ReadVersionResponse, Error> {
self.tables
.read_version(self.http.auth_header().await?, table_id, version_id)
.await
.map_err(Error::from)
}
pub async fn create_enrichment(
&self,
request: &CreateEnrichmentRequest,
) -> Result<CreateEnrichmentResponse, Error> {
self.enrichments
.create_enrichment(self.http.auth_header().await?, request.clone())
.await
.map_err(Error::from)
}
pub async fn enrichment_storage_access(
&self,
enrichment_id: Uuid,
request: &EnrichmentStorageAccessRequest,
) -> Result<EnrichmentStorageAccessResponse, Error> {
self.enrichments
.storage_access(
self.http.auth_header().await?,
enrichment_id,
request.clone(),
)
.await
.map_err(Error::from)
}
pub async fn enrichment_storage_binding(
&self,
enrichment_id: Uuid,
request: &EnrichmentStorageAccessRequest,
) -> Result<Option<EnrichmentStorageBinding>, Error> {
match self
.enrichments
.storage_binding(
self.http.auth_header().await?,
enrichment_id,
request.clone(),
)
.await
{
Ok(binding) => Ok(Some(binding)),
Err(error) if missing(&error) => Ok(None),
Err(error) => Err(error.into()),
}
}
pub async fn create_enrichment_version(
&self,
enrichment_id: Uuid,
request: &CreateEnrichmentVersionRequest,
) -> Result<CreateEnrichmentVersionResponse, Error> {
self.enrichments
.create_version(
self.http.auth_header().await?,
enrichment_id,
request.clone(),
)
.await
.map_err(Error::from)
}
pub async fn read_enrichment_version(
&self,
enrichment_id: Uuid,
version_id: Uuid,
) -> Result<ReadEnrichmentVersionResponse, Error> {
self.enrichments
.read_version(self.http.auth_header().await?, enrichment_id, version_id)
.await
.map_err(Error::from)
}
}
fn missing<E>(error: &CallError<E>) -> bool {
match error {
CallError::Service(failure) => failure.status() == 404,
CallError::UnknownRemote(failure) => failure.status() == 404,
_ => false,
}
}