use crate::model::metadata::ProviderMetadata;
use std::fmt::Debug;
use std::future::Future;
use std::sync::Arc;
use std::time::SystemTime;
use url::Url;
use walker_common::utils::url::Urlify;
pub struct DiscoverConfig {
pub source: String,
pub since: Option<SystemTime>,
}
impl DiscoverConfig {
pub fn with_since(mut self, since: impl Into<Option<SystemTime>>) -> Self {
self.since = since.into();
self
}
}
impl From<&str> for DiscoverConfig {
fn from(value: &str) -> Self {
Self {
since: None,
source: value.to_string(),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DistributionContext {
Directory(Url),
Feed(Url),
}
impl DistributionContext {
pub fn url(&self) -> &Url {
match self {
Self::Directory(url) => url,
Self::Feed(url) => url,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DiscoveredAdvisory {
pub context: Arc<DistributionContext>,
pub url: Url,
pub modified: SystemTime,
}
pub trait AsDiscovered: Debug {
fn as_discovered(&self) -> &DiscoveredAdvisory;
}
impl AsDiscovered for DiscoveredAdvisory {
fn as_discovered(&self) -> &DiscoveredAdvisory {
self
}
}
impl Urlify for DiscoveredAdvisory {
fn url(&self) -> &Url {
&self.url
}
fn relative_base_and_url(&self) -> Option<(&Url, String)> {
self.context
.url()
.make_relative(&self.url)
.map(|relative| (self.context.url(), relative))
}
}
#[derive(Debug)]
pub struct DiscoveredContext<'c> {
pub metadata: &'c ProviderMetadata,
}
pub trait DiscoveredVisitor {
type Error: std::fmt::Display + Debug;
type Context;
fn visit_context(
&self,
context: &DiscoveredContext,
) -> impl Future<Output = Result<Self::Context, Self::Error>>;
fn visit_advisory(
&self,
context: &Self::Context,
advisory: DiscoveredAdvisory,
) -> impl Future<Output = Result<(), Self::Error>>;
}
impl<F, E, Fut> DiscoveredVisitor for F
where
F: Fn(DiscoveredAdvisory) -> Fut,
Fut: Future<Output = Result<(), E>>,
E: std::fmt::Display + Debug,
{
type Error = E;
type Context = ();
async fn visit_context(
&self,
_context: &DiscoveredContext<'_>,
) -> Result<Self::Context, Self::Error> {
Ok(())
}
async fn visit_advisory(
&self,
_ctx: &Self::Context,
advisory: DiscoveredAdvisory,
) -> Result<(), Self::Error> {
self(advisory).await
}
}