Skip to main content

wasm_pkg_client/
metadata.rs

1use anyhow::Context;
2use reqwest::StatusCode;
3use wasm_pkg_common::{
4    Error,
5    metadata::{REGISTRY_METADATA_PATH, RegistryMetadata},
6    registry::Registry,
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        // TODO use `core::net::Ipv4Addr::is_loopback()`
41        let scheme = if registry.host() == "localhost" || registry.host() == "127.0.0.1" {
42            "http"
43        } else {
44            "https"
45        };
46        let url = format!("{scheme}://{registry}{REGISTRY_METADATA_PATH}");
47        fetch_url(&url)
48            .await
49            .with_context(|| format!("error fetching registry metadata from {url:?}"))
50            .map_err(Error::RegistryMetadataError)
51    }
52}
53
54async fn fetch_url(url: &str) -> anyhow::Result<Option<RegistryMetadata>> {
55    tracing::debug!(?url, "Fetching registry metadata");
56
57    let resp = reqwest::get(url).await?;
58    if resp.status() == StatusCode::NOT_FOUND {
59        return Ok(None);
60    }
61    let resp = resp.error_for_status()?;
62    Ok(Some(resp.json().await?))
63}