csaf_walker/source/
descriptor.rs1use crate::{
2 discover::DiscoverConfig,
3 metadata::MetadataRetriever,
4 source::{DispatchSource, FileOptions, FileSource, HttpOptions, HttpSource},
5};
6use anyhow::bail;
7use fluent_uri::UriRef;
8use std::path::PathBuf;
9use std::str::FromStr;
10use url::Url;
11use walker_common::fetcher::{Fetcher, FetcherOptions};
12
13#[derive(Clone, Debug)]
15pub enum SourceDescriptor {
16 File(PathBuf),
18 Url(Url),
20 Lookup(String),
22}
23
24impl FromStr for SourceDescriptor {
25 type Err = anyhow::Error;
26
27 fn from_str(source: &str) -> Result<Self, Self::Err> {
28 match UriRef::parse(source) {
29 Ok(uri) => match uri.scheme().map(|s| s.as_str()) {
30 Some("https") => Ok(SourceDescriptor::Url(Url::parse(source)?)),
31 Some("file") => Ok(SourceDescriptor::File(PathBuf::from(uri.path().as_str()))),
32 Some(other) => bail!("URLs with scheme '{other}' are not supported"),
33 None => Ok(SourceDescriptor::Lookup(source.to_string())),
34 },
35 Err(err) => {
36 log::debug!("Failed to handle source as URL: {err}");
37 Ok(SourceDescriptor::Lookup(source.to_string()))
38 }
39 }
40 }
41}
42
43impl SourceDescriptor {
44 pub fn parse(source: impl AsRef<str>) -> anyhow::Result<Self> {
46 Self::from_str(source.as_ref())
47 }
48
49 pub async fn into_source(
51 self,
52 discover: DiscoverConfig,
53 fetcher: FetcherOptions,
54 ) -> anyhow::Result<DispatchSource> {
55 match self {
56 Self::File(path) => {
57 Ok(FileSource::new(path, FileOptions::new().since(discover.since))?.into())
58 }
59 Self::Url(url) => Ok(HttpSource::new(
60 url,
61 Fetcher::new(fetcher).await?,
62 HttpOptions::new().since(discover.since),
63 )
64 .into()),
65 Self::Lookup(source) => {
66 let fetcher = Fetcher::new(fetcher).await?;
67 Ok(HttpSource::new(
68 MetadataRetriever::new(source),
69 fetcher,
70 HttpOptions::new().since(discover.since),
71 )
72 .into())
73 }
74 }
75 }
76}