1use std::future::Future;
2use std::pin::Pin;
3use std::sync::Arc;
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::BoxCloneSyncService<Exchange, Exchange, CamelError>;
52
53#[derive(Clone)]
65pub struct OpaqueProcessor(pub BoxProcessor);
66
67impl std::fmt::Debug for OpaqueProcessor {
68 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69 f.write_str("BoxProcessor(...)")
70 }
71}
72
73pub struct SyncBoxProcessor(BoxProcessor);
84
85impl SyncBoxProcessor {
86 pub fn new(processor: BoxProcessor) -> Self {
87 SyncBoxProcessor(processor)
88 }
89
90 pub fn clone_inner(&self) -> BoxProcessor {
91 self.0.clone()
92 }
93}
94
95impl Clone for SyncBoxProcessor {
96 fn clone(&self) -> Self {
97 SyncBoxProcessor(self.0.clone())
98 }
99}
100
101#[allow(dead_code)]
104const _: () = {
105 fn is_sync<T: Sync>() {}
106 fn _check() {
107 is_sync::<BoxProcessor>();
108 }
109};
110
111pub trait BoxProcessorExt {
124 fn from_fn<F, Fut>(f: F) -> BoxProcessor
128 where
129 F: Fn(Exchange) -> Fut + Send + Sync + 'static,
130 Fut: Future<Output = Result<Exchange, CamelError>> + Send + 'static;
131}
132
133impl BoxProcessorExt for BoxProcessor {
134 fn from_fn<F, Fut>(f: F) -> BoxProcessor
135 where
136 F: Fn(Exchange) -> Fut + Send + Sync + 'static,
137 Fut: Future<Output = Result<Exchange, CamelError>> + Send + 'static,
138 {
139 BoxProcessor::new(ProcessorFn::new(f))
140 }
141}
142
143pub struct ProcessorFn<F> {
147 f: Arc<F>,
148}
149
150impl<F> Clone for ProcessorFn<F> {
152 fn clone(&self) -> Self {
153 Self {
154 f: Arc::clone(&self.f),
155 }
156 }
157}
158
159impl<F> ProcessorFn<F> {
160 pub fn new(f: F) -> Self {
161 Self { f: Arc::new(f) }
162 }
163}
164
165impl<F, Fut> Service<Exchange> for ProcessorFn<F>
166where
167 F: Fn(Exchange) -> Fut + Send + Sync + 'static,
168 Fut: Future<Output = Result<Exchange, CamelError>> + Send + 'static,
169{
170 type Response = Exchange;
171 type Error = CamelError;
172 type Future = Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send>>;
173
174 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
175 Poll::Ready(Ok(()))
176 }
177
178 fn call(&mut self, exchange: Exchange) -> Self::Future {
179 let f = Arc::clone(&self.f);
180 Box::pin(async move { f(exchange).await })
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::message::Message;
188 use tower::ServiceExt;
189
190 #[tokio::test]
191 async fn test_identity_processor_passes_through() {
192 let exchange = Exchange::new(Message::new("hello"));
193 let processor = IdentityProcessor;
194
195 let result = processor.oneshot(exchange).await.unwrap();
196 assert_eq!(result.input.body.as_text(), Some("hello"));
197 }
198
199 #[tokio::test]
200 async fn test_identity_processor_preserves_headers() {
201 let mut exchange = Exchange::new(Message::default());
202 exchange
203 .input
204 .set_header("key", serde_json::Value::String("value".into()));
205
206 let processor = IdentityProcessor;
207 let result = processor.oneshot(exchange).await.unwrap();
208 assert_eq!(
209 result.input.header("key"),
210 Some(&serde_json::Value::String("value".into()))
211 );
212 }
213
214 #[tokio::test]
215 async fn test_identity_processor_preserves_properties() {
216 let mut exchange = Exchange::new(Message::default());
217 exchange.set_property("prop", serde_json::Value::Bool(true));
218
219 let processor = IdentityProcessor;
220 let result = processor.oneshot(exchange).await.unwrap();
221 assert_eq!(
222 result.property("prop"),
223 Some(&serde_json::Value::Bool(true))
224 );
225 }
226
227 #[tokio::test]
228 async fn test_processor_fn_transforms_exchange() {
229 let processor = ProcessorFn::new(|mut ex: Exchange| async move {
230 ex.input.body = crate::body::Body::Text("transformed".into());
231 Ok(ex)
232 });
233
234 let exchange = Exchange::new(Message::new("original"));
235 let result = processor.oneshot(exchange).await.unwrap();
236 assert_eq!(result.input.body.as_text(), Some("transformed"));
237 }
238
239 #[tokio::test]
240 async fn test_processor_fn_can_return_error() {
241 let processor = ProcessorFn::new(|_ex: Exchange| async move {
242 Err(CamelError::ProcessorError("intentional error".into()))
243 });
244
245 let exchange = Exchange::new(Message::default());
246 let result: Result<Exchange, CamelError> = processor.oneshot(exchange).await;
247 assert!(result.is_err());
248 }
249
250 #[tokio::test]
251 async fn test_processor_fn_is_cloneable() {
252 let processor = ProcessorFn::new(|ex: Exchange| async move { Ok(ex) });
253 let cloned = processor.clone();
254
255 let exchange = Exchange::new(Message::new("test"));
256 let result = cloned.oneshot(exchange).await.unwrap();
257 assert_eq!(result.input.body.as_text(), Some("test"));
258 }
259
260 #[tokio::test]
261 async fn test_box_processor_from_identity() {
262 let processor: BoxProcessor = BoxProcessor::new(IdentityProcessor);
263
264 let exchange = Exchange::new(Message::new("boxed"));
265 let result = processor.oneshot(exchange).await.unwrap();
266 assert_eq!(result.input.body.as_text(), Some("boxed"));
267 }
268
269 #[tokio::test]
270 async fn test_box_processor_from_processor_fn() {
271 let processor: BoxProcessor =
272 BoxProcessor::new(ProcessorFn::new(|mut ex: Exchange| async move {
273 ex.input.body = crate::body::Body::Text("via_box".into());
274 Ok(ex)
275 }));
276
277 let exchange = Exchange::new(Message::new("original"));
278 let result = processor.oneshot(exchange).await.unwrap();
279 assert_eq!(result.input.body.as_text(), Some("via_box"));
280 }
281
282 #[tokio::test]
283 async fn test_box_processor_ext_from_fn() {
284 let processor = BoxProcessor::from_fn(|mut ex: Exchange| async move {
285 ex.input.body = crate::body::Body::Text("via_from_fn".into());
286 Ok(ex)
287 });
288
289 let exchange = Exchange::new(Message::new("original"));
290 let result = processor.oneshot(exchange).await.unwrap();
291 assert_eq!(result.input.body.as_text(), Some("via_from_fn"));
292 }
293}