camel_processor/
set_header.rs1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use tower::Service;
6
7use camel_api::{CamelError, Exchange, Value};
8
9#[derive(Clone)]
11pub struct SetHeader<P> {
12 inner: P,
13 key: String,
14 value: Value,
15}
16
17impl<P> SetHeader<P> {
18 pub fn new(inner: P, key: impl Into<String>, value: impl Into<Value>) -> Self {
20 Self {
21 inner,
22 key: key.into(),
23 value: value.into(),
24 }
25 }
26}
27
28#[derive(Clone)]
30pub struct SetHeaderLayer {
31 key: String,
32 value: Value,
33}
34
35impl SetHeaderLayer {
36 pub fn new(key: impl Into<String>, value: impl Into<Value>) -> Self {
37 Self {
38 key: key.into(),
39 value: value.into(),
40 }
41 }
42}
43
44impl<S> tower::Layer<S> for SetHeaderLayer {
45 type Service = SetHeader<S>;
46
47 fn layer(&self, inner: S) -> Self::Service {
48 SetHeader::new(inner, self.key.clone(), self.value.clone())
49 }
50}
51
52impl<P> Service<Exchange> for SetHeader<P>
53where
54 P: Service<Exchange, Response = Exchange, Error = CamelError> + Clone + Send + 'static,
55 P::Future: Send,
56{
57 type Response = Exchange;
58 type Error = CamelError;
59 type Future = Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send>>;
60
61 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
62 self.inner.poll_ready(cx)
63 }
64
65 fn call(&mut self, mut exchange: Exchange) -> Self::Future {
66 exchange
67 .input
68 .headers
69 .insert(self.key.clone(), self.value.clone());
70 let fut = self.inner.call(exchange);
71 Box::pin(fut)
72 }
73}
74
75#[derive(Clone)]
78pub struct SetHeaderIfAbsent<P> {
79 inner: P,
80 key: String,
81 value: Value,
82}
83
84impl<P> SetHeaderIfAbsent<P> {
85 pub fn new(inner: P, key: impl Into<String>, value: impl Into<Value>) -> Self {
88 Self {
89 inner,
90 key: key.into(),
91 value: value.into(),
92 }
93 }
94}
95
96impl<P> Service<Exchange> for SetHeaderIfAbsent<P>
97where
98 P: Service<Exchange, Response = Exchange, Error = CamelError> + Clone + Send + 'static,
99 P::Future: Send,
100{
101 type Response = Exchange;
102 type Error = CamelError;
103 type Future = Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send>>;
104
105 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
106 self.inner.poll_ready(cx)
107 }
108
109 fn call(&mut self, mut exchange: Exchange) -> Self::Future {
110 exchange
111 .input
112 .headers
113 .entry(self.key.clone())
114 .or_insert(self.value.clone());
115 let fut = self.inner.call(exchange);
116 Box::pin(fut)
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use camel_api::{IdentityProcessor, Message};
124 use tower::ServiceExt;
125
126 #[tokio::test]
127 async fn test_set_header_adds_header() {
128 let exchange = Exchange::new(Message::default());
129
130 let processor = SetHeader::new(IdentityProcessor, "source", Value::String("timer".into()));
131
132 let result = processor.oneshot(exchange).await.unwrap();
133 assert_eq!(
134 result.input.header("source"),
135 Some(&Value::String("timer".into()))
136 );
137 }
138
139 #[tokio::test]
140 async fn test_set_header_overwrites_existing() {
141 let mut exchange = Exchange::new(Message::default());
142 exchange
143 .input
144 .set_header("key", Value::String("old".into()));
145
146 let processor = SetHeader::new(IdentityProcessor, "key", Value::String("new".into()));
147
148 let result = processor.oneshot(exchange).await.unwrap();
149 assert_eq!(
150 result.input.header("key"),
151 Some(&Value::String("new".into()))
152 );
153 }
154
155 #[tokio::test]
156 async fn test_set_header_preserves_body() {
157 let exchange = Exchange::new(Message::new("body content"));
158
159 let processor = SetHeader::new(IdentityProcessor, "header", Value::Bool(true));
160
161 let result = processor.oneshot(exchange).await.unwrap();
162 assert_eq!(result.input.body.as_text(), Some("body content"));
163 assert_eq!(result.input.header("header"), Some(&Value::Bool(true)));
164 }
165
166 #[tokio::test]
167 async fn test_set_header_layer_composes() {
168 use tower::ServiceBuilder;
169
170 let svc = ServiceBuilder::new()
171 .layer(super::SetHeaderLayer::new(
172 "env",
173 Value::String("test".into()),
174 ))
175 .service(IdentityProcessor);
176
177 let exchange = Exchange::new(Message::default());
178 let result = svc.oneshot(exchange).await.unwrap();
179 assert_eq!(
180 result.input.header("env"),
181 Some(&Value::String("test".into()))
182 );
183 }
184
185 #[tokio::test]
188 async fn test_set_header_if_absent_adds_when_missing() {
189 let exchange = Exchange::new(Message::default());
190
191 let processor =
192 SetHeaderIfAbsent::new(IdentityProcessor, "source", Value::String("timer".into()));
193
194 let result = processor.oneshot(exchange).await.unwrap();
195 assert_eq!(
196 result.input.header("source"),
197 Some(&Value::String("timer".into()))
198 );
199 }
200
201 #[tokio::test]
202 async fn test_set_header_if_absent_preserves_existing() {
203 let mut exchange = Exchange::new(Message::default());
204 exchange
205 .input
206 .set_header("key", Value::String("old".into()));
207
208 let processor =
209 SetHeaderIfAbsent::new(IdentityProcessor, "key", Value::String("new".into()));
210
211 let result = processor.oneshot(exchange).await.unwrap();
212 assert_eq!(
213 result.input.header("key"),
214 Some(&Value::String("old".into()))
215 );
216 }
217
218 #[tokio::test]
219 async fn test_set_header_if_absent_preserves_body() {
220 let exchange = Exchange::new(Message::new("body content"));
221
222 let processor = SetHeaderIfAbsent::new(IdentityProcessor, "header", Value::Bool(true));
223
224 let result = processor.oneshot(exchange).await.unwrap();
225 assert_eq!(result.input.body.as_text(), Some("body content"));
226 assert_eq!(result.input.header("header"), Some(&Value::Bool(true)));
227 }
228}