warg-loader 0.0.6

Warg package loader
Documentation
use anyhow::Context;
use reqwest::StatusCode;
use serde::Deserialize;

use crate::Error;

const WELL_KNOWN_PATH: &str = ".well-known/warg/registry.json";

#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RegistryMeta {
    pub oci_registry: Option<String>,
    pub oci_namespace_prefix: Option<String>,
    pub warg_url: Option<String>,
}

impl RegistryMeta {
    pub async fn fetch_or_default(domain: &str) -> Self {
        match Self::fetch(domain).await {
            Ok(Some(meta)) => {
                tracing::debug!("Got registry metadata {meta:?}");
                meta
            }
            Ok(None) => {
                tracing::debug!("Metadata not found");
                Default::default()
            }
            Err(err) => {
                tracing::warn!("Error fetching registry metadata: {err}");
                Default::default()
            }
        }
    }

    pub async fn fetch(domain: &str) -> Result<Option<Self>, Error> {
        let scheme = if domain.starts_with("localhost:") {
            "http"
        } else {
            "https"
        };
        let url = format!("{scheme}://{domain}/{WELL_KNOWN_PATH}");
        Self::fetch_url(&url)
            .await
            .with_context(|| format!("error fetching registry metadata from {url:?}"))
            .map_err(Error::RegistryMeta)
    }

    async fn fetch_url(url: &str) -> anyhow::Result<Option<Self>> {
        tracing::debug!("Fetching registry metadata from {url:?}");
        let resp = reqwest::get(url).await?;
        if resp.status() == StatusCode::NOT_FOUND {
            return Ok(None);
        }
        let resp = resp.error_for_status()?;
        Ok(Some(resp.json().await?))
    }
}