walker_extras/visitors/send/
csaf.rs

1use super::*;
2use crate::csaf::{
3    retrieve::{RetrievalContext, RetrievedAdvisory, RetrievedVisitor},
4    validation::{ValidatedAdvisory, ValidatedVisitor, ValidationContext, ValidationError},
5};
6use csaf_walker::{discover::DiscoveredAdvisory, source::Source};
7use walker_common::retrieve::RetrievalError;
8
9#[derive(Debug, thiserror::Error)]
10pub enum SendRetrievedAdvisoryError<S: Source> {
11    #[error(transparent)]
12    Store(#[from] SendError),
13    #[error(transparent)]
14    Retrieval(#[from] RetrievalError<DiscoveredAdvisory, S>),
15}
16
17impl<S: Source> RetrievedVisitor<S> for SendVisitor {
18    type Error = SendRetrievedAdvisoryError<S>;
19    type Context = ();
20
21    async fn visit_context(&self, _: &RetrievalContext<'_>) -> Result<Self::Context, Self::Error> {
22        Ok(())
23    }
24
25    async fn visit_advisory(
26        &self,
27        _context: &Self::Context,
28        result: Result<RetrievedAdvisory, RetrievalError<DiscoveredAdvisory, S>>,
29    ) -> Result<(), Self::Error> {
30        self.send_retrieved_advisory(result?).await?;
31        Ok(())
32    }
33}
34
35#[allow(clippy::large_enum_variant)]
36#[derive(Debug, thiserror::Error)]
37pub enum SendValidatedAdvisoryError<S: Source> {
38    #[error(transparent)]
39    Store(#[from] SendError),
40    #[error(transparent)]
41    Validation(#[from] ValidationError<S>),
42}
43
44impl<S: Source> ValidatedVisitor<S> for SendVisitor {
45    type Error = SendValidatedAdvisoryError<S>;
46    type Context = ();
47
48    async fn visit_context(&self, _: &ValidationContext<'_>) -> Result<Self::Context, Self::Error> {
49        Ok(())
50    }
51
52    async fn visit_advisory(
53        &self,
54        _context: &Self::Context,
55        result: Result<ValidatedAdvisory, ValidationError<S>>,
56    ) -> Result<(), Self::Error> {
57        self.send_retrieved_advisory(result?.retrieved).await?;
58        Ok(())
59    }
60}
61
62impl SendVisitor {
63    async fn send_retrieved_advisory(&self, advisory: RetrievedAdvisory) -> Result<(), SendError> {
64        log::debug!(
65            "Sending: {} (modified: {:?})",
66            advisory.url,
67            advisory.metadata.last_modification
68        );
69
70        let RetrievedAdvisory {
71            data,
72            discovered: DiscoveredAdvisory { url, .. },
73            ..
74        } = advisory;
75
76        self.send_json(url.as_str(), data).await
77    }
78
79    pub async fn send_json(&self, name: &str, data: Bytes) -> Result<(), SendError> {
80        self.send(name, data, |request| {
81            request.header(header::CONTENT_TYPE, "application/json")
82        })
83        .await
84    }
85}