wasm_pkg_client/
metadata.rs

1use anyhow::Context;
2use reqwest::StatusCode;
3use wasm_pkg_common::{
4    metadata::{RegistryMetadata, REGISTRY_METADATA_PATH},
5    registry::Registry,
6    Error,
7};
8
9/// Extension trait for [`RegistryMetadata`] adding client functionality.
10pub trait RegistryMetadataExt: Sized {
11    /// Attempt to fetch [`RegistryMetadata`] from the given [`Registry`]. On
12    /// failure, return defaults.
13    fn fetch_or_default(registry: &Registry) -> impl std::future::Future<Output = Self> + Send;
14
15    /// Fetch [`RegistryMetadata`] from the given [`Registry`].
16    fn fetch(
17        registry: &Registry,
18    ) -> impl std::future::Future<Output = Result<Option<Self>, Error>> + Send;
19}
20
21impl RegistryMetadataExt for RegistryMetadata {
22    async fn fetch_or_default(registry: &Registry) -> Self {
23        match Self::fetch(registry).await {
24            Ok(Some(meta)) => {
25                tracing::debug!(?meta, "Got registry metadata");
26                meta
27            }
28            Ok(None) => {
29                tracing::debug!("Metadata not found");
30                Default::default()
31            }
32            Err(err) => {
33                tracing::warn!(error = ?err, "Error fetching registry metadata");
34                Default::default()
35            }
36        }
37    }
38
39    async fn fetch(registry: &Registry) -> Result<Option<Self>, Error> {
40        let scheme = if registry.host() == "localhost" {
41            "http"
42        } else {
43            "https"
44        };
45        let url = format!("{scheme}://{registry}{REGISTRY_METADATA_PATH}");
46        fetch_url(&url)
47            .await
48            .with_context(|| format!("error fetching registry metadata from {url:?}"))
49            .map_err(Error::RegistryMetadataError)
50    }
51}
52
53async fn fetch_url(url: &str) -> anyhow::Result<Option<RegistryMetadata>> {
54    tracing::debug!(?url, "Fetching registry metadata");
55
56    let resp = reqwest::get(url).await?;
57    if resp.status() == StatusCode::NOT_FOUND {
58        return Ok(None);
59    }
60    let resp = resp.error_for_status()?;
61    Ok(Some(resp.json().await?))
62}