1use std::collections::HashMap as StdHashMap;
2use std::path::PathBuf;
3use std::sync::Arc;
4use std::sync::OnceLock;
5use std::sync::atomic::{AtomicU64, Ordering};
6
7use async_trait::async_trait;
8use base64::Engine;
9use bytes::BytesMut;
10use camel_api::store_principal_properties;
11use camel_api::{AuthorizationDecision, Body, CamelError, Exchange, Message, Value};
12use camel_component_api::{
13 ConcurrencyModel, Consumer, ConsumerContext, ConsumerStartupMode, ExchangeEnvelope,
14 SecurityContext,
15};
16use camel_proto_compiler::ProtoCache;
17use prost::Message as _;
18use prost_reflect::{DynamicMessage, MessageDescriptor};
19use tokio::sync::mpsc;
20use tonic::Status;
21use tracing::{debug, info};
22
23use crate::config::GrpcServerConfig;
24use crate::mode::GrpcMode;
25use crate::server::GrpcDispatchTable;
26use crate::server::GrpcServerRegistry;
27
28static PROTO_CACHE: OnceLock<ProtoCache> = OnceLock::new();
29
30fn proto_cache() -> &'static ProtoCache {
31 PROTO_CACHE.get_or_init(ProtoCache::new)
32}
33
34pub fn resolve_grpc_mode(
36 proto_path: &PathBuf,
37 service_name: &str,
38 method_name: &str,
39) -> Result<GrpcMode, CamelError> {
40 let cache = proto_cache();
41 let pool = cache
42 .get_or_compile(proto_path, std::iter::empty::<&std::path::Path>())
43 .map_err(|e| CamelError::EndpointCreationFailed(format!("failed to compile proto: {e}")))?;
44
45 let svc = pool.get_service_by_name(service_name).ok_or_else(|| {
46 CamelError::EndpointCreationFailed(format!(
47 "service descriptor not found: {}",
48 service_name
49 ))
50 })?;
51
52 let method = svc
53 .methods()
54 .find(|m| m.name() == method_name)
55 .ok_or_else(|| {
56 CamelError::EndpointCreationFailed(format!(
57 "method descriptor not found: {}/{}",
58 service_name, method_name
59 ))
60 })?;
61
62 Ok(GrpcMode::from_method(&method))
63}
64
65const RESERVED_METADATA_KEYS: &[&str] = &[
66 "content-type",
67 "te",
68 "grpc-encoding",
69 "grpc-accept-encoding",
70 "grpc-status",
71 "grpc-message",
72 "grpc-status-details-bin",
73 "user-agent",
74];
75
76fn extract_metadata(metadata: &tonic::metadata::MetadataMap) -> Vec<(String, serde_json::Value)> {
77 let mut headers = Vec::new();
78 for key_and_value in metadata.iter() {
79 use tonic::metadata::KeyAndValueRef;
80 match key_and_value {
81 KeyAndValueRef::Ascii(key, value) => {
82 let key_str = key.as_str();
83 if RESERVED_METADATA_KEYS.contains(&key_str) {
84 continue;
85 }
86 if let Ok(v) = value.to_str() {
87 headers.push((
88 key_str.to_string(),
89 serde_json::Value::String(v.to_string()),
90 ));
91 }
92 }
93 KeyAndValueRef::Binary(key, value) => {
94 let key_str = key.as_str();
95 if RESERVED_METADATA_KEYS.contains(&key_str) {
96 continue;
97 }
98 let encoded = base64::engine::general_purpose::STANDARD.encode(value);
99 headers.push((format!("bin:{key_str}"), serde_json::Value::String(encoded)));
100 }
101 }
102 }
103 headers
104}
105
106pub(crate) enum GrpcStreamItem {
107 Message(Vec<u8>),
108 Error(tonic::Status),
109 Done,
110}
111
112pub(crate) enum GrpcReply {
113 Ok(Vec<u8>),
114 Err(tonic::Status),
115}
116
117pub(crate) enum GrpcRequestEnvelope {
118 Unary {
119 metadata: tonic::metadata::MetadataMap,
120 body: Vec<u8>,
121 reply_tx: tokio::sync::oneshot::Sender<GrpcReply>,
122 principal: Option<camel_api::security_policy::Principal>,
123 },
124 ServerStreaming {
125 metadata: tonic::metadata::MetadataMap,
126 body: Vec<u8>,
127 reply_tx: mpsc::Sender<GrpcStreamItem>,
128 principal: Option<camel_api::security_policy::Principal>,
129 },
130 ClientStreaming {
131 metadata: tonic::metadata::MetadataMap,
132 body_rx: mpsc::Receiver<Vec<u8>>,
133 reply_tx: tokio::sync::oneshot::Sender<GrpcReply>,
134 principal: Option<camel_api::security_policy::Principal>,
135 },
136 Bidi {
137 metadata: tonic::metadata::MetadataMap,
138 body_rx: mpsc::Receiver<Vec<u8>>,
139 reply_tx: mpsc::Sender<GrpcStreamItem>,
140 principal: Option<camel_api::security_policy::Principal>,
141 },
142}
143
144static OBSERVER_REGISTRY: OnceLock<std::sync::Mutex<StdHashMap<String, GrpcStreamObserver>>> =
147 OnceLock::new();
148
149static OBSERVER_COUNTER: AtomicU64 = AtomicU64::new(0);
150
151fn next_observer_id() -> String {
152 let n = OBSERVER_COUNTER.fetch_add(1, Ordering::Relaxed);
153 format!("obs-{n}")
154}
155
156fn observer_registry() -> &'static std::sync::Mutex<StdHashMap<String, GrpcStreamObserver>> {
157 OBSERVER_REGISTRY.get_or_init(|| std::sync::Mutex::new(StdHashMap::new()))
158}
159
160fn register_observer(id: String, observer: GrpcStreamObserver) {
161 let registry = observer_registry();
162 let mut registry = match registry.lock() {
163 Ok(g) => g,
164 Err(poisoned) => poisoned.into_inner(),
165 };
166 registry.insert(id, observer);
167}
168
169fn remove_observer(id: &str) -> Option<GrpcStreamObserver> {
170 let registry = observer_registry();
171 let mut registry = match registry.lock() {
172 Ok(g) => g,
173 Err(poisoned) => poisoned.into_inner(),
174 };
175 registry.remove(id)
176}
177
178pub fn take_stream_observer(exchange: &Exchange) -> Option<GrpcStreamObserver> {
179 let id = exchange
180 .properties
181 .get("CamelGrpcStreamObserverId")?
182 .as_str()?;
183 remove_observer(id)
184}
185
186struct ObserverGuard {
189 id: String,
190}
191
192impl ObserverGuard {
193 fn new(id: String) -> Self {
194 Self { id }
195 }
196}
197
198impl Drop for ObserverGuard {
199 fn drop(&mut self) {
200 remove_observer(&self.id);
201 }
202}
203
204#[derive(Clone)]
207pub struct GrpcStreamObserver {
208 tx: mpsc::Sender<GrpcStreamItem>,
209 resp_desc: MessageDescriptor,
210}
211
212impl GrpcStreamObserver {
213 pub(crate) fn new(tx: mpsc::Sender<GrpcStreamItem>, resp_desc: MessageDescriptor) -> Self {
214 Self { tx, resp_desc }
215 }
216
217 pub async fn on_next(&self, json: serde_json::Value) -> Result<(), CamelError> {
218 let encoded = json_to_protobuf_bytes(json, self.resp_desc.clone())
219 .map_err(|e| CamelError::ProcessorError(format!("failed to encode protobuf: {e}")))?;
220 self.tx
221 .send(GrpcStreamItem::Message(encoded))
222 .await
223 .map_err(|_| CamelError::ProcessorError("stream observer channel closed".into()))
224 }
225
226 pub async fn on_error(&self, status: Status) {
227 if self.tx.send(GrpcStreamItem::Error(status)).await.is_err() {
228 tracing::debug!("grpc stream observer: failed to send error, channel closed");
229 }
230 }
231
232 pub async fn on_completed(&self) {
233 if self.tx.send(GrpcStreamItem::Done).await.is_err() {
234 tracing::debug!("grpc stream observer: failed to send done, channel closed");
235 }
236 }
237}
238
239fn json_to_protobuf_bytes(
242 json: serde_json::Value,
243 desc: MessageDescriptor,
244) -> Result<Vec<u8>, Status> {
245 let json_str = serde_json::to_string(&json)
246 .map_err(|e| Status::internal(format!("failed to serialize JSON: {e}")))?;
247 let mut de = serde_json::Deserializer::from_str(&json_str);
248 let resp_dyn = DynamicMessage::deserialize(desc, &mut de)
249 .map_err(|e| Status::internal(format!("failed to parse JSON into protobuf: {e}")))?;
250 let mut buf = BytesMut::new();
251 prost::Message::encode(&resp_dyn, &mut buf)
252 .map_err(|e| Status::internal(format!("failed to encode protobuf: {e}")))?;
253 Ok(buf.to_vec())
254}
255
256pub struct GrpcConsumer {
259 host: String,
260 port: u16,
261 path: String,
262 proto_path: PathBuf,
263 service_name: String,
264 method_name: String,
265 mode: GrpcMode,
266 security_ctx: Option<SecurityContext>,
267 runtime: Arc<dyn camel_component_api::RuntimeObservability>,
268 server_config: GrpcServerConfig,
269}
270
271impl GrpcConsumer {
272 #[allow(clippy::too_many_arguments)]
273 pub fn new(
274 host: String,
275 port: u16,
276 path: String,
277 proto_path: PathBuf,
278 service_name: String,
279 method_name: String,
280 mode: GrpcMode,
281 runtime: Arc<dyn camel_component_api::RuntimeObservability>,
282 server_config: GrpcServerConfig,
283 ) -> Self {
284 Self {
285 host,
286 port,
287 path,
288 proto_path,
289 service_name,
290 method_name,
291 mode,
292 security_ctx: None,
293 runtime,
294 server_config,
295 }
296 }
297
298 fn resolve_descriptors(&self) -> Result<(MessageDescriptor, MessageDescriptor), CamelError> {
299 let cache = proto_cache();
300 let pool = cache
301 .get_or_compile(&self.proto_path, std::iter::empty::<&std::path::Path>())
302 .map_err(|e| {
303 CamelError::EndpointCreationFailed(format!("failed to compile proto: {e}"))
304 })?;
305
306 let svc = pool
307 .get_service_by_name(&self.service_name)
308 .ok_or_else(|| {
309 CamelError::EndpointCreationFailed(format!(
310 "service descriptor not found: {}",
311 self.service_name
312 ))
313 })?;
314
315 let method = svc
316 .methods()
317 .find(|m| m.name() == self.method_name)
318 .ok_or_else(|| {
319 CamelError::EndpointCreationFailed(format!(
320 "method descriptor not found: {}/{}",
321 self.service_name, self.method_name
322 ))
323 })?;
324
325 Ok((method.input(), method.output()))
326 }
327
328 pub async fn start_with_listener(
329 &mut self,
330 ctx: ConsumerContext,
331 listener: tokio::net::TcpListener,
332 ) -> Result<(), CamelError> {
333 let dispatch = GrpcServerRegistry::global()
334 .get_or_spawn_with_listener(
335 listener,
336 &self.host,
337 self.port,
338 self.server_config.clone(),
339 Arc::clone(&self.runtime),
340 )
341 .await?;
342 self.start_inner(ctx, dispatch).await
343 }
344
345 async fn start_inner(
346 &mut self,
347 ctx: ConsumerContext,
348 dispatch: GrpcDispatchTable,
349 ) -> Result<(), CamelError> {
350 let (req_desc, resp_desc) = self.resolve_descriptors()?;
351 let mode = self.mode;
352
353 let (env_tx, mut env_rx) = mpsc::channel::<GrpcRequestEnvelope>(64);
354 {
355 let mut table = dispatch.write().await;
356 if table.contains_key(&self.path) {
357 return Err(CamelError::EndpointCreationFailed(format!(
358 "duplicate gRPC consumer path: {}",
359 self.path
360 )));
361 }
362 let authenticator = self
363 .security_ctx
364 .as_ref()
365 .map(|ctx| ctx.authenticator.clone());
366 table.insert(self.path.clone(), (env_tx, mode, authenticator));
367 }
368
369 let path = self.path.clone();
370 let host = self.host.clone();
371 let port = self.port;
372 let sender = ctx.sender();
373
374 info!(
375 path = %path,
376 host = %host,
377 port = port,
378 mode = ?mode,
379 "grpc consumer started, waiting for requests"
380 );
381
382 let semaphore = std::sync::Arc::new(tokio::sync::Semaphore::new(64));
385 let mut join_set = tokio::task::JoinSet::new();
386
387 loop {
388 tokio::select! {
389 biased;
390 _ = ctx.cancelled() => {
391 info!(
392 path = %path,
393 "grpc consumer cancelled, shutting down"
394 );
395 break;
396 }
397 envelope = env_rx.recv() => {
398 let Some(envelope) = envelope else { break };
399
400 let sem = semaphore.clone();
401 let permit = sem.acquire_owned().await.map_err(|_| CamelError::ChannelClosed)?;
402 let req_desc = req_desc.clone();
403 let resp_desc = resp_desc.clone();
404 let sender = sender.clone();
405 let correlation_id = next_observer_id();
406 let path_for_log = path.clone();
407 let policy = self.security_ctx.as_ref().map(|ctx| ctx.policy.clone());
408
409 debug!(
410 path = %path_for_log,
411 correlation_id = %correlation_id,
412 "grpc consumer received request"
413 );
414
415 join_set.spawn(async move {
416 let _permit = permit;
417 match envelope {
418 GrpcRequestEnvelope::Unary { metadata, body, reply_tx, principal } => {
419 debug!(
420 path = %path_for_log,
421 correlation_id = %correlation_id,
422 size = body.len(),
423 "grpc consumer processing unary request"
424 );
425
426 if let (Some(principal), Some(policy)) = (&principal, &policy) {
427 let mut exchange = Exchange::new(Message::new(Body::Empty));
428 store_principal_properties(&mut exchange, principal);
429 match policy.evaluate(&mut exchange).await {
430 Ok(AuthorizationDecision::Granted { .. }) => {
431 tracing::debug!(path = %path_for_log, subject = %principal.subject, "gRPC request authorized");
432 }
433 Ok(AuthorizationDecision::Denied { reason, .. }) => {
434 tracing::warn!(path = %path_for_log, reason = %reason, "gRPC request denied");
435 let _ = reply_tx.send(GrpcReply::Err(tonic::Status::permission_denied(reason)));
436 return;
437 }
438 Err(e) => {
439 tracing::error!(path = %path_for_log, error = %e, "gRPC policy evaluation error");
441 let _ = reply_tx.send(GrpcReply::Err(tonic::Status::internal(format!("authorization error: {e}"))));
442 return;
443 }
444 }
445 }
446
447 let result = process_unary_request(
448 body, metadata, req_desc, resp_desc, sender,
449 ).await;
450 let reply = match result {
451 Ok(bytes) => GrpcReply::Ok(bytes),
452 Err(status) => GrpcReply::Err(status),
453 };
454 let _ = reply_tx.send(reply);
455 }
456 GrpcRequestEnvelope::ServerStreaming { metadata, body, reply_tx, principal } => {
457 debug!(
458 path = %path_for_log,
459 correlation_id = %correlation_id,
460 size = body.len(),
461 "grpc consumer processing server streaming request"
462 );
463
464 if let (Some(principal), Some(policy)) = (&principal, &policy) {
465 let mut exchange = Exchange::new(Message::new(Body::Empty));
466 store_principal_properties(&mut exchange, principal);
467 match policy.evaluate(&mut exchange).await {
468 Ok(AuthorizationDecision::Granted { .. }) => {
469 tracing::debug!(path = %path_for_log, subject = %principal.subject, "gRPC request authorized");
470 }
471 Ok(AuthorizationDecision::Denied { reason, .. }) => {
472 tracing::warn!(path = %path_for_log, reason = %reason, "gRPC request denied");
473 let _ = reply_tx.send(GrpcStreamItem::Error(tonic::Status::permission_denied(reason))).await;
474 return;
475 }
476 Err(e) => {
477 tracing::error!(path = %path_for_log, error = %e, "gRPC policy evaluation error");
479 let _ = reply_tx.send(GrpcStreamItem::Error(tonic::Status::internal(format!("authorization error: {e}")))).await;
480 return;
481 }
482 }
483 }
484
485 process_server_streaming_request(
486 body, metadata, req_desc, resp_desc, sender, reply_tx,
487 ).await;
488 }
489 GrpcRequestEnvelope::ClientStreaming { metadata, body_rx, reply_tx, principal } => {
490 debug!(
491 path = %path_for_log,
492 correlation_id = %correlation_id,
493 "grpc consumer processing client streaming request"
494 );
495
496 if let (Some(principal), Some(policy)) = (&principal, &policy) {
497 let mut exchange = Exchange::new(Message::new(Body::Empty));
498 store_principal_properties(&mut exchange, principal);
499 match policy.evaluate(&mut exchange).await {
500 Ok(AuthorizationDecision::Granted { .. }) => {
501 tracing::debug!(path = %path_for_log, subject = %principal.subject, "gRPC request authorized");
502 }
503 Ok(AuthorizationDecision::Denied { reason, .. }) => {
504 tracing::warn!(path = %path_for_log, reason = %reason, "gRPC request denied");
505 let _ = reply_tx.send(GrpcReply::Err(tonic::Status::permission_denied(reason)));
506 return;
507 }
508 Err(e) => {
509 tracing::error!(path = %path_for_log, error = %e, "gRPC policy evaluation error");
511 let _ = reply_tx.send(GrpcReply::Err(tonic::Status::internal(format!("authorization error: {e}"))));
512 return;
513 }
514 }
515 }
516
517 process_client_streaming_request(
518 body_rx, metadata, req_desc, resp_desc, sender, reply_tx,
519 ).await;
520 }
521 GrpcRequestEnvelope::Bidi { metadata, body_rx, reply_tx, principal } => {
522 debug!(
523 path = %path_for_log,
524 correlation_id = %correlation_id,
525 "grpc consumer processing bidi streaming request"
526 );
527
528 if let (Some(principal), Some(policy)) = (&principal, &policy) {
529 let mut exchange = Exchange::new(Message::new(Body::Empty));
530 store_principal_properties(&mut exchange, principal);
531 match policy.evaluate(&mut exchange).await {
532 Ok(AuthorizationDecision::Granted { .. }) => {
533 tracing::debug!(path = %path_for_log, subject = %principal.subject, "gRPC request authorized");
534 }
535 Ok(AuthorizationDecision::Denied { reason, .. }) => {
536 tracing::warn!(path = %path_for_log, reason = %reason, "gRPC request denied");
537 let _ = reply_tx.send(GrpcStreamItem::Error(tonic::Status::permission_denied(reason))).await;
538 return;
539 }
540 Err(e) => {
541 tracing::error!(path = %path_for_log, error = %e, "gRPC policy evaluation error");
543 let _ = reply_tx.send(GrpcStreamItem::Error(tonic::Status::internal(format!("authorization error: {e}")))).await;
544 return;
545 }
546 }
547 }
548
549 process_bidi_request(
550 body_rx, metadata, req_desc, resp_desc, sender, reply_tx,
551 ).await;
552 }
553 }
554 });
555 }
556 }
557 }
558
559 join_set.shutdown().await;
560
561 GrpcServerRegistry::global()
562 .unregister(&host, port, &path)
563 .await;
564
565 info!(
566 path = %path,
567 "grpc consumer stopped"
568 );
569
570 Ok(())
571 }
572}
573
574#[async_trait]
575impl Consumer for GrpcConsumer {
576 async fn start(&mut self, ctx: ConsumerContext) -> Result<(), CamelError> {
577 info!(
578 host = %self.host,
579 port = self.port,
580 service = %self.service_name,
581 method = %self.method_name,
582 mode = ?self.mode,
583 "grpc consumer starting"
584 );
585 let dispatch = GrpcServerRegistry::global()
586 .get_or_spawn(
587 &self.host,
588 self.port,
589 self.server_config.clone(),
590 Arc::clone(&self.runtime),
591 )
592 .await?;
593 ctx.mark_ready();
596 self.start_inner(ctx, dispatch).await
597 }
598
599 async fn stop(&mut self) -> Result<(), CamelError> {
600 info!(
601 host = %self.host,
602 port = self.port,
603 service = %self.service_name,
604 method = %self.method_name,
605 "grpc consumer stopping"
606 );
607 GrpcServerRegistry::global()
608 .unregister(&self.host, self.port, &self.path)
609 .await;
610 Ok(())
611 }
612
613 fn concurrency_model(&self) -> ConcurrencyModel {
614 ConcurrencyModel::Concurrent { max: None }
615 }
616
617 fn startup_mode(&self) -> ConsumerStartupMode {
618 ConsumerStartupMode::Explicit
619 }
620
621 fn set_security_context(&mut self, ctx: SecurityContext) {
622 self.security_ctx = Some(ctx);
623 }
624}
625
626async fn process_unary_request(
629 body: Vec<u8>,
630 metadata: tonic::metadata::MetadataMap,
631 req_desc: MessageDescriptor,
632 resp_desc: MessageDescriptor,
633 sender: mpsc::Sender<ExchangeEnvelope>,
634) -> Result<Vec<u8>, Status> {
635 let req_dyn = DynamicMessage::decode(req_desc, body.as_slice())
636 .map_err(|e| Status::invalid_argument(format!("failed to decode protobuf: {e}")))?;
637
638 let json = serde_json::to_value(&req_dyn).map_err(|e| {
639 Status::invalid_argument(format!("failed to convert protobuf to JSON: {e}"))
640 })?;
641
642 let mut msg = Message::new(Body::Json(json));
643 for (k, v) in extract_metadata(&metadata) {
644 msg.set_header(k, v);
645 }
646
647 let exchange = Exchange::new(msg);
648
649 let (reply_tx, reply_rx) = tokio::sync::oneshot::channel();
650 let envelope = ExchangeEnvelope {
651 exchange,
652 reply_tx: Some(reply_tx),
653 };
654
655 sender
656 .send(envelope)
657 .await
658 .map_err(|_| Status::internal("pipeline channel closed"))?;
659
660 let result = reply_rx
661 .await
662 .map_err(|_| Status::internal("pipeline reply dropped"))?
663 .map_err(|e| Status::internal(format!("pipeline error: {e}")))?;
664
665 let resp_json = match result.input.body {
666 Body::Json(v) => v,
667 other => {
668 return Err(Status::internal(format!(
669 "expected JSON response body from pipeline, got {other:?}"
670 )));
671 }
672 };
673
674 let json_str = serde_json::to_string(&resp_json)
675 .map_err(|e| Status::internal(format!("failed to serialize response JSON: {e}")))?;
676 let mut de = serde_json::Deserializer::from_str(&json_str);
677 let resp_dyn = DynamicMessage::deserialize(resp_desc, &mut de)
678 .map_err(|e| Status::internal(format!("failed to parse JSON into protobuf: {e}")))?;
679
680 let mut buf = BytesMut::new();
681 resp_dyn
682 .encode(&mut buf)
683 .map_err(|e| Status::internal(format!("failed to encode protobuf response: {e}")))?;
684
685 Ok(buf.to_vec())
686}
687
688async fn process_server_streaming_request(
691 body: Vec<u8>,
692 metadata: tonic::metadata::MetadataMap,
693 req_desc: MessageDescriptor,
694 resp_desc: MessageDescriptor,
695 sender: mpsc::Sender<ExchangeEnvelope>,
696 reply_tx: mpsc::Sender<GrpcStreamItem>,
697) {
698 let req_dyn = match DynamicMessage::decode(req_desc, body.as_slice()) {
699 Ok(m) => m,
700 Err(e) => {
701 let _ = reply_tx
702 .send(GrpcStreamItem::Error(Status::invalid_argument(format!(
703 "failed to decode protobuf: {e}"
704 ))))
705 .await;
706 return;
707 }
708 };
709
710 let json = match serde_json::to_value(&req_dyn) {
711 Ok(v) => v,
712 Err(e) => {
713 let _ = reply_tx
714 .send(GrpcStreamItem::Error(Status::invalid_argument(format!(
715 "failed to convert protobuf to JSON: {e}"
716 ))))
717 .await;
718 return;
719 }
720 };
721
722 let mut msg = Message::new(Body::Json(json));
723 for (k, v) in extract_metadata(&metadata) {
724 msg.set_header(k, v);
725 }
726
727 let observer = GrpcStreamObserver::new(reply_tx.clone(), resp_desc);
728 let observer_id = next_observer_id();
729 register_observer(observer_id.clone(), observer);
730 let _guard = ObserverGuard::new(observer_id.clone());
731
732 let mut exchange = Exchange::new(msg);
733 exchange.set_property("CamelGrpcStreamObserverId", Value::String(observer_id));
734
735 let envelope = ExchangeEnvelope {
736 exchange,
737 reply_tx: None,
738 };
739
740 if sender.send(envelope).await.is_err() {
741 let _ = reply_tx
742 .send(GrpcStreamItem::Error(Status::internal(
743 "pipeline channel closed",
744 )))
745 .await;
746 }
747
748 reply_tx.closed().await;
753}
754
755async fn process_client_streaming_request(
758 mut body_rx: mpsc::Receiver<Vec<u8>>,
759 metadata: tonic::metadata::MetadataMap,
760 req_desc: MessageDescriptor,
761 resp_desc: MessageDescriptor,
762 sender: mpsc::Sender<ExchangeEnvelope>,
763 reply_tx: tokio::sync::oneshot::Sender<GrpcReply>,
764) {
765 while let Some(body) = body_rx.recv().await {
766 let req_dyn = match DynamicMessage::decode(req_desc.clone(), body.as_slice()) {
767 Ok(d) => d,
768 Err(e) => {
769 let _ = reply_tx.send(GrpcReply::Err(Status::invalid_argument(format!(
770 "failed to decode protobuf: {e}"
771 ))));
772 return;
773 }
774 };
775
776 let json = match serde_json::to_value(&req_dyn) {
777 Ok(j) => j,
778 Err(e) => {
779 let _ = reply_tx.send(GrpcReply::Err(Status::internal(format!(
780 "failed to convert protobuf to JSON: {e}"
781 ))));
782 return;
783 }
784 };
785
786 let mut msg = Message::new(Body::Json(json));
787 for (k, v) in extract_metadata(&metadata) {
788 msg.set_header(k, v);
789 }
790 msg.set_header(
791 "CamelGrpcClientStreaming".to_string(),
792 serde_json::Value::Bool(true),
793 );
794
795 let exchange = Exchange::new(msg);
796 let (reply_tx_pipe, reply_rx_pipe) = tokio::sync::oneshot::channel();
797 let envelope = ExchangeEnvelope {
798 exchange,
799 reply_tx: Some(reply_tx_pipe),
800 };
801
802 if sender.send(envelope).await.is_err() {
803 let _ = reply_tx.send(GrpcReply::Err(Status::internal("pipeline channel closed")));
804 return;
805 }
806
807 let _ = reply_rx_pipe.await;
809 }
810
811 let mut completion_msg = Message::new(Body::Json(serde_json::Value::Null));
813 for (k, v) in extract_metadata(&metadata) {
814 completion_msg.set_header(k, v);
815 }
816 completion_msg.set_header(
817 "CamelGrpcClientStreaming".to_string(),
818 serde_json::Value::Bool(true),
819 );
820 completion_msg.set_header(
821 "CamelGrpcClientStreamComplete".to_string(),
822 serde_json::Value::Bool(true),
823 );
824
825 let completion_exchange = Exchange::new(completion_msg);
826 let (reply_tx_pipe, reply_rx_pipe) = tokio::sync::oneshot::channel();
827 let envelope = ExchangeEnvelope {
828 exchange: completion_exchange,
829 reply_tx: Some(reply_tx_pipe),
830 };
831
832 if sender.send(envelope).await.is_err() {
833 let _ = reply_tx.send(GrpcReply::Err(Status::internal("pipeline channel closed")));
834 return;
835 }
836
837 let result = match reply_rx_pipe.await {
839 Ok(Ok(exchange)) => exchange,
840 Ok(Err(e)) => {
841 let _ = reply_tx.send(GrpcReply::Err(Status::internal(format!(
842 "pipeline error: {e}"
843 ))));
844 return;
845 }
846 Err(_) => {
847 let _ = reply_tx.send(GrpcReply::Err(Status::internal("pipeline reply dropped")));
848 return;
849 }
850 };
851
852 let resp_json = match result.input.body {
853 Body::Json(v) => v,
854 other => {
855 let _ = reply_tx.send(GrpcReply::Err(Status::internal(format!(
856 "expected JSON response body from pipeline, got {other:?}"
857 ))));
858 return;
859 }
860 };
861
862 let encoded = match json_to_protobuf_bytes(resp_json, resp_desc) {
863 Ok(b) => b,
864 Err(e) => {
865 let _ = reply_tx.send(GrpcReply::Err(Status::internal(format!(
866 "failed to encode response: {e}",
867 ))));
868 return;
869 }
870 };
871
872 let _ = reply_tx.send(GrpcReply::Ok(encoded));
873}
874
875async fn process_bidi_request(
878 mut body_rx: mpsc::Receiver<Vec<u8>>,
879 metadata: tonic::metadata::MetadataMap,
880 req_desc: MessageDescriptor,
881 resp_desc: MessageDescriptor,
882 sender: mpsc::Sender<ExchangeEnvelope>,
883 reply_tx: mpsc::Sender<GrpcStreamItem>,
884) {
885 let observer = GrpcStreamObserver::new(reply_tx.clone(), resp_desc);
886 let observer_id = next_observer_id();
887 register_observer(observer_id.clone(), observer.clone());
888 let _guard = ObserverGuard::new(observer_id.clone());
889
890 let sender_clone = sender.clone();
892 let metadata_clone = metadata.clone();
893 let req_desc_clone = req_desc.clone();
894
895 let forward_task = tokio::spawn(async move {
896 let mut sequence: u64 = 0;
897 while let Some(body) = body_rx.recv().await {
898 let req_dyn = match DynamicMessage::decode(req_desc_clone.clone(), body.as_slice()) {
899 Ok(m) => m,
900 Err(e) => {
901 let _ = observer
902 .on_error(Status::invalid_argument(format!(
903 "failed to decode protobuf: {e}"
904 )))
905 .await;
906 continue;
907 }
908 };
909
910 let json = match serde_json::to_value(&req_dyn) {
911 Ok(v) => v,
912 Err(e) => {
913 let _ = observer
914 .on_error(Status::invalid_argument(format!(
915 "failed to convert protobuf to JSON: {e}"
916 )))
917 .await;
918 continue;
919 }
920 };
921
922 let mut msg = Message::new(Body::Json(json));
923 for (k, v) in extract_metadata(&metadata_clone) {
924 msg.set_header(k, v);
925 }
926
927 msg.set_header(
928 "CamelGrpcBidiSequence",
929 serde_json::Value::Number(sequence.into()),
930 );
931 sequence += 1;
932
933 let mut exchange = Exchange::new(msg);
934 exchange.set_property(
935 "CamelGrpcStreamObserverId",
936 Value::String(observer_id.clone()),
937 );
938
939 let envelope = ExchangeEnvelope {
940 exchange,
941 reply_tx: None,
942 };
943
944 if sender_clone.send(envelope).await.is_err() {
945 let _ = observer
946 .on_error(Status::internal("pipeline channel closed"))
947 .await;
948 break;
949 }
950 }
951
952 observer.on_completed().await;
954 });
955
956 let _ = forward_task.await;
958}