use {
crate::dependency::UpdateUrl,
log::{debug, error},
reqwest::{header::ACCEPT, Client, StatusCode},
serde::{Deserialize, Serialize},
std::collections::BTreeMap,
thiserror::Error,
};
#[derive(Error, Debug)]
pub enum RegistryError {
#[error("Failed to fetch package '{url}': {source}")]
FetchError {
url: String,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("HTTP error for package '{url}': {status}")]
HttpError { url: String, status: StatusCode },
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct PackageMeta {
pub name: String,
pub time: BTreeMap<String, String>,
}
#[async_trait::async_trait]
pub trait RegistryClient: std::fmt::Debug + Send + Sync {
async fn fetch(&self, update_url: &UpdateUrl) -> Result<PackageMeta, RegistryError>;
}
#[derive(Debug)]
pub struct LiveRegistryClient {
pub client: Client,
}
#[async_trait::async_trait]
impl RegistryClient for LiveRegistryClient {
async fn fetch(&self, update_url: &UpdateUrl) -> Result<PackageMeta, RegistryError> {
let req = self.client.get(&update_url.url).header(ACCEPT, "application/json");
debug!("GET {update_url:?}");
match req.send().await {
Ok(res) => match res.status() {
StatusCode::OK => match res.json::<PackageMeta>().await {
Ok(package_meta) => Ok(package_meta),
Err(err) => Err(RegistryError::FetchError {
url: update_url.url.to_string(),
source: Box::new(err),
}),
},
status => Err(RegistryError::HttpError {
url: update_url.url.to_string(),
status,
}),
},
Err(err) => Err(RegistryError::FetchError {
url: update_url.url.to_string(),
source: Box::new(err),
}),
}
}
}
impl LiveRegistryClient {
pub fn new() -> Self {
LiveRegistryClient { client: Client::new() }
}
}