use super::Authentication;
use super::authentication;
use crate::containerization_extras::ProgressHandler;
use crate::containerization_oci::image::Descriptor;
use crate::containerization_oci::image::Index;
use crate::error::Error;
use crate::platform;
use crate::platform::ffi;
use std::path::Path;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct RetryOptions {
pub max_retries: isize,
pub retry_interval: u64,
}
impl RetryOptions {
pub fn new(max_retries: isize, retry_interval: u64) -> Self {
Self {
max_retries,
retry_interval,
}
}
}
#[derive(Clone, Debug)]
pub struct HostOptions {
pub scheme: Option<String>,
pub port: Option<u16>,
pub authentication: Option<Authentication>,
pub client_id: Option<String>,
pub retry_options: Option<RetryOptions>,
pub buffer_size: usize,
}
impl Default for HostOptions {
fn default() -> Self {
Self {
scheme: Some("https".to_string()),
port: None,
authentication: None,
client_id: None,
retry_options: None,
buffer_size: 4 * 1024 * 1024,
}
}
}
pub struct RegistryClient {
handle: ffi::CzRegistryClient,
}
unsafe impl Send for RegistryClient {}
unsafe impl Sync for RegistryClient {}
impl RegistryClient {
pub fn new(reference: &str, insecure: bool, auth: Option<&Authentication>) -> Result<Self, Error> {
platform::outcome(
ffi::cz_registry_client_new(reference, insecure, authentication::crossing(auth)?),
format!("make a registry client for {reference}"),
)
.map(|outcome| Self {
handle: outcome.registry_client(),
})
}
pub fn with_host(host: &str, options: HostOptions) -> Result<Self, Error> {
platform::outcome(
ffi::cz_registry_client_with_host(
host,
options.scheme,
options.port,
authentication::crossing(options.authentication.as_ref())?,
options.client_id,
options.retry_options.is_some(),
options
.retry_options
.map_or(0, |retry_options| retry_options.max_retries),
options
.retry_options
.map_or(0, |retry_options| retry_options.retry_interval),
options.buffer_size,
),
format!("make a registry client for {host}"),
)
.map(|outcome| Self {
handle: outcome.registry_client(),
})
}
pub fn ping(&self) -> Result<(), Error> {
platform::outcome(self.handle.ping(), "ping the registry").map(drop)
}
pub fn resolve(&self, name: &str, tag: &str) -> Result<Descriptor, Error> {
platform::outcome(self.handle.resolve(name, tag), format!("resolve {name}:{tag}"))
.map(|outcome| outcome.descriptor())
}
pub fn fetch_data(&self, name: &str, descriptor: &Descriptor) -> Result<Vec<u8>, Error> {
platform::outcome(
self.handle.fetch_data(name, descriptor.clone()),
format!("fetch {} from {name}", descriptor.digest),
)
.map(|outcome| outcome.bytes())
}
pub fn fetch_blob(
&self,
name: &str,
descriptor: &Descriptor,
into: &Path,
progress: Option<ProgressHandler>,
) -> Result<(i64, String), Error> {
let outcome = platform::outcome(
self.handle.fetch_blob(
name,
descriptor.clone(),
&into.display().to_string(),
platform::Progress(progress),
),
format!("fetch {} from {name} into {}", descriptor.digest, into.display()),
)?;
Ok((outcome.written_size(), outcome.written_digest()))
}
pub fn catalog(&self, prefix: Option<&str>) -> Result<Vec<String>, Error> {
platform::outcome(
self.handle.catalog(prefix.map(str::to_string)),
"list the registry's repositories",
)
.map(|outcome| outcome.strings())
}
pub fn referrers(&self, name: &str, digest: &str, artifact_type: Option<&str>) -> Result<Index, Error> {
platform::outcome(
self
.handle
.referrers(name, digest, artifact_type.map(str::to_string)),
format!("list what refers to {digest} in {name}"),
)
.map(|outcome| outcome.index())
}
}