1use crate::cache::{Cache, CachedResponse, ResponseCache};
7use crate::failure_analysis::FailureContextCollector;
8use crate::performance::PerformanceMonitor;
9use crate::templating::TemplateEngine;
10use crate::workspace::core::{EntityId, Folder, MockRequest, MockResponse, Workspace};
11use crate::{
12 routing::{HttpMethod, Route, RouteRegistry},
13 Error, Result,
14};
15use chrono::{DateTime, Utc};
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18use std::sync::Arc;
19use std::time::Duration;
20
21#[derive(Debug, Clone)]
23pub struct RequestExecutionResult {
24 pub request_id: EntityId,
26 pub response: Option<MockResponse>,
28 pub duration_ms: u64,
30 pub success: bool,
32 pub error: Option<String>,
34 pub failure_context: Option<crate::failure_analysis::FailureContext>,
36}
37
38#[derive(Debug, Clone)]
40pub struct RequestMatchCriteria {
41 pub method: HttpMethod,
43 pub path: String,
45 pub query_params: HashMap<String, String>,
47 pub headers: HashMap<String, String>,
49 pub body: Option<String>,
51}
52
53#[derive(Debug, Clone)]
55pub struct RequestProcessor {
56 _template_engine: TemplateEngine,
58 environment_manager: Option<crate::workspace::environment::EnvironmentManager>,
60 performance_monitor: Arc<PerformanceMonitor>,
62 response_cache: Arc<ResponseCache>,
64 validation_cache: Arc<Cache<String, RequestValidationResult>>,
66 optimizations_enabled: bool,
68 failure_collector: Option<Arc<FailureContextCollector>>,
70}
71
72#[derive(Debug, Clone)]
74pub struct RequestValidationResult {
75 pub is_valid: bool,
77 pub errors: Vec<String>,
79 pub warnings: Vec<String>,
81}
82
83#[derive(Debug, Clone)]
85pub struct RequestExecutionContext {
86 pub workspace_id: EntityId,
88 pub environment_variables: HashMap<String, String>,
90 pub global_headers: HashMap<String, String>,
92 pub timeout_seconds: u64,
94 pub ssl_verify: bool,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct RequestMetrics {
101 pub total_requests: u64,
103 pub successful_requests: u64,
105 pub failed_requests: u64,
107 pub average_response_time_ms: f64,
109 pub popular_requests: Vec<(EntityId, u64)>,
111 pub last_execution: Option<DateTime<Utc>>,
113}
114
115impl RequestProcessor {
116 pub fn new() -> Self {
118 Self {
119 _template_engine: TemplateEngine::new(),
120 environment_manager: None,
121 performance_monitor: Arc::new(PerformanceMonitor::new()),
122 response_cache: Arc::new(ResponseCache::new(1000, Duration::from_secs(300))), validation_cache: Arc::new(Cache::with_ttl(500, Duration::from_secs(60))), optimizations_enabled: true,
125 failure_collector: Some(Arc::new(FailureContextCollector::new())),
126 }
127 }
128
129 pub fn with_environment_manager(
131 environment_manager: crate::workspace::environment::EnvironmentManager,
132 ) -> Self {
133 Self {
134 _template_engine: TemplateEngine::new(),
135 environment_manager: Some(environment_manager),
136 performance_monitor: Arc::new(PerformanceMonitor::new()),
137 response_cache: Arc::new(ResponseCache::new(1000, Duration::from_secs(300))),
138 validation_cache: Arc::new(Cache::with_ttl(500, Duration::from_secs(60))),
139 optimizations_enabled: true,
140 failure_collector: Some(Arc::new(FailureContextCollector::new())),
141 }
142 }
143
144 pub fn with_performance_config(
146 environment_manager: Option<crate::workspace::environment::EnvironmentManager>,
147 cache_size: usize,
148 cache_ttl: Duration,
149 enable_optimizations: bool,
150 ) -> Self {
151 Self {
152 _template_engine: TemplateEngine::new(),
153 environment_manager,
154 performance_monitor: Arc::new(PerformanceMonitor::new()),
155 response_cache: Arc::new(ResponseCache::new(cache_size, cache_ttl)),
156 validation_cache: Arc::new(Cache::with_ttl(cache_size / 2, Duration::from_secs(60))),
157 optimizations_enabled: enable_optimizations,
158 failure_collector: Some(Arc::new(FailureContextCollector::new())),
159 }
160 }
161
162 pub fn performance_monitor(&self) -> Arc<PerformanceMonitor> {
164 self.performance_monitor.clone()
165 }
166
167 pub fn set_optimizations_enabled(&mut self, enabled: bool) {
169 self.optimizations_enabled = enabled;
170 }
171
172 pub fn find_matching_request(
174 &self,
175 workspace: &Workspace,
176 criteria: &RequestMatchCriteria,
177 ) -> Option<EntityId> {
178 for request in &workspace.requests {
180 if self.request_matches(request, criteria) {
181 return Some(request.id.clone());
182 }
183 }
184
185 if let Some(request_id) =
187 self.find_matching_request_in_folders(&workspace.folders, criteria)
188 {
189 return Some(request_id);
190 }
191
192 None
193 }
194
195 fn request_matches(&self, request: &MockRequest, criteria: &RequestMatchCriteria) -> bool {
197 if request.method != criteria.method {
199 return false;
200 }
201
202 if !self.url_matches_pattern(&request.url, &criteria.path) {
204 return false;
205 }
206
207 for (key, expected_value) in &criteria.query_params {
209 if let Some(actual_value) = request.query_params.get(key) {
210 if actual_value != expected_value {
211 return false;
212 }
213 } else {
214 return false;
215 }
216 }
217
218 for (key, expected_value) in &criteria.headers {
220 if let Some(actual_value) = request.headers.get(key) {
221 if actual_value != expected_value {
222 return false;
223 }
224 } else {
225 return false;
226 }
227 }
228
229 true
230 }
231
232 pub fn url_matches_pattern(&self, pattern: &str, url: &str) -> bool {
234 if pattern == url {
236 return true;
237 }
238
239 if pattern == "*" {
241 return true;
242 }
243
244 if pattern.contains('*') {
246 return self.matches_path_pattern(pattern, url);
247 }
248
249 false
250 }
251
252 fn matches_path_pattern(&self, pattern: &str, path: &str) -> bool {
254 let pattern_parts: Vec<&str> = pattern.split('/').filter(|s| !s.is_empty()).collect();
255 let path_parts: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
256
257 self.match_segments(&pattern_parts, &path_parts, 0, 0)
258 }
259
260 #[allow(clippy::only_used_in_recursion)]
262 fn match_segments(
263 &self,
264 pattern_parts: &[&str],
265 path_parts: &[&str],
266 pattern_idx: usize,
267 path_idx: usize,
268 ) -> bool {
269 if pattern_idx == pattern_parts.len() && path_idx == path_parts.len() {
271 return true;
272 }
273
274 if pattern_idx == pattern_parts.len() {
276 return false;
277 }
278
279 let current_pattern = pattern_parts[pattern_idx];
280
281 match current_pattern {
282 "*" => {
283 if path_idx < path_parts.len() {
285 if self.match_segments(pattern_parts, path_parts, pattern_idx + 1, path_idx + 1)
287 {
288 return true;
289 }
290 }
291 false
292 }
293 "**" => {
294 if self.match_segments(pattern_parts, path_parts, pattern_idx + 1, path_idx) {
297 return true;
298 }
299 if path_idx < path_parts.len()
301 && self.match_segments(pattern_parts, path_parts, pattern_idx, path_idx + 1)
302 {
303 return true;
304 }
305 false
306 }
307 _ => {
308 if path_idx < path_parts.len() && current_pattern == path_parts[path_idx] {
310 return self.match_segments(
311 pattern_parts,
312 path_parts,
313 pattern_idx + 1,
314 path_idx + 1,
315 );
316 }
317 false
318 }
319 }
320 }
321
322 fn find_matching_request_in_folders(
324 &self,
325 folders: &[Folder],
326 criteria: &RequestMatchCriteria,
327 ) -> Option<EntityId> {
328 for folder in folders {
329 for request in &folder.requests {
331 if self.request_matches(request, criteria) {
332 return Some(request.id.clone());
333 }
334 }
335
336 if let Some(request_id) =
338 self.find_matching_request_in_folders(&folder.folders, criteria)
339 {
340 return Some(request_id);
341 }
342 }
343
344 None
345 }
346
347 pub async fn execute_request(
349 &self,
350 workspace: &mut Workspace,
351 request_id: &EntityId,
352 context: &RequestExecutionContext,
353 ) -> Result<RequestExecutionResult> {
354 let _perf_guard = if self.optimizations_enabled {
356 self.performance_monitor.start_tracking_named("execute_request")
357 } else {
358 None
359 };
360
361 let cache_key = if self.optimizations_enabled {
363 self.generate_response_cache_key(request_id, context)
364 } else {
365 String::new()
366 };
367
368 if self.optimizations_enabled && !cache_key.is_empty() {
370 if let Some(cached_response) = self.response_cache.get_response(&cache_key).await {
371 self.performance_monitor.record_cache_hit();
372 return Ok(RequestExecutionResult {
373 request_id: request_id.clone(),
374 response: Some(self.convert_cached_response_to_mock_response(cached_response)),
375 duration_ms: 1, success: true,
377 error: None,
378 failure_context: None,
379 });
380 } else {
381 self.performance_monitor.record_cache_miss();
382 }
383 }
384
385 let request = match self.find_request_in_workspace(workspace, request_id) {
387 Some(req) => req,
388 None => {
389 if self.optimizations_enabled {
390 self.performance_monitor.record_error();
391 }
392 let error_msg = format!("Request with ID {} not found", request_id);
393
394 if let Some(ref collector) = self.failure_collector {
398 let _failure_context = collector
399 .collect_context(
400 "UNKNOWN",
401 &request_id.to_string(),
402 None,
403 Some(error_msg.clone()),
404 )
405 .ok();
406 }
407
408 return Err(Error::generic(error_msg));
409 }
410 };
411
412 let start_time = std::time::Instant::now();
413 let method = "GET"; let path = request_id.to_string(); let validation = match self.validate_request_cached(request, context).await {
418 Ok(v) => v,
419 Err(e) => {
420 if self.optimizations_enabled {
421 self.performance_monitor.record_error();
422 }
423 let error_msg = format!("Request validation error: {}", e);
424
425 if let Some(ref collector) = self.failure_collector {
429 let _failure_context = collector
430 .collect_context(method, &path, None, Some(error_msg.clone()))
431 .ok();
432 }
433
434 return Err(e);
435 }
436 };
437
438 if !validation.is_valid {
439 if self.optimizations_enabled {
440 self.performance_monitor.record_error();
441 }
442 let error_msg = format!("Request validation failed: {:?}", validation.errors);
443
444 if let Some(ref collector) = self.failure_collector {
448 let _failure_context =
449 collector.collect_context(method, &path, None, Some(error_msg.clone())).ok();
450 }
451
452 return Err(Error::Validation { message: error_msg });
453 }
454
455 let response = match request.active_response() {
457 Some(resp) => resp,
458 None => {
459 if self.optimizations_enabled {
460 self.performance_monitor.record_error();
461 }
462 let error_msg = "No active response found for request".to_string();
463
464 if let Some(ref collector) = self.failure_collector {
468 let _failure_context = collector
469 .collect_context(method, &path, None, Some(error_msg.clone()))
470 .ok();
471 }
472
473 return Err(Error::generic(error_msg));
474 }
475 };
476
477 let processed_response = match self.process_response(response, context).await {
479 Ok(resp) => resp,
480 Err(e) => {
481 if self.optimizations_enabled {
482 self.performance_monitor.record_error();
483 }
484 let error_msg = format!("Failed to process response: {}", e);
485
486 if let Some(ref collector) = self.failure_collector {
490 let _failure_context = collector
491 .collect_context(method, &path, None, Some(error_msg.clone()))
492 .ok();
493 }
494
495 return Err(e);
496 }
497 };
498
499 let duration_ms = start_time.elapsed().as_millis() as u64;
500
501 if self.optimizations_enabled && !cache_key.is_empty() {
503 let cached_response =
504 self.convert_mock_response_to_cached_response(&processed_response);
505 self.response_cache.cache_response(cache_key, cached_response).await;
506 }
507
508 if let Some(request_mut) = self.find_request_in_workspace_mut(workspace, request_id) {
510 if let Some(response_mut) = request_mut.active_response_mut() {
511 response_mut.record_usage(request_id.clone(), duration_ms);
512 }
513 }
514
515 Ok(RequestExecutionResult {
516 request_id: request_id.clone(),
517 response: Some(processed_response),
518 duration_ms,
519 success: true,
520 error: None,
521 failure_context: None,
522 })
523 }
524
525 fn find_request_in_workspace_mut<'a>(
527 &self,
528 workspace: &'a mut Workspace,
529 request_id: &EntityId,
530 ) -> Option<&'a mut MockRequest> {
531 for request in &mut workspace.requests {
533 if &request.id == request_id {
534 return Some(request);
535 }
536 }
537
538 self.find_request_in_folders_mut(&mut workspace.folders, request_id)
540 }
541
542 #[allow(clippy::only_used_in_recursion)]
544 fn find_request_in_folders_mut<'a>(
545 &self,
546 folders: &'a mut [Folder],
547 request_id: &EntityId,
548 ) -> Option<&'a mut MockRequest> {
549 for folder in folders {
550 for request in &mut folder.requests {
552 if &request.id == request_id {
553 return Some(request);
554 }
555 }
556
557 if let Some(request) = self.find_request_in_folders_mut(&mut folder.folders, request_id)
559 {
560 return Some(request);
561 }
562 }
563
564 None
565 }
566
567 fn find_request_in_workspace<'a>(
569 &self,
570 workspace: &'a Workspace,
571 request_id: &EntityId,
572 ) -> Option<&'a MockRequest> {
573 workspace
575 .requests
576 .iter()
577 .find(|r| &r.id == request_id)
578 .or_else(|| self.find_request_in_folders(&workspace.folders, request_id))
579 }
580
581 #[allow(clippy::only_used_in_recursion)]
583 fn find_request_in_folders<'a>(
584 &self,
585 folders: &'a [Folder],
586 request_id: &EntityId,
587 ) -> Option<&'a MockRequest> {
588 for folder in folders {
589 if let Some(request) = folder.requests.iter().find(|r| &r.id == request_id) {
591 return Some(request);
592 }
593
594 if let Some(request) = self.find_request_in_folders(&folder.folders, request_id) {
596 return Some(request);
597 }
598 }
599
600 None
601 }
602
603 pub fn validate_request(
605 &self,
606 request: &MockRequest,
607 _context: &RequestExecutionContext,
608 ) -> RequestValidationResult {
609 let mut errors = Vec::new();
610 let mut warnings = Vec::new();
611
612 if !request.enabled {
614 errors.push("Request is disabled".to_string());
615 }
616
617 if request.url.is_empty() {
619 errors.push("Request URL cannot be empty".to_string());
620 }
621
622 match request.method {
624 HttpMethod::GET
625 | HttpMethod::POST
626 | HttpMethod::PUT
627 | HttpMethod::DELETE
628 | HttpMethod::PATCH
629 | HttpMethod::HEAD
630 | HttpMethod::OPTIONS => {
631 }
633 }
634
635 if request.active_response().is_none() {
637 warnings.push("No active response configured".to_string());
638 }
639
640 for response in &request.responses {
642 if response.status_code < 100 || response.status_code > 599 {
643 errors.push(format!("Invalid status code: {}", response.status_code));
644 }
645
646 if response.body.is_empty() {
647 warnings.push(format!("Response '{}' has empty body", response.name));
648 }
649 }
650
651 RequestValidationResult {
652 is_valid: errors.is_empty(),
653 errors,
654 warnings,
655 }
656 }
657
658 async fn process_response(
660 &self,
661 response: &MockResponse,
662 context: &RequestExecutionContext,
663 ) -> Result<MockResponse> {
664 if response.delay > 0 {
666 tokio::time::sleep(std::time::Duration::from_millis(response.delay)).await;
667 }
668
669 let mut processed_response = response.clone();
671
672 if let Some(env_manager) = &self.environment_manager {
674 if let Some(_env_vars) = self.get_environment_variables(context) {
675 processed_response.body = env_manager.substitute_variables(&response.body).value;
676 }
677 }
678
679 Ok(processed_response)
680 }
681
682 fn get_environment_variables(
684 &self,
685 context: &RequestExecutionContext,
686 ) -> Option<HashMap<String, String>> {
687 if let Some(env_manager) = &self.environment_manager {
688 if let Some(active_env) = env_manager.get_active_environment() {
689 return Some(active_env.variables.clone());
690 }
691 }
692
693 Some(context.environment_variables.clone())
694 }
695
696 pub fn get_request_metrics(&self, workspace: &Workspace) -> RequestMetrics {
698 let mut total_requests = 0u64;
699 let mut successful_requests = 0u64;
700 let mut failed_requests = 0u64;
701 let mut total_response_time = 0u64;
702 let mut request_counts = HashMap::new();
703 let mut last_execution: Option<DateTime<Utc>> = None;
704
705 for request in &workspace.requests {
707 total_requests += 1;
708
709 for response in &request.responses {
711 let execution_count = response.history.len() as u64;
712 *request_counts.entry(request.id.clone()).or_insert(0) += execution_count;
713
714 for entry in &response.history {
715 total_response_time += entry.duration_ms;
716
717 if let Some(current_last) = last_execution {
719 if entry.timestamp > current_last {
720 last_execution = Some(entry.timestamp);
721 }
722 } else {
723 last_execution = Some(entry.timestamp);
724 }
725
726 if entry.duration_ms < 5000 {
728 successful_requests += 1;
730 } else {
731 failed_requests += 1;
732 }
733 }
734 }
735 }
736
737 self.collect_folder_request_metrics(
739 &workspace.folders,
740 &mut total_requests,
741 &mut successful_requests,
742 &mut failed_requests,
743 &mut total_response_time,
744 &mut request_counts,
745 &mut last_execution,
746 );
747
748 let average_response_time = if total_requests > 0 {
749 total_response_time as f64 / total_requests as f64
750 } else {
751 0.0
752 };
753
754 let mut popular_requests: Vec<_> = request_counts.into_iter().collect();
756 popular_requests.sort_by(|a, b| b.1.cmp(&a.1));
757 popular_requests.truncate(5);
758
759 RequestMetrics {
760 total_requests,
761 successful_requests,
762 failed_requests,
763 average_response_time_ms: average_response_time,
764 popular_requests,
765 last_execution,
766 }
767 }
768
769 #[allow(clippy::only_used_in_recursion)]
771 #[allow(clippy::too_many_arguments)]
772 fn collect_folder_request_metrics(
773 &self,
774 folders: &[Folder],
775 total_requests: &mut u64,
776 successful_requests: &mut u64,
777 failed_requests: &mut u64,
778 total_response_time: &mut u64,
779 request_counts: &mut HashMap<EntityId, u64>,
780 last_execution: &mut Option<DateTime<Utc>>,
781 ) {
782 for folder in folders {
783 for request in &folder.requests {
784 *total_requests += 1;
785
786 for response in &request.responses {
788 let execution_count = response.history.len() as u64;
789 *request_counts.entry(request.id.clone()).or_insert(0) += execution_count;
790
791 for entry in &response.history {
792 *total_response_time += entry.duration_ms;
793
794 if let Some(current_last) = *last_execution {
796 if entry.timestamp > current_last {
797 *last_execution = Some(entry.timestamp);
798 }
799 } else {
800 *last_execution = Some(entry.timestamp);
801 }
802
803 if entry.duration_ms < 5000 {
805 *successful_requests += 1;
806 } else {
807 *failed_requests += 1;
808 }
809 }
810 }
811 }
812
813 self.collect_folder_request_metrics(
815 &folder.folders,
816 total_requests,
817 successful_requests,
818 failed_requests,
819 total_response_time,
820 request_counts,
821 last_execution,
822 );
823 }
824 }
825
826 pub fn create_route_from_request(&self, request: &MockRequest) -> Result<Route> {
828 if !request.enabled {
829 return Err(Error::validation("Request is disabled"));
830 }
831
832 let response = request
833 .active_response()
834 .ok_or_else(|| Error::validation("No active response found"))?;
835
836 let mut route = Route::new(request.method.clone(), request.url.clone());
838
839 route.metadata.insert("id".to_string(), serde_json::json!(request.id));
841 route.metadata.insert("response".to_string(), serde_json::json!(response.body));
842 route
843 .metadata
844 .insert("status_code".to_string(), serde_json::json!(response.status_code));
845 route.metadata.insert("headers".to_string(), serde_json::json!(request.headers));
846 route
847 .metadata
848 .insert("query_params".to_string(), serde_json::json!(request.query_params));
849 route.metadata.insert("enabled".to_string(), serde_json::json!(request.enabled));
850 route
851 .metadata
852 .insert("created_at".to_string(), serde_json::json!(request.created_at));
853 route
854 .metadata
855 .insert("updated_at".to_string(), serde_json::json!(request.updated_at));
856
857 Ok(route)
858 }
859
860 pub fn update_route_registry(
862 &self,
863 workspace: &Workspace,
864 route_registry: &mut RouteRegistry,
865 ) -> Result<()> {
866 route_registry.clear();
867
868 for request in &workspace.requests {
870 if request.enabled {
871 if let Ok(route) = self.create_route_from_request(request) {
872 let _ = route_registry.add_route(route);
873 }
874 }
875 }
876
877 self.add_folder_routes_to_registry(&workspace.folders, route_registry)?;
879
880 Ok(())
881 }
882
883 fn add_folder_routes_to_registry(
885 &self,
886 folders: &[Folder],
887 route_registry: &mut RouteRegistry,
888 ) -> Result<()> {
889 for folder in folders {
890 for request in &folder.requests {
891 if request.enabled {
892 if let Ok(route) = self.create_route_from_request(request) {
893 let _ = route_registry.add_route(route);
894 }
895 }
896 }
897
898 self.add_folder_routes_to_registry(&folder.folders, route_registry)?;
900 }
901
902 Ok(())
903 }
904
905 fn generate_response_cache_key(
909 &self,
910 request_id: &EntityId,
911 context: &RequestExecutionContext,
912 ) -> String {
913 use std::collections::hash_map::DefaultHasher;
914 use std::hash::{Hash, Hasher};
915
916 let mut hasher = DefaultHasher::new();
917 request_id.hash(&mut hasher);
918 context.workspace_id.hash(&mut hasher);
919
920 for (key, value) in &context.environment_variables {
922 key.hash(&mut hasher);
923 value.hash(&mut hasher);
924 }
925
926 for (key, value) in &context.global_headers {
928 key.hash(&mut hasher);
929 value.hash(&mut hasher);
930 }
931
932 format!("req_{}_{}", hasher.finish(), request_id)
933 }
934
935 async fn validate_request_cached(
937 &self,
938 request: &MockRequest,
939 context: &RequestExecutionContext,
940 ) -> Result<RequestValidationResult> {
941 if !self.optimizations_enabled {
942 return Ok(self.validate_request(request, context));
943 }
944
945 let cache_key = format!("val_{}_{}", request.id, context.workspace_id);
947
948 if let Some(cached_result) = self.validation_cache.get(&cache_key).await {
950 return Ok(cached_result);
951 }
952
953 let result = self.validate_request(request, context);
955
956 self.validation_cache.insert(cache_key, result.clone(), None).await;
958
959 Ok(result)
960 }
961
962 fn convert_mock_response_to_cached_response(&self, response: &MockResponse) -> CachedResponse {
964 CachedResponse {
965 status_code: response.status_code,
966 headers: response.headers.clone(),
967 body: response.body.clone(),
968 content_type: response.headers.get("Content-Type").cloned(),
969 }
970 }
971
972 fn convert_cached_response_to_mock_response(&self, cached: CachedResponse) -> MockResponse {
974 MockResponse {
975 id: EntityId::new(),
976 name: "Cached Response".to_string(),
977 status_code: cached.status_code,
978 headers: cached.headers,
979 body: cached.body,
980 delay: 0, active: true,
982 created_at: chrono::Utc::now(),
983 updated_at: chrono::Utc::now(),
984 history: Vec::new(),
985 intelligent: None,
986 drift: None,
987 }
988 }
989
990 pub async fn get_performance_summary(&self) -> crate::performance::PerformanceSummary {
992 self.performance_monitor.get_summary().await
993 }
994
995 pub async fn get_cache_stats(&self) -> (crate::cache::CacheStats, crate::cache::CacheStats) {
997 let response_cache_stats = self.response_cache.stats().await;
998 let validation_cache_stats = self.validation_cache.stats().await;
999 (response_cache_stats, validation_cache_stats)
1000 }
1001
1002 pub async fn clear_caches(&self) {
1004 self.response_cache.get_response("").await; self.validation_cache.clear().await;
1006 }
1007}
1008
1009impl Default for RequestProcessor {
1010 fn default() -> Self {
1011 Self::new()
1012 }
1013}