mockforge_grpc/reflection/mock_proxy/
proxy.rs

1//! Core proxy functionality and state management
2//!
3//! This module provides the main MockReflectionProxy struct and core proxy functionality.
4
5use crate::dynamic::ServiceRegistry;
6use crate::reflection::{
7    cache::DescriptorCache,
8    config::ProxyConfig,
9    connection_pool::ConnectionPool,
10    smart_mock_generator::{SmartMockConfig, SmartMockGenerator},
11};
12use std::sync::{
13    atomic::{AtomicUsize, Ordering},
14    Arc, Mutex,
15};
16use std::time::Duration;
17use tonic::Status;
18use tracing::debug;
19
20/// Guard that automatically decrements the active connection counter when dropped
21pub struct ConnectionGuard {
22    counter: Arc<AtomicUsize>,
23}
24
25impl Drop for ConnectionGuard {
26    fn drop(&mut self) {
27        self.counter.fetch_sub(1, Ordering::Relaxed);
28    }
29}
30
31/// A mock-enabled reflection proxy that serves mock responses
32pub struct MockReflectionProxy {
33    /// Cache of service and method descriptors
34    pub(crate) cache: DescriptorCache,
35    /// Proxy configuration
36    pub(crate) config: ProxyConfig,
37    /// Timeout for requests
38    pub(crate) timeout_duration: Duration,
39    /// Connection pool for gRPC channels
40    #[allow(dead_code)]
41    pub(crate) connection_pool: ConnectionPool,
42    /// Registry of dynamic services for mock responses
43    pub(crate) service_registry: Arc<ServiceRegistry>,
44    /// Smart mock data generator for intelligent field population
45    pub(crate) smart_generator: Arc<Mutex<SmartMockGenerator>>,
46    /// Counter for active connections/requests
47    pub(crate) active_connections: Arc<AtomicUsize>,
48    /// Counter for total requests processed
49    pub(crate) total_requests: Arc<AtomicUsize>,
50}
51
52impl MockReflectionProxy {
53    /// Create a new mock reflection proxy
54    pub async fn new(
55        config: ProxyConfig,
56        service_registry: Arc<ServiceRegistry>,
57    ) -> Result<Self, Status> {
58        debug!(
59            "Creating mock reflection proxy with {} services",
60            service_registry.service_names().len()
61        );
62
63        let cache = DescriptorCache::new();
64
65        // Populate cache from service registry's descriptor pool
66        cache.populate_from_pool(Some(service_registry.descriptor_pool())).await;
67
68        let connection_pool = ConnectionPool::new();
69
70        let timeout_duration = Duration::from_secs(config.request_timeout_seconds);
71
72        let smart_generator = Arc::new(Mutex::new(SmartMockGenerator::new(SmartMockConfig {
73            field_name_inference: true,
74            use_faker: true,
75            field_overrides: std::collections::HashMap::new(),
76            service_profiles: std::collections::HashMap::new(),
77            max_depth: 3,
78            seed: config.mock_seed,
79            deterministic: false,
80        })));
81
82        Ok(Self {
83            cache,
84            config,
85            timeout_duration,
86            connection_pool,
87            service_registry,
88            smart_generator,
89            active_connections: Arc::new(AtomicUsize::new(0)),
90            total_requests: Arc::new(AtomicUsize::new(0)),
91        })
92    }
93
94    /// Get the proxy configuration
95    pub fn config(&self) -> &ProxyConfig {
96        &self.config
97    }
98
99    /// Get the descriptor cache
100    pub fn cache(&self) -> &DescriptorCache {
101        &self.cache
102    }
103
104    /// Get the service registry
105    pub fn service_registry(&self) -> &Arc<ServiceRegistry> {
106        &self.service_registry
107    }
108
109    /// Get the list of service names
110    pub fn service_names(&self) -> Vec<String> {
111        self.service_registry.service_names()
112    }
113
114    /// Get the smart mock generator
115    pub fn smart_generator(&self) -> &Arc<Mutex<SmartMockGenerator>> {
116        &self.smart_generator
117    }
118
119    /// Check if a service method should be mocked
120    pub fn should_mock_service_method(&self, service_name: &str, _method_name: &str) -> bool {
121        // Check if service is in registry
122        self.service_registry.get(service_name).is_some()
123    }
124
125    /// Get the timeout duration for requests
126    pub fn timeout_duration(&self) -> Duration {
127        self.timeout_duration
128    }
129
130    /// Update the proxy configuration
131    pub fn update_config(&mut self, config: ProxyConfig) {
132        self.config = config;
133        // Update timeout
134        self.timeout_duration = Duration::from_secs(self.config.request_timeout_seconds);
135    }
136
137    /// Create a connection guard that tracks active connections
138    pub fn track_connection(&self) -> ConnectionGuard {
139        self.active_connections.fetch_add(1, Ordering::Relaxed);
140        ConnectionGuard {
141            counter: self.active_connections.clone(),
142        }
143    }
144
145    /// Get statistics about the proxy
146    pub async fn get_stats(&self) -> ProxyStats {
147        ProxyStats {
148            cached_services: self.cache.service_count().await,
149            cached_methods: self.cache.method_count().await,
150            registered_services: self.service_registry.service_names().len(),
151            total_requests: self.total_requests.load(Ordering::Relaxed) as u64,
152            active_connections: self.active_connections.load(Ordering::Relaxed),
153        }
154    }
155}
156
157/// Statistics about the proxy
158#[derive(Debug, Clone)]
159pub struct ProxyStats {
160    pub cached_services: usize,
161    pub cached_methods: usize,
162    pub registered_services: usize,
163    pub total_requests: u64,
164    pub active_connections: usize,
165}
166
167impl Clone for MockReflectionProxy {
168    fn clone(&self) -> Self {
169        Self {
170            cache: self.cache.clone(),
171            config: self.config.clone(),
172            timeout_duration: self.timeout_duration,
173            connection_pool: self.connection_pool.clone(),
174            service_registry: self.service_registry.clone(),
175            smart_generator: self.smart_generator.clone(),
176            active_connections: self.active_connections.clone(),
177            total_requests: self.total_requests.clone(),
178        }
179    }
180}
181
182#[cfg(test)]
183mod tests {
184
185    #[test]
186    fn test_module_compiles() {}
187}