1use super::*;
21use tokio::sync::mpsc;
22use std::net::SocketAddr;
23use tokio::io::{AsyncReadExt, AsyncWriteExt};
24
25pub struct RiGrpcServer {
26 config: RiGrpcConfig,
27 stats: Arc<RwLock<RiGrpcStats>>,
28 registry: RiGrpcServiceRegistry,
29 shutdown_tx: Option<mpsc::Sender<()>>,
30 running: Arc<RwLock<bool>>,
31}
32
33#[cfg(feature = "pyo3")]
34#[pyclass]
35pub struct RiGrpcServerPy {
36 inner: RiGrpcServer,
37}
38
39#[cfg(feature = "pyo3")]
40#[pymethods]
41impl RiGrpcServerPy {
42 #[new]
43 fn new() -> Self {
44 Self {
45 inner: RiGrpcServer::new(RiGrpcConfig::default()),
46 }
47 }
48
49 fn get_stats(&self) -> RiGrpcStats {
50 self.inner.get_stats()
51 }
52
53 fn is_running(&self) -> bool {
54 self.inner.is_running_sync()
55 }
56
57 fn list_services(&self) -> Vec<String> {
58 self.inner.list_services()
59 }
60
61 fn start(&mut self) -> PyResult<()> {
62 let rt = tokio::runtime::Runtime::new()
63 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
64
65 rt.block_on(async {
66 self.inner.start().await
67 }).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
68 }
69
70 fn stop(&mut self) -> PyResult<()> {
71 let rt = tokio::runtime::Runtime::new()
72 .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
73
74 rt.block_on(async {
75 self.inner.stop().await
76 }).map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
77 }
78}
79
80impl RiGrpcServer {
81 pub fn new(config: RiGrpcConfig) -> Self {
82 Self {
83 config,
84 stats: Arc::new(RwLock::new(RiGrpcStats::new())),
85 registry: RiGrpcServiceRegistry::new(),
86 shutdown_tx: None,
87 running: Arc::new(RwLock::new(false)),
88 }
89 }
90
91 pub fn get_stats(&self) -> RiGrpcStats {
92 self.stats.try_read()
93 .map(|guard| guard.clone())
94 .unwrap_or_else(|_| RiGrpcStats::new())
95 }
96
97 pub fn is_running_sync(&self) -> bool {
98 self.stats.try_read()
99 .map(|guard| guard.active_connections > 0)
100 .unwrap_or(false)
101 }
102
103 pub fn list_services(&self) -> Vec<String> {
104 self.registry.list_services()
105 }
106
107 pub async fn start(&mut self) -> RiResult<()> {
108 let addr: SocketAddr = format!("{}:{}", self.config.addr, self.config.port).parse()
109 .map_err(|e| GrpcError::Server { message: format!("Invalid address: {}", e) })?;
110
111 let (shutdown_tx, shutdown_rx) = mpsc::channel(1);
112 self.shutdown_tx = Some(shutdown_tx);
113
114 *self.running.write().await = true;
115
116 let stats = self.stats.clone();
117 let registry = self.registry.clone();
118 let running = self.running.clone();
119 let max_concurrent = self.config.max_concurrent_requests as usize;
120 let config = self.config.clone();
121
122 tokio::spawn(async move {
123 let _ = Self::run_server(addr, stats, registry, shutdown_rx, running, max_concurrent, config).await;
124 });
125
126 tracing::info!("gRPC server started on {}", addr);
127 Ok(())
128 }
129
130 async fn run_server(
131 addr: SocketAddr,
132 stats: Arc<RwLock<RiGrpcStats>>,
133 registry: RiGrpcServiceRegistry,
134 mut shutdown_rx: mpsc::Receiver<()>,
135 running: Arc<RwLock<bool>>,
136 max_concurrent: usize,
137 config: RiGrpcConfig,
138 ) {
139 let listener = match tokio::net::TcpListener::bind(&addr).await {
140 Ok(l) => l,
141 Err(e) => {
142 tracing::error!("Failed to bind gRPC server to {}: {}", addr, e);
143 return;
144 }
145 };
146
147 tracing::info!("gRPC server listening on {}", addr);
148
149 let semaphore = Arc::new(tokio::sync::Semaphore::new(max_concurrent));
150
151 loop {
152 tokio::select! {
153 _ = shutdown_rx.recv() => {
154 tracing::info!("gRPC server shutting down");
155 break;
156 }
157 result = listener.accept() => {
158 match result {
159 Ok((stream, peer_addr)) => {
160 let permit = semaphore.clone().acquire_owned().await;
161 if let Ok(permit) = permit {
162 stats.write().await.active_connections += 1;
163
164 let stats_clone = stats.clone();
165 let registry_clone = registry.clone();
166 let config_clone = config.clone();
167
168 tokio::spawn(async move {
169 Self::handle_connection(stream, peer_addr, stats_clone, registry_clone, config_clone).await;
170 drop(permit);
171 });
172 }
173 }
174 Err(e) => {
175 tracing::error!("Failed to accept connection: {}", e);
176 }
177 }
178 }
179 }
180 }
181
182 *running.write().await = false;
183 }
184
185 async fn handle_connection(
186 mut stream: tokio::net::TcpStream,
187 peer_addr: SocketAddr,
188 stats: Arc<RwLock<RiGrpcStats>>,
189 registry: RiGrpcServiceRegistry,
190 config: RiGrpcConfig,
191 ) {
192 tracing::debug!("gRPC client connected from {}", peer_addr);
193
194 let mut buffer = vec![0u8; 65536];
195
196 loop {
197 let n = match stream.read(&mut buffer).await {
198 Ok(0) => break,
199 Ok(n) => n,
200 Err(e) => {
201 tracing::debug!("Read error from {}: {}", peer_addr, e);
202 break;
203 }
204 };
205
206 let request_data = &buffer[..n];
207
208 if let Err(e) = Self::process_request(&mut stream, request_data, &stats, ®istry, &config).await {
209 tracing::error!("Error processing request from {}: {}", peer_addr, e);
210 break;
211 }
212 }
213
214 let mut stats_guard = stats.write().await;
215 if stats_guard.active_connections > 0 {
216 stats_guard.active_connections -= 1;
217 }
218 }
219
220 async fn process_request(
221 stream: &mut tokio::net::TcpStream,
222 request_data: &[u8],
223 stats: &Arc<RwLock<RiGrpcStats>>,
224 registry: &RiGrpcServiceRegistry,
225 config: &RiGrpcConfig,
226 ) -> RiResult<()> {
227 let request_str = String::from_utf8_lossy(request_data);
228
229 if config.enable_auth {
230 if let Some(ref expected_token) = config.auth_token {
231 let auth_valid = Self::validate_auth(&request_str, expected_token);
232 if !auth_valid {
233 stats.write().await.record_error();
234 let error_response = Self::build_grpc_error_response("Unauthorized: Invalid or missing authentication token");
235 stream.write_all(&error_response).await
236 .map_err(|e| GrpcError::Server { message: format!("Write error: {}", e) })?;
237 return Err(GrpcError::Server { message: "Unauthorized".to_string() }.into());
238 }
239 }
240 }
241
242 let (service_name, method_name) = Self::parse_request_path(&request_str)?;
243
244 tracing::debug!("gRPC request: {}/{}", service_name, method_name);
245
246 let services = registry.services.read().await;
247 let service = services.get(&service_name).cloned();
248 drop(services);
249
250 match service {
251 Some(svc) => {
252 let body_start = Self::find_body_start(request_data);
253 let body_data = if body_start < request_data.len() {
254 &request_data[body_start..]
255 } else {
256 &request_data[0..0]
257 };
258
259 stats.write().await.record_request(body_data.len());
260
261 match svc.handle_request(&method_name, body_data).await {
262 Ok(response_data) => {
263 stats.write().await.record_response(response_data.len());
264
265 let grpc_response = Self::build_grpc_response(&response_data);
266 stream.write_all(&grpc_response).await
267 .map_err(|e| GrpcError::Server { message: format!("Write error: {}", e) })?;
268 }
269 Err(e) => {
270 stats.write().await.record_error();
271
272 let error_response = Self::build_grpc_error_response(&e.to_string());
273 stream.write_all(&error_response).await
274 .map_err(|e| GrpcError::Server { message: format!("Write error: {}", e) })?;
275 }
276 }
277 }
278 None => {
279 stats.write().await.record_error();
280
281 let error_response = Self::build_grpc_error_response(&format!("Service not found: {}", service_name));
282 stream.write_all(&error_response).await
283 .map_err(|e| GrpcError::Server { message: format!("Write error: {}", e) })?;
284 }
285 }
286
287 Ok(())
288 }
289
290 fn validate_auth(request_str: &str, expected_token: &str) -> bool {
297 let expected_bearer = format!("Bearer {}", expected_token);
298
299 for line in request_str.lines() {
300 let line_lower = line.to_lowercase();
301 if line_lower.contains("authorization") {
302 if let Some(token) = line.split(':').nth(1) {
303 let token = token.trim();
304
305 let token_matches = Self::constant_time_compare(token.as_bytes(), expected_bearer.as_bytes())
308 || Self::constant_time_compare(token.as_bytes(), expected_token.as_bytes());
309
310 return token_matches;
311 }
312 }
313 }
314 false
315 }
316
317 fn constant_time_compare(a: &[u8], b: &[u8]) -> bool {
331 if a.len() != b.len() {
332 let mut _result: u8 = 0;
333 for i in 0..a.len() {
334 _result |= a[i] ^ if i < b.len() { b[i] } else { a[i] };
335 }
336 return false;
337 }
338
339 let mut result: u8 = 0;
340 for i in 0..a.len() {
341 result |= a[i] ^ b[i];
342 }
343
344 result == 0
345 }
346
347 fn parse_request_path(request_str: &str) -> RiResult<(String, String)> {
348 for line in request_str.lines() {
349 if line.contains(":path") {
350 let parts: Vec<&str> = line.split_whitespace().collect();
351 if parts.len() >= 2 {
352 let full_path = parts[1].trim_start_matches('/');
353 let path_parts: Vec<&str> = full_path.splitn(2, '/').collect();
354 if path_parts.len() == 2 {
355 return Ok((path_parts[0].to_string(), path_parts[1].to_string()));
356 }
357 }
358 }
359 }
360
361 Err(GrpcError::Server { message: "Invalid request path".to_string() }.into())
362 }
363
364 fn find_body_start(buffer: &[u8]) -> usize {
365 let mut pos = 0;
366 while pos + 3 < buffer.len() {
367 if buffer[pos] == b'\r' && buffer[pos + 1] == b'\n' && buffer[pos + 2] == b'\r' && buffer[pos + 3] == b'\n' {
368 return pos + 4;
369 }
370 pos += 1;
371 }
372 buffer.len()
373 }
374
375 fn build_grpc_response(data: &[u8]) -> Vec<u8> {
376 let header_len = 58;
377 let trailers_len = 24;
378 let total_len = header_len + 4 + data.len() + trailers_len;
379 let mut response = Vec::with_capacity(total_len);
380
381 let header = "HTTP/2.0 200 OK\r\ncontent-type: application/grpc\r\n\r\n";
382 response.extend_from_slice(header.as_bytes());
383
384 let len = data.len() as u32;
385 response.push(0u8);
386 response.extend_from_slice(&len.to_be_bytes()[1..4]);
387 response.extend_from_slice(data);
388
389 let trailers = "\r\ngrpc-status: 0\r\n\r\n";
390 response.extend_from_slice(trailers.as_bytes());
391
392 response
393 }
394
395 fn build_grpc_error_response(message: &str) -> Vec<u8> {
396 let header = "HTTP/2.0 200 OK\r\ncontent-type: application/grpc\r\n\r\n";
397 let trailers = format!("\r\ngrpc-status: 2\r\ngrpc-message: {}\r\n\r\n", message);
398 let total_len = header.len() + trailers.len();
399 let mut response = Vec::with_capacity(total_len);
400
401 response.extend_from_slice(header.as_bytes());
402 response.extend_from_slice(trailers.as_bytes());
403
404 response
405 }
406
407 pub async fn stop(&mut self) -> RiResult<()> {
408 *self.running.write().await = false;
409
410 if let Some(tx) = self.shutdown_tx.take() {
411 tx.send(()).await.map_err(|e| GrpcError::Server {
412 message: format!("Shutdown error: {}", e)
413 })?;
414 }
415
416 tracing::info!("gRPC server stopped");
417 Ok(())
418 }
419
420 pub async fn is_running(&self) -> bool {
421 *self.running.read().await
422 }
423}
424
425impl Clone for RiGrpcServer {
426 fn clone(&self) -> Self {
427 Self {
428 config: self.config.clone(),
429 stats: self.stats.clone(),
430 registry: self.registry.clone(),
431 shutdown_tx: None,
432 running: self.running.clone(),
433 }
434 }
435}
436
437impl Default for RiGrpcServer {
438 fn default() -> Self {
439 Self::new(RiGrpcConfig::default())
440 }
441}