speakeasy_rust_sdk/
controller.rs

1//! Control [masking](Controller::set_masking()), [path_hint](Controller::set_path_hint()) and [customer_id](Controller::set_customer_id()) on a per request basis
2
3// 1MB
4pub(crate) const MAX_SIZE: usize = 1024 * 1024;
5
6use crate::speakeasy_protos::ingest::IngestRequest;
7
8use crate::{
9    async_runtime,
10    generic_http::{GenericRequest, GenericResponse},
11    har_builder::HarBuilder,
12    path_hint,
13    transport::Transport,
14    Error, GenericSpeakeasySdk, Masking, RequestConfig,
15};
16
17// Control [masking](Controller::set_masking()), [path_hint](Controller::set_path_hint()) and [customer_id](Controller::set_customer_id()) on a per request basis
18#[derive(Debug, Clone)]
19pub struct Controller<T: Transport> {
20    transport: T,
21    config: RequestConfig,
22
23    request: Option<GenericRequest>,
24
25    masking: Masking,
26    path_hint: Option<String>,
27    customer_id: Option<String>,
28
29    pub(crate) max_capture_size: usize,
30}
31
32// Public
33impl<T> Controller<T>
34where
35    T: Transport + Send + Clone + 'static,
36{
37    #[doc(hidden)]
38    pub fn new(sdk: &GenericSpeakeasySdk<T>) -> Self {
39        Self {
40            transport: sdk.transport.clone(),
41            config: sdk.config.clone(),
42            request: None,
43            masking: sdk.masking.clone(),
44            path_hint: None,
45            customer_id: None,
46            max_capture_size: MAX_SIZE,
47        }
48    }
49
50    /// Set the path_hint request
51    pub fn set_path_hint(&mut self, path_hint: &str) {
52        let path_hint = path_hint::normalize(path_hint);
53        self.path_hint = Some(path_hint)
54    }
55
56    /// Set new masking for the request, see [Masking](crate::masking::Masking) for more
57    pub fn set_masking(&mut self, masking: Masking) {
58        self.masking = masking
59    }
60
61    /// Set new customer_id for the request
62    pub fn set_customer_id(&mut self, customer_id: String) {
63        self.customer_id = Some(customer_id)
64    }
65
66    /// Set new max_capture_size for the request, if the request or response bodies are above this, it will be dropped
67    pub fn set_max_capture_size(&mut self, max_capture_size: usize) {
68        self.max_capture_size = max_capture_size
69    }
70}
71
72// Crate use only
73impl<T> Controller<T>
74where
75    T: Transport + Send + Clone + 'static,
76{
77    pub(crate) fn set_request(&mut self, request: GenericRequest) {
78        self.request = Some(request)
79    }
80
81    pub(crate) fn build_and_send_har(self, response: GenericResponse) -> Result<(), Error> {
82        let request = self.request.clone().ok_or(Error::RequestNotSaved)?;
83
84        // look for path hint for request, if not look in the request
85        let path_hint = self
86            .path_hint
87            .as_ref()
88            .or(request.path_hint.as_ref())
89            .map(ToString::to_string)
90            .unwrap_or_else(|| "".to_string());
91
92        let masking = self.masking.clone();
93
94        let customer_id = self.customer_id.clone().unwrap_or_default();
95
96        let max_capture_size = self.max_capture_size;
97
98        let config = self.config.clone();
99        let transport = self.transport;
100
101        async_runtime::spawn_task(async move {
102            let har = HarBuilder::new(request, response, max_capture_size).build(&masking);
103            let har_json = serde_json::to_string(&har).expect("har will serialize to json");
104
105            let masking_metadata = if masking.is_empty() {
106                None
107            } else {
108                Some(masking.into())
109            };
110
111            let ingest = IngestRequest {
112                har: har_json,
113                path_hint,
114                api_id: config.api_id,
115                version_id: config.version_id,
116                customer_id,
117                masking_metadata,
118            };
119
120            transport.send(ingest)
121        });
122
123        Ok(())
124    }
125}