mockforge_grpc/reflection/mock_proxy/
proxy.rs1use 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
20pub 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
31pub struct MockReflectionProxy {
33 pub(crate) cache: DescriptorCache,
35 pub(crate) config: ProxyConfig,
37 pub(crate) timeout_duration: Duration,
39 #[allow(dead_code)]
41 pub(crate) connection_pool: ConnectionPool,
42 pub(crate) service_registry: Arc<ServiceRegistry>,
44 pub(crate) smart_generator: Arc<Mutex<SmartMockGenerator>>,
46 pub(crate) active_connections: Arc<AtomicUsize>,
48 pub(crate) total_requests: Arc<AtomicUsize>,
50}
51
52impl MockReflectionProxy {
53 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 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 pub fn config(&self) -> &ProxyConfig {
96 &self.config
97 }
98
99 pub fn cache(&self) -> &DescriptorCache {
101 &self.cache
102 }
103
104 pub fn service_registry(&self) -> &Arc<ServiceRegistry> {
106 &self.service_registry
107 }
108
109 pub fn service_names(&self) -> Vec<String> {
111 self.service_registry.service_names()
112 }
113
114 pub fn smart_generator(&self) -> &Arc<Mutex<SmartMockGenerator>> {
116 &self.smart_generator
117 }
118
119 pub fn should_mock_service_method(&self, service_name: &str, method_name: &str) -> bool {
121 if let Some(service) = self.service_registry.get(service_name) {
123 service.methods().iter().any(|m| m.name == method_name)
124 } else {
125 false
126 }
127 }
128
129 pub fn timeout_duration(&self) -> Duration {
131 self.timeout_duration
132 }
133
134 pub fn update_config(&mut self, config: ProxyConfig) {
136 self.config = config;
137 self.timeout_duration = Duration::from_secs(self.config.request_timeout_seconds);
139 }
140
141 pub fn track_connection(&self) -> ConnectionGuard {
143 self.active_connections.fetch_add(1, Ordering::Relaxed);
144 ConnectionGuard {
145 counter: self.active_connections.clone(),
146 }
147 }
148
149 pub async fn get_stats(&self) -> ProxyStats {
151 ProxyStats {
152 cached_services: self.cache.service_count().await,
153 cached_methods: self.cache.method_count().await,
154 registered_services: self.service_registry.service_names().len(),
155 total_requests: self.total_requests.load(Ordering::Relaxed) as u64,
156 active_connections: self.active_connections.load(Ordering::Relaxed),
157 }
158 }
159}
160
161#[derive(Debug, Clone)]
163pub struct ProxyStats {
164 pub cached_services: usize,
166 pub cached_methods: usize,
168 pub registered_services: usize,
170 pub total_requests: u64,
172 pub active_connections: usize,
174}
175
176impl Clone for MockReflectionProxy {
177 fn clone(&self) -> Self {
178 Self {
179 cache: self.cache.clone(),
180 config: self.config.clone(),
181 timeout_duration: self.timeout_duration,
182 connection_pool: self.connection_pool.clone(),
183 service_registry: self.service_registry.clone(),
184 smart_generator: self.smart_generator.clone(),
185 active_connections: self.active_connections.clone(),
186 total_requests: self.total_requests.clone(),
187 }
188 }
189}
190
191#[cfg(test)]
192mod tests {
193 #[test]
194 fn test_module_compiles() {
195 }
197}