1use std::future::Future;
2use std::pin::Pin;
3use std::sync::{Arc, Mutex};
4use std::task::{Context, Poll};
5
6use tower::Service;
7
8use crate::error::CamelError;
9use crate::exchange::Exchange;
10
11pub trait Processor:
16 Service<Exchange, Response = Exchange, Error = CamelError> + Clone + Send + Sync + 'static
17{
18}
19
20impl<P> Processor for P where
22 P: Service<Exchange, Response = Exchange, Error = CamelError> + Clone + Send + Sync + 'static
23{
24}
25
26#[derive(Debug, Clone)]
28pub struct IdentityProcessor;
29
30impl Service<Exchange> for IdentityProcessor {
31 type Response = Exchange;
32 type Error = CamelError;
33 type Future = Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send>>;
34
35 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
36 Poll::Ready(Ok(()))
37 }
38
39 fn call(&mut self, exchange: Exchange) -> Self::Future {
40 Box::pin(async move { Ok(exchange) })
41 }
42}
43
44pub type BoxProcessor = tower::util::BoxCloneService<Exchange, Exchange, CamelError>;
48
49#[derive(Clone)]
61pub struct OpaqueProcessor(pub BoxProcessor);
62
63impl std::fmt::Debug for OpaqueProcessor {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 f.write_str("BoxProcessor(...)")
66 }
67}
68
69pub struct SyncBoxProcessor(Arc<Mutex<BoxProcessor>>);
77
78impl SyncBoxProcessor {
79 pub fn new(processor: BoxProcessor) -> Self {
80 SyncBoxProcessor(Arc::new(Mutex::new(processor)))
81 }
82
83 pub fn clone_inner(&self) -> BoxProcessor {
84 self.0.lock().unwrap_or_else(|e| e.into_inner()).clone()
85 }
86}
87
88impl Clone for SyncBoxProcessor {
89 fn clone(&self) -> Self {
90 SyncBoxProcessor(self.0.clone())
91 }
92}
93
94pub trait BoxProcessorExt {
107 fn from_fn<F, Fut>(f: F) -> BoxProcessor
111 where
112 F: Fn(Exchange) -> Fut + Send + Sync + 'static,
113 Fut: Future<Output = Result<Exchange, CamelError>> + Send + 'static;
114}
115
116impl BoxProcessorExt for BoxProcessor {
117 fn from_fn<F, Fut>(f: F) -> BoxProcessor
118 where
119 F: Fn(Exchange) -> Fut + Send + Sync + 'static,
120 Fut: Future<Output = Result<Exchange, CamelError>> + Send + 'static,
121 {
122 BoxProcessor::new(ProcessorFn::new(f))
123 }
124}
125
126pub struct ProcessorFn<F> {
130 f: Arc<F>,
131}
132
133impl<F> Clone for ProcessorFn<F> {
135 fn clone(&self) -> Self {
136 Self {
137 f: Arc::clone(&self.f),
138 }
139 }
140}
141
142impl<F> ProcessorFn<F> {
143 pub fn new(f: F) -> Self {
144 Self { f: Arc::new(f) }
145 }
146}
147
148impl<F, Fut> Service<Exchange> for ProcessorFn<F>
149where
150 F: Fn(Exchange) -> Fut + Send + Sync + 'static,
151 Fut: Future<Output = Result<Exchange, CamelError>> + Send + 'static,
152{
153 type Response = Exchange;
154 type Error = CamelError;
155 type Future = Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send>>;
156
157 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
158 Poll::Ready(Ok(()))
159 }
160
161 fn call(&mut self, exchange: Exchange) -> Self::Future {
162 let f = Arc::clone(&self.f);
163 Box::pin(async move { f(exchange).await })
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use super::*;
170 use crate::message::Message;
171 use tower::ServiceExt;
172
173 #[tokio::test]
174 async fn test_identity_processor_passes_through() {
175 let exchange = Exchange::new(Message::new("hello"));
176 let processor = IdentityProcessor;
177
178 let result = processor.oneshot(exchange).await.unwrap();
179 assert_eq!(result.input.body.as_text(), Some("hello"));
180 }
181
182 #[tokio::test]
183 async fn test_identity_processor_preserves_headers() {
184 let mut exchange = Exchange::new(Message::default());
185 exchange
186 .input
187 .set_header("key", serde_json::Value::String("value".into()));
188
189 let processor = IdentityProcessor;
190 let result = processor.oneshot(exchange).await.unwrap();
191 assert_eq!(
192 result.input.header("key"),
193 Some(&serde_json::Value::String("value".into()))
194 );
195 }
196
197 #[tokio::test]
198 async fn test_identity_processor_preserves_properties() {
199 let mut exchange = Exchange::new(Message::default());
200 exchange.set_property("prop", serde_json::Value::Bool(true));
201
202 let processor = IdentityProcessor;
203 let result = processor.oneshot(exchange).await.unwrap();
204 assert_eq!(
205 result.property("prop"),
206 Some(&serde_json::Value::Bool(true))
207 );
208 }
209
210 #[tokio::test]
211 async fn test_processor_fn_transforms_exchange() {
212 let processor = ProcessorFn::new(|mut ex: Exchange| async move {
213 ex.input.body = crate::body::Body::Text("transformed".into());
214 Ok(ex)
215 });
216
217 let exchange = Exchange::new(Message::new("original"));
218 let result = processor.oneshot(exchange).await.unwrap();
219 assert_eq!(result.input.body.as_text(), Some("transformed"));
220 }
221
222 #[tokio::test]
223 async fn test_processor_fn_can_return_error() {
224 let processor = ProcessorFn::new(|_ex: Exchange| async move {
225 Err(CamelError::ProcessorError("intentional error".into()))
226 });
227
228 let exchange = Exchange::new(Message::default());
229 let result: Result<Exchange, CamelError> = processor.oneshot(exchange).await;
230 assert!(result.is_err());
231 }
232
233 #[tokio::test]
234 async fn test_processor_fn_is_cloneable() {
235 let processor = ProcessorFn::new(|ex: Exchange| async move { Ok(ex) });
236 let cloned = processor.clone();
237
238 let exchange = Exchange::new(Message::new("test"));
239 let result = cloned.oneshot(exchange).await.unwrap();
240 assert_eq!(result.input.body.as_text(), Some("test"));
241 }
242
243 #[tokio::test]
244 async fn test_box_processor_from_identity() {
245 let processor: BoxProcessor = tower::util::BoxCloneService::new(IdentityProcessor);
246
247 let exchange = Exchange::new(Message::new("boxed"));
248 let result = processor.oneshot(exchange).await.unwrap();
249 assert_eq!(result.input.body.as_text(), Some("boxed"));
250 }
251
252 #[tokio::test]
253 async fn test_box_processor_from_processor_fn() {
254 let processor: BoxProcessor =
255 tower::util::BoxCloneService::new(ProcessorFn::new(|mut ex: Exchange| async move {
256 ex.input.body = crate::body::Body::Text("via_box".into());
257 Ok(ex)
258 }));
259
260 let exchange = Exchange::new(Message::new("original"));
261 let result = processor.oneshot(exchange).await.unwrap();
262 assert_eq!(result.input.body.as_text(), Some("via_box"));
263 }
264
265 #[tokio::test]
266 async fn test_box_processor_ext_from_fn() {
267 let processor = BoxProcessor::from_fn(|mut ex: Exchange| async move {
268 ex.input.body = crate::body::Body::Text("via_from_fn".into());
269 Ok(ex)
270 });
271
272 let exchange = Exchange::new(Message::new("original"));
273 let result = processor.oneshot(exchange).await.unwrap();
274 assert_eq!(result.input.body.as_text(), Some("via_from_fn"));
275 }
276}