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