tirocinio-canali-steffo-acrate/acrate-nodeinfo/src/lib.rs

139 lines
3.1 KiB
Rust
Raw Normal View History

2024-11-09 10:01:26 +00:00
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
pub struct Discovery {
pub links: Vec<DiscoveryDocument>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DiscoveryDocument {
pub rel: String,
pub href: String,
}
impl Discovery {
pub async fn get(url: reqwest::Url) -> Result<Self, DiscoveryGetError> {
use DiscoveryGetError::*;
log::debug!("Getting nodeinfo discovery at: {url}");
log::trace!("Sending GET request to: {url}");
let response = reqwest::get(url)
.await
.map_err(Request)?;
log::trace!("Checking headers of the response...");
response
.headers()
.get("Content-Type")
.ok_or(ContentTypeMissing)?
.eq("application/json")
.then_some(())
.ok_or(ContentTypeInvalid)?;
log::trace!("Attempting to parse nodeinfo discovery as JSON...");
let data = response.json::<Self>()
.await
.map_err(Parse)?;
Ok(data)
}
const WELLKNOWN_DISCOVERY_PATH: &str = "/.well-known/nodeinfo";
pub async fn discover(base: &reqwest::Url) -> Result<Self, DiscoveryDiscoverError> {
use DiscoveryDiscoverError::*;
log::debug!("Discovering nodeinfo at base: {base}");
let mut url = base.clone();
let path = Self::WELLKNOWN_DISCOVERY_PATH;
log::trace!("Setting URL path to `{path}`...");
url.set_path(path);
log::trace!("Unsetting URL query...");
url.set_query(None);
log::trace!("Unsetting URL fragment...");
url.set_fragment(None);
log::trace!("Setting URL scheme to HTTPS...");
url.set_scheme("https")
.map_err(UrlManipulation)?;
log::trace!("Attempting to retrieve nodeinfo via HTTPS...");
let https = Self::get(url.clone())
.await;
let https = match https {
Ok(data) => {
log::trace!("HTTPS retrieval was successful, returning...");
return Ok(data)
}
Err(err) => {
log::warn!("HTTPS retrieval failed.");
err
}
};
log::trace!("Setting URL scheme to HTTP...");
url.set_scheme("http")
.map_err(UrlManipulation)?;
log::trace!("Attempting to retrieve nodeinfo via HTTP...");
let http = Self::get(url.clone())
.await;
let http = match http {
Ok(data) => {
log::trace!("HTTP retrieval was successful, returning...");
return Ok(data)
}
Err(err) => {
log::warn!("HTTP retrieval failed.");
err
}
};
Err(
DiscoveryDiscoverError::Fetch(
DiscoveryDiscoverAttemptsErrors {
https,
http,
}
)
)
}
}
pub enum DiscoveryGetError {
/// The HTTP request failed.
Request(reqwest::Error),
/// The `Content-Type` header of the response is missing.
ContentTypeMissing,
/// The `Content-Type` header of the response is invalid.
ContentTypeInvalid,
/// The JSON document failed to be parsed.
Parse(reqwest::Error),
}
pub enum DiscoveryDiscoverError {
/// Manipulation of the URL scheme of the given base failed.
///
/// See [reqwest::Url::set_scheme] for possible causes.
UrlManipulation(()),
/// All attempts of fetching the discovery metadata failed.
Fetch(DiscoveryDiscoverAttemptsErrors),
2024-11-09 08:41:08 +00:00
}
2024-11-09 10:01:26 +00:00
pub struct DiscoveryDiscoverAttemptsErrors {
/// The error occurred during the HTTPS request.
pub https: DiscoveryGetError,
2024-11-09 08:41:08 +00:00
2024-11-09 10:01:26 +00:00
/// The error occurred during the HTTP request.
pub http: DiscoveryGetError,
2024-11-09 08:41:08 +00:00
}