1use std::collections::HashMap;
31
32use serde::de::DeserializeOwned;
33use serde::{Deserialize, Serialize};
34
35use crate::function::AppError;
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
48pub struct EventEnvelope {
49 id: String,
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 to: Option<String>,
52 #[serde(default, skip_serializing_if = "Option::is_none")]
53 from: Option<String>,
54 #[serde(default, skip_serializing_if = "Option::is_none")]
55 reply_to: Option<String>,
56 #[serde(default, skip_serializing_if = "Option::is_none")]
57 cid: Option<String>,
58 #[serde(default, skip_serializing_if = "Option::is_none")]
59 trace_id: Option<String>,
60 #[serde(default, skip_serializing_if = "Option::is_none")]
61 trace_path: Option<String>,
62 #[serde(default, skip_serializing_if = "Option::is_none")]
65 span_id: Option<String>,
66 #[serde(default, skip_serializing_if = "Option::is_none")]
67 status: Option<i32>,
68 headers: HashMap<String, String>,
69 #[serde(default = "nil_value", skip_serializing_if = "is_nil")]
71 body: rmpv::Value,
72 #[serde(default, skip_serializing_if = "Option::is_none")]
73 exec_time: Option<f32>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
77 round_trip: Option<f32>,
78 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
85 annotations: HashMap<String, rmpv::Value>,
86 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
93 tags: HashMap<String, String>,
94}
95
96fn nil_value() -> rmpv::Value {
97 rmpv::Value::Nil
98}
99
100fn is_nil(value: &rmpv::Value) -> bool {
101 matches!(value, rmpv::Value::Nil)
102}
103
104impl Default for EventEnvelope {
105 fn default() -> Self {
106 EventEnvelope {
107 id: uuid::Uuid::new_v4().simple().to_string(),
108 to: None,
109 from: None,
110 reply_to: None,
111 cid: None,
112 trace_id: None,
113 trace_path: None,
114 span_id: None,
115 status: None,
116 headers: HashMap::new(),
117 body: rmpv::Value::Nil,
118 exec_time: None,
119 round_trip: None,
120 annotations: HashMap::new(),
121 tags: HashMap::new(),
122 }
123 }
124}
125
126impl EventEnvelope {
127 pub fn new() -> Self {
128 Self::default()
129 }
130
131 pub fn set_to(mut self, route: &str) -> Self {
134 self.to = Some(route.to_string());
135 self
136 }
137
138 pub fn set_from(mut self, route: &str) -> Self {
139 self.from = Some(route.to_string());
140 self
141 }
142
143 pub fn set_reply_to(mut self, route: &str) -> Self {
144 self.reply_to = Some(route.to_string());
145 self
146 }
147
148 pub fn clear_reply_to(mut self) -> Self {
152 self.reply_to = None;
153 self
154 }
155
156 pub fn clear_to(mut self) -> Self {
161 self.to = None;
162 self
163 }
164
165 pub fn set_correlation_id(mut self, cid: &str) -> Self {
166 self.cid = Some(cid.to_string());
167 self
168 }
169
170 pub fn set_trace(mut self, trace_id: &str, trace_path: &str) -> Self {
171 self.trace_id = Some(trace_id.to_string());
172 self.trace_path = Some(trace_path.to_string());
173 self
174 }
175
176 pub fn set_span_id(mut self, span_id: &str) -> Self {
179 self.span_id = Some(span_id.to_string());
180 self
181 }
182
183 pub fn set_status(mut self, status: i32) -> Self {
184 self.status = Some(status);
185 self
186 }
187
188 pub fn set_header(mut self, key: &str, value: &str) -> Self {
189 let value: String = value.chars().filter(|c| *c != '\r' && *c != '\n').collect();
192 self.headers.insert(key.to_string(), value);
193 self
194 }
195
196 pub fn set_body<T: Serialize>(mut self, value: T) -> Result<Self, AppError> {
199 self.body = rmpv::ext::to_value(value)
200 .map_err(|e| AppError::new(500, format!("unable to serialize body: {e}")))?;
201 Ok(self)
202 }
203
204 pub fn set_raw_body(mut self, value: rmpv::Value) -> Self {
206 self.body = value;
207 self
208 }
209
210 pub fn id(&self) -> &str {
213 &self.id
214 }
215
216 pub fn to(&self) -> Option<&str> {
217 self.to.as_deref()
218 }
219
220 pub fn from(&self) -> Option<&str> {
221 self.from.as_deref()
222 }
223
224 pub fn reply_to(&self) -> Option<&str> {
225 self.reply_to.as_deref()
226 }
227
228 pub fn correlation_id(&self) -> Option<&str> {
229 self.cid.as_deref()
230 }
231
232 pub fn trace_id(&self) -> Option<&str> {
233 self.trace_id.as_deref()
234 }
235
236 pub fn trace_path(&self) -> Option<&str> {
237 self.trace_path.as_deref()
238 }
239
240 pub fn span_id(&self) -> Option<&str> {
242 self.span_id.as_deref()
243 }
244
245 pub fn status(&self) -> i32 {
247 self.status.unwrap_or(200)
248 }
249
250 pub fn has_error(&self) -> bool {
252 self.status() >= 400
253 }
254
255 pub fn headers(&self) -> &HashMap<String, String> {
256 &self.headers
257 }
258
259 pub fn header(&self, key: &str) -> Option<&str> {
260 if let Some(value) = self.headers.get(key) {
263 return Some(value.as_str());
264 }
265 self.headers
266 .iter()
267 .find(|(name, _)| name.eq_ignore_ascii_case(key))
268 .map(|(_, value)| value.as_str())
269 }
270
271 pub fn body(&self) -> &rmpv::Value {
272 &self.body
273 }
274
275 pub fn body_as<T: DeserializeOwned>(&self) -> Result<T, AppError> {
278 rmpv::ext::from_value(self.body.clone())
279 .map_err(|e| AppError::new(500, format!("unable to deserialize body: {e}")))
280 }
281
282 pub fn exec_time(&self) -> Option<f32> {
284 self.exec_time
285 }
286
287 pub fn round_trip(&self) -> Option<f32> {
289 self.round_trip
290 }
291
292 pub fn set_round_trip(mut self, ms: f32) -> Self {
295 self.round_trip = Some(ms);
296 self
297 }
298
299 pub fn annotations(&self) -> &HashMap<String, rmpv::Value> {
301 &self.annotations
302 }
303
304 pub fn clear_annotations(mut self) -> Self {
307 self.annotations.clear();
308 self
309 }
310
311 pub fn tag(&self, key: &str) -> Option<&str> {
313 self.tags.get(key).map(String::as_str)
314 }
315
316 pub fn add_tag(mut self, key: &str, value: &str) -> Self {
320 self.tags.insert(key.to_string(), value.to_string());
321 self
322 }
323
324 pub(crate) fn set_body_internal(&mut self, body: rmpv::Value) {
327 self.body = body;
328 }
329
330 pub(crate) fn set_cid_internal(&mut self, cid: Option<String>) {
331 self.cid = cid;
332 }
333
334 pub(crate) fn set_from_internal(&mut self, from: &str) {
335 self.from = Some(from.to_string());
336 }
337
338 pub(crate) fn set_to_internal(&mut self, to: &str) {
339 self.to = Some(to.to_string());
340 }
341
342 pub(crate) fn set_exec_time_internal(&mut self, ms: f32) {
343 self.exec_time = Some(ms);
344 }
345
346 pub(crate) fn set_trace_internal(&mut self, trace_id: &str, trace_path: &str) {
347 self.trace_id = Some(trace_id.to_string());
348 self.trace_path = Some(trace_path.to_string());
349 }
350
351 pub(crate) fn set_span_id_internal(&mut self, span_id: &str) {
352 self.span_id = Some(span_id.to_string());
353 }
354
355 pub(crate) fn clear_span_id_internal(&mut self) {
356 self.span_id = None;
357 }
358
359 pub(crate) fn set_annotations_internal(&mut self, annotations: HashMap<String, rmpv::Value>) {
360 self.annotations = annotations;
361 }
362
363 pub(crate) fn clear_annotations_internal(&mut self) {
364 self.annotations.clear();
365 }
366
367 pub(crate) fn clear_tags_internal(&mut self) {
368 self.tags.clear();
369 }
370
371 pub(crate) fn remove_header_internal(&mut self, key: &str) -> Option<String> {
374 self.headers.remove(key)
375 }
376
377 pub fn to_bytes(&self) -> Result<Vec<u8>, AppError> {
391 if crate::serializer::null_transport() || !crate::serializer::has_nil_map_entry(&self.body)
392 {
393 return rmp_serde::to_vec_named(self)
394 .map_err(|e| AppError::new(500, format!("unable to encode envelope: {e}")));
395 }
396 let mut stripped = self.clone();
397 stripped.body = crate::serializer::strip_nulls_always(&self.body);
398 rmp_serde::to_vec_named(&stripped)
399 .map_err(|e| AppError::new(500, format!("unable to encode envelope: {e}")))
400 }
401
402 pub fn from_bytes(bytes: &[u8]) -> Result<Self, AppError> {
404 rmp_serde::from_slice(bytes)
405 .map_err(|e| AppError::new(500, format!("unable to decode envelope: {e}")))
406 }
407}