From aca801cede510b8f25079afae2a6437f346b842d Mon Sep 17 00:00:00 2001 From: Giovanni Bezicheri Date: Wed, 8 Apr 2026 14:52:26 +0200 Subject: [PATCH] feat: add custom HttpRequester support for IEEE 2030.5 Client --- sep2_client/src/client.rs | 22 +++++++++++++++++++++- sep2_client/src/tls.rs | 31 ++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/sep2_client/src/client.rs b/sep2_client/src/client.rs index 33a9a95..b86156a 100644 --- a/sep2_client/src/client.rs +++ b/sep2_client/src/client.rs @@ -26,7 +26,7 @@ use tokio::sync::Mutex; use crate::{ time::{current_time_with_offset, SEPTime}, - tls::{create_client, create_client_tls_cfg, create_http_client, ClientInner}, + tls::{create_client, create_client_tls_cfg, create_http_client, ClientInner, HttpRequester}, }; #[cfg(feature = "event")] @@ -294,6 +294,26 @@ impl Client { Ok(out) } + /// Construct an IEEE 2030.5 Client instance that uses a custom [`HttpRequester`] implementation. + /// + /// This is useful for testing or mocking HTTP interactions. + pub fn new_custom( + server_addr: &str, + requester: impl HttpRequester + 'static, + tickrate: Option, + ) -> Self { + let out = Client { + addr: server_addr.to_owned().into(), + inner: ClientInner::Custom(Arc::new(requester)), + polls: Arc::new(Mutex::new(BinaryHeap::new())), + }; + tokio::spawn( + out.clone() + .poll_task(tickrate.unwrap_or(Self::DEFAULT_TICKRATE)), + ); + out + } + async fn poll_task(self, tickrate: Duration) { loop { tokio::time::sleep(tickrate).await; diff --git a/sep2_client/src/tls.rs b/sep2_client/src/tls.rs index 839f084..71a0cef 100644 --- a/sep2_client/src/tls.rs +++ b/sep2_client/src/tls.rs @@ -3,11 +3,14 @@ //! Provides an interface for parsing & verifying 2030.5 certificates, as per IEEE 2030.5 section 6.11 //! +use std::future::Future; use std::path::Path; +use std::pin::Pin; +use std::sync::Arc; use std::time::Duration; use anyhow::{bail, Result}; -use hyper::client::{HttpConnector, ResponseFuture}; +use hyper::client::HttpConnector; use hyper::{Body, Client, Request}; use hyper_openssl::HttpsConnector; use openssl::ssl::{SslConnector, SslConnectorBuilder, SslFiletype, SslMethod, SslVerifyMode}; @@ -21,17 +24,35 @@ pub(crate) type HTTPSClient = Client; pub(crate) type HTTPClient = Client; pub(crate) type TlsClientConfig = SslConnectorBuilder; -#[derive(Clone, Debug)] +/// A trait for custom HTTP request handling, useful for mocking. +pub trait HttpRequester: Send + Sync { + fn request( + &self, + req: Request, + ) -> Pin< + Box< + dyn Future, hyper::Error>> + Send, + >, + >; +} + +#[derive(Clone)] pub(crate) enum ClientInner { Https(HTTPSClient), Http(HTTPClient), + Custom(Arc), } impl ClientInner { - pub(crate) fn request(&self, req: Request) -> ResponseFuture { + pub(crate) fn request( + &self, + req: Request, + ) -> Pin, hyper::Error>> + Send>> + { match self { - ClientInner::Https(c) => c.request(req), - ClientInner::Http(c) => c.request(req), + ClientInner::Https(c) => Box::pin(c.request(req)), + ClientInner::Http(c) => Box::pin(c.request(req)), + ClientInner::Custom(c) => c.request(req), } } }