1use crate::model::metadata::ProviderMetadata;
4use std::fmt::Debug;
5use std::future::Future;
6use std::sync::Arc;
7use std::time::SystemTime;
8use url::Url;
9use walker_common::utils::url::Urlify;
10
11pub struct DiscoverConfig {
13 pub source: String,
18
19 pub since: Option<SystemTime>,
22}
23
24impl DiscoverConfig {
25 pub fn with_since(mut self, since: impl Into<Option<SystemTime>>) -> Self {
26 self.since = since.into();
27 self
28 }
29}
30
31impl From<&str> for DiscoverConfig {
32 fn from(value: &str) -> Self {
33 Self {
34 since: None,
35 source: value.to_string(),
36 }
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Eq)]
41pub enum DistributionContext {
42 Directory(Url),
43 Feed(Url),
44}
45
46impl DistributionContext {
47 pub fn url(&self) -> &Url {
49 match self {
50 Self::Directory(url) => url,
51 Self::Feed(url) => url,
52 }
53 }
54}
55
56#[derive(Clone, Debug, PartialEq, Eq)]
57pub struct DiscoveredAdvisory {
58 pub context: Arc<DistributionContext>,
60 pub url: Url,
62 pub modified: SystemTime,
64}
65
66pub trait AsDiscovered: Debug {
68 fn as_discovered(&self) -> &DiscoveredAdvisory;
69}
70
71impl AsDiscovered for DiscoveredAdvisory {
72 fn as_discovered(&self) -> &DiscoveredAdvisory {
73 self
74 }
75}
76
77impl Urlify for DiscoveredAdvisory {
78 fn url(&self) -> &Url {
79 &self.url
80 }
81
82 fn relative_base_and_url(&self) -> Option<(&Url, String)> {
83 self.context
84 .url()
85 .make_relative(&self.url)
86 .map(|relative| (self.context.url(), relative))
87 }
88}
89
90#[derive(Debug)]
91pub struct DiscoveredContext<'c> {
92 pub metadata: &'c ProviderMetadata,
93}
94
95pub trait DiscoveredVisitor {
97 type Error: std::fmt::Display + Debug;
98 type Context;
99
100 fn visit_context(
101 &self,
102 context: &DiscoveredContext,
103 ) -> impl Future<Output = Result<Self::Context, Self::Error>>;
104
105 fn visit_advisory(
106 &self,
107 context: &Self::Context,
108 advisory: DiscoveredAdvisory,
109 ) -> impl Future<Output = Result<(), Self::Error>>;
110}
111
112impl<F, E, Fut> DiscoveredVisitor for F
113where
114 F: Fn(DiscoveredAdvisory) -> Fut,
115 Fut: Future<Output = Result<(), E>>,
116 E: std::fmt::Display + Debug,
117{
118 type Error = E;
119 type Context = ();
120
121 async fn visit_context(
122 &self,
123 _context: &DiscoveredContext<'_>,
124 ) -> Result<Self::Context, Self::Error> {
125 Ok(())
126 }
127
128 async fn visit_advisory(
129 &self,
130 _ctx: &Self::Context,
131 advisory: DiscoveredAdvisory,
132 ) -> Result<(), Self::Error> {
133 self(advisory).await
134 }
135}