use std::collections::HashMap;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use crate::function::AppError;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct EventEnvelope {
id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
to: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
from: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
reply_to: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
cid: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
trace_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
trace_path: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
span_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
status: Option<i32>,
headers: HashMap<String, String>,
#[serde(default = "nil_value", skip_serializing_if = "is_nil")]
body: rmpv::Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
exec_time: Option<f32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
round_trip: Option<f32>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
annotations: HashMap<String, rmpv::Value>,
#[serde(default, skip_serializing_if = "HashMap::is_empty")]
tags: HashMap<String, String>,
}
fn nil_value() -> rmpv::Value {
rmpv::Value::Nil
}
fn is_nil(value: &rmpv::Value) -> bool {
matches!(value, rmpv::Value::Nil)
}
impl Default for EventEnvelope {
fn default() -> Self {
EventEnvelope {
id: uuid::Uuid::new_v4().simple().to_string(),
to: None,
from: None,
reply_to: None,
cid: None,
trace_id: None,
trace_path: None,
span_id: None,
status: None,
headers: HashMap::new(),
body: rmpv::Value::Nil,
exec_time: None,
round_trip: None,
annotations: HashMap::new(),
tags: HashMap::new(),
}
}
}
impl EventEnvelope {
pub fn new() -> Self {
Self::default()
}
pub fn set_to(mut self, route: &str) -> Self {
self.to = Some(route.to_string());
self
}
pub fn set_from(mut self, route: &str) -> Self {
self.from = Some(route.to_string());
self
}
pub fn set_reply_to(mut self, route: &str) -> Self {
self.reply_to = Some(route.to_string());
self
}
pub fn clear_reply_to(mut self) -> Self {
self.reply_to = None;
self
}
pub fn clear_to(mut self) -> Self {
self.to = None;
self
}
pub fn set_correlation_id(mut self, cid: &str) -> Self {
self.cid = Some(cid.to_string());
self
}
pub fn set_trace(mut self, trace_id: &str, trace_path: &str) -> Self {
self.trace_id = Some(trace_id.to_string());
self.trace_path = Some(trace_path.to_string());
self
}
pub fn set_span_id(mut self, span_id: &str) -> Self {
self.span_id = Some(span_id.to_string());
self
}
pub fn set_status(mut self, status: i32) -> Self {
self.status = Some(status);
self
}
pub fn set_header(mut self, key: &str, value: &str) -> Self {
let value: String = value.chars().filter(|c| *c != '\r' && *c != '\n').collect();
self.headers.insert(key.to_string(), value);
self
}
pub fn set_body<T: Serialize>(mut self, value: T) -> Result<Self, AppError> {
self.body = rmpv::ext::to_value(value)
.map_err(|e| AppError::new(500, format!("unable to serialize body: {e}")))?;
Ok(self)
}
pub fn set_raw_body(mut self, value: rmpv::Value) -> Self {
self.body = value;
self
}
pub fn id(&self) -> &str {
&self.id
}
pub fn to(&self) -> Option<&str> {
self.to.as_deref()
}
pub fn from(&self) -> Option<&str> {
self.from.as_deref()
}
pub fn reply_to(&self) -> Option<&str> {
self.reply_to.as_deref()
}
pub fn correlation_id(&self) -> Option<&str> {
self.cid.as_deref()
}
pub fn trace_id(&self) -> Option<&str> {
self.trace_id.as_deref()
}
pub fn trace_path(&self) -> Option<&str> {
self.trace_path.as_deref()
}
pub fn span_id(&self) -> Option<&str> {
self.span_id.as_deref()
}
pub fn status(&self) -> i32 {
self.status.unwrap_or(200)
}
pub fn has_error(&self) -> bool {
self.status() >= 400
}
pub fn headers(&self) -> &HashMap<String, String> {
&self.headers
}
pub fn header(&self, key: &str) -> Option<&str> {
if let Some(value) = self.headers.get(key) {
return Some(value.as_str());
}
self.headers
.iter()
.find(|(name, _)| name.eq_ignore_ascii_case(key))
.map(|(_, value)| value.as_str())
}
pub fn body(&self) -> &rmpv::Value {
&self.body
}
pub fn body_as<T: DeserializeOwned>(&self) -> Result<T, AppError> {
rmpv::ext::from_value(self.body.clone())
.map_err(|e| AppError::new(500, format!("unable to deserialize body: {e}")))
}
pub fn exec_time(&self) -> Option<f32> {
self.exec_time
}
pub fn round_trip(&self) -> Option<f32> {
self.round_trip
}
pub fn set_round_trip(mut self, ms: f32) -> Self {
self.round_trip = Some(ms);
self
}
pub fn annotations(&self) -> &HashMap<String, rmpv::Value> {
&self.annotations
}
pub fn clear_annotations(mut self) -> Self {
self.annotations.clear();
self
}
pub fn tag(&self, key: &str) -> Option<&str> {
self.tags.get(key).map(String::as_str)
}
pub fn add_tag(mut self, key: &str, value: &str) -> Self {
self.tags.insert(key.to_string(), value.to_string());
self
}
pub(crate) fn set_body_internal(&mut self, body: rmpv::Value) {
self.body = body;
}
pub(crate) fn set_cid_internal(&mut self, cid: Option<String>) {
self.cid = cid;
}
pub(crate) fn set_from_internal(&mut self, from: &str) {
self.from = Some(from.to_string());
}
pub(crate) fn set_to_internal(&mut self, to: &str) {
self.to = Some(to.to_string());
}
pub(crate) fn set_exec_time_internal(&mut self, ms: f32) {
self.exec_time = Some(ms);
}
pub(crate) fn set_trace_internal(&mut self, trace_id: &str, trace_path: &str) {
self.trace_id = Some(trace_id.to_string());
self.trace_path = Some(trace_path.to_string());
}
pub(crate) fn set_span_id_internal(&mut self, span_id: &str) {
self.span_id = Some(span_id.to_string());
}
pub(crate) fn clear_span_id_internal(&mut self) {
self.span_id = None;
}
pub(crate) fn set_annotations_internal(&mut self, annotations: HashMap<String, rmpv::Value>) {
self.annotations = annotations;
}
pub(crate) fn clear_annotations_internal(&mut self) {
self.annotations.clear();
}
pub(crate) fn clear_tags_internal(&mut self) {
self.tags.clear();
}
pub(crate) fn remove_header_internal(&mut self, key: &str) -> Option<String> {
self.headers.remove(key)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, AppError> {
if crate::serializer::null_transport() || !crate::serializer::has_nil_map_entry(&self.body)
{
return rmp_serde::to_vec_named(self)
.map_err(|e| AppError::new(500, format!("unable to encode envelope: {e}")));
}
let mut stripped = self.clone();
stripped.body = crate::serializer::strip_nulls_always(&self.body);
rmp_serde::to_vec_named(&stripped)
.map_err(|e| AppError::new(500, format!("unable to encode envelope: {e}")))
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, AppError> {
rmp_serde::from_slice(bytes)
.map_err(|e| AppError::new(500, format!("unable to decode envelope: {e}")))
}
}