Skip to main content

brooks_lib/dcdn/processors/
source.rs

1// brooks, Copyright 2026, Will Hawkins
2//
3// This file is part of brooks.
4
5// This file is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18//! The Source Generic Metadata Processing Implementation
19
20use reqwest::dns::{Addrs, Resolve};
21
22use crate::{
23    cdni::original::spec::TypedSourceMetadata,
24    dcdn::{
25        imdi,
26        interpret::{Error, MetadataInformationResultElements, ProcessedRequestResponse, Stages},
27        processors::SimpleProcessorsInterpreterContext,
28    },
29    processing::interpret::{self, InterpretationResult},
30    prr::{self, Prr},
31    verifying::original::verify::SourceVerificationKey,
32};
33
34use std::fmt::Debug;
35use std::net::SocketAddr;
36
37#[derive(Debug, Clone)]
38pub struct SourceMetadataResolver {
39    pub addr: SocketAddr,
40}
41
42impl Resolve for SourceMetadataResolver {
43    fn resolve(&self, _name: reqwest::dns::Name) -> reqwest::dns::Resolving {
44        let addrs: Addrs = Box::new(vec![self.addr].into_iter());
45        Box::pin(std::future::ready(Ok(addrs)))
46    }
47}
48
49impl
50    interpret::Interpreter<
51        SimpleProcessorsInterpreterContext<'_>,
52        (imdi::ResultValue, MetadataInformationResultElements),
53        Stages,
54        Error,
55    > for TypedSourceMetadata<SourceVerificationKey>
56{
57    fn interpret<'a>(
58        &self,
59        input: SimpleProcessorsInterpreterContext<'a>,
60    ) -> InterpretationResult<
61        SimpleProcessorsInterpreterContext<'a>,
62        (imdi::ResultValue, MetadataInformationResultElements),
63        Error,
64    > {
65        let req = &*input.req;
66
67        let req: reqwest::Request = req
68            .try_into()
69            .map_err(|e: prr::Error| Error::InvalidInput(e.into()))?;
70
71        let req_method = req.method().clone();
72        let req_url = req.url().clone();
73
74        let mut clientb = reqwest::Client::builder();
75
76        let resolver = SourceMetadataResolver {
77            addr: *self
78                .value
79                .aug
80                .sources
81                .first()
82                .ok_or(Error::AssertionFailure(
83                    "Missing sources".to_string().into(),
84                ))?
85                .0
86                .first()
87                .ok_or(Error::AssertionFailure(
88                    "Missing endpoints".to_string().into(),
89                ))?,
90        };
91
92        clientb = clientb.dns_resolver(resolver);
93
94        let client = clientb.build().map_err(|e| Error::RuntimeError(e.into()))?;
95
96        let result: Result<ProcessedRequestResponse, Error> = input.runtime.block_on(async {
97            let r = client
98                .execute(req)
99                .await
100                .map_err(|e| Error::RuntimeError(e.into()))?;
101
102            let mut result = ProcessedRequestResponse::new_response(&req_url, &req_method);
103
104            result.oheaders = r.headers().clone();
105
106            result
107                .set_status(&r.status().as_u16())
108                .map_err(|_| Error::RuntimeError(prr::Error::BadStatus.into()))?;
109
110            let b = r.bytes().await.map_err(|e| Error::RuntimeError(e.into()))?;
111            result.obody = b.to_vec();
112            Ok(result)
113        });
114
115        Ok((
116            input.with_res(Box::new(result?)),
117            (None, MetadataInformationResultElements::default()),
118        ))
119    }
120
121    fn at(&self, stage: Stages) -> bool {
122        stage == Stages::Source
123    }
124}