csaf_walker/rolie/
mod.rs

1mod roliefeed;
2
3pub use roliefeed::*;
4
5use crate::source::HttpSourceError;
6use time::OffsetDateTime;
7use url::{ParseError, Url};
8use walker_common::fetcher::Json;
9use walker_common::{fetcher, fetcher::Fetcher};
10
11#[derive(Debug, thiserror::Error)]
12pub enum Error {
13    #[error("Fetch error: {0}")]
14    Fetcher(#[from] fetcher::Error),
15    #[error("URL error: {0}")]
16    Url(#[from] ParseError),
17    #[error("JSON parse error: {0}")]
18    Json(#[from] serde_json::Error),
19}
20
21impl From<Error> for HttpSourceError {
22    fn from(value: Error) -> Self {
23        match value {
24            Error::Fetcher(err) => Self::Fetcher(err),
25            Error::Url(err) => Self::Url(err),
26            Error::Json(err) => Self::Json(err),
27        }
28    }
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
32pub struct SourceFile {
33    /// The relative file name
34    pub file: String,
35    /// The timestamp of the last change
36    #[serde(with = "time::serde::iso8601")]
37    pub timestamp: OffsetDateTime,
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize)]
41pub struct RolieSource {
42    #[serde(default, skip_serializing_if = "Vec::is_empty")]
43    pub files: Vec<SourceFile>,
44}
45
46impl RolieSource {
47    pub async fn retrieve(fetcher: &Fetcher, base_url: Url) -> Result<Self, Error> {
48        let mut files = vec![];
49        let Json(result) = fetcher.fetch::<Json<RolieFeed>>(base_url).await?;
50        for url in result.feed.entry {
51            for link in url.link {
52                files.push(SourceFile {
53                    file: link.href,
54                    timestamp: url.updated,
55                })
56            }
57        }
58
59        log::debug!("found {:?} files", files.len());
60
61        Ok(Self { files })
62    }
63}