1use chrono::{DateTime, Utc};
4use rskit_errors::{AppError, AppResult, ErrorCode};
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Event {
11 pub id: String,
13 #[serde(rename = "type")]
15 pub event_type: String,
16 pub source: String,
18 #[serde(default)]
20 pub subject: String,
21 #[serde(default = "default_content_type")]
23 pub content_type: String,
24 #[serde(default)]
26 pub version: String,
27 pub timestamp: DateTime<Utc>,
29 pub data: serde_json::Value,
31}
32
33fn default_content_type() -> String {
34 "application/json".to_string()
35}
36
37impl Event {
38 pub fn new(event_type: impl Into<String>, source: impl Into<String>) -> Self {
40 Self {
41 id: Uuid::new_v4().to_string(),
42 event_type: event_type.into(),
43 source: source.into(),
44 subject: String::new(),
45 content_type: "application/json".to_string(),
46 version: "1.0".to_string(),
47 timestamp: Utc::now(),
48 data: serde_json::Value::Null,
49 }
50 }
51
52 #[must_use]
54 pub fn with_subject(mut self, subject: impl Into<String>) -> Self {
55 self.subject = subject.into();
56 self
57 }
58
59 pub fn with_data(mut self, data: impl Serialize) -> AppResult<Self> {
61 self.data = serde_json::to_value(data).map_err(|e| {
62 AppError::new(
63 ErrorCode::Internal,
64 format!("Failed to serialize event data: {e}"),
65 )
66 })?;
67 Ok(self)
68 }
69
70 #[must_use]
72 pub fn with_version(mut self, version: impl Into<String>) -> Self {
73 self.version = version.into();
74 self
75 }
76
77 #[must_use]
79 pub fn with_content_type(mut self, content_type: impl Into<String>) -> Self {
80 self.content_type = content_type.into();
81 self
82 }
83
84 pub fn to_json(&self) -> AppResult<Vec<u8>> {
86 serde_json::to_vec(self).map_err(|e| {
87 AppError::new(
88 ErrorCode::Internal,
89 format!("Failed to serialize event: {e}"),
90 )
91 })
92 }
93
94 pub fn from_json(bytes: &[u8]) -> AppResult<Self> {
96 serde_json::from_slice(bytes).map_err(|e| {
97 AppError::new(
98 ErrorCode::Internal,
99 format!("Failed to deserialize event: {e}"),
100 )
101 })
102 }
103
104 pub fn parse_data<T: serde::de::DeserializeOwned>(&self) -> AppResult<T> {
106 serde_json::from_value(self.data.clone()).map_err(|e| {
107 AppError::new(
108 ErrorCode::Internal,
109 format!("Failed to parse event data: {e}"),
110 )
111 })
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use super::*;
118
119 #[test]
120 fn new_event_has_defaults() {
121 let event = Event::new("user.created", "auth-service");
122 assert_eq!(event.event_type, "user.created");
123 assert_eq!(event.source, "auth-service");
124 assert!(!event.id.is_empty());
125 assert_eq!(event.content_type, "application/json");
126 assert_eq!(event.version, "1.0");
127 assert_eq!(event.data, serde_json::Value::Null);
128 }
129
130 #[test]
131 fn builder_methods() {
132 let event = Event::new("order.placed", "shop")
133 .with_subject("order-123")
134 .with_version("2.0")
135 .with_content_type("text/plain");
136
137 assert_eq!(event.subject, "order-123");
138 assert_eq!(event.version, "2.0");
139 assert_eq!(event.content_type, "text/plain");
140 }
141
142 #[test]
143 fn with_data_serializes_payload() {
144 #[derive(Serialize, Deserialize, Debug, PartialEq)]
145 struct Payload {
146 name: String,
147 count: u32,
148 }
149
150 let payload = Payload {
151 name: "test".to_string(),
152 count: 42,
153 };
154 let event = Event::new("test.event", "test")
155 .with_data(&payload)
156 .unwrap();
157
158 let parsed: Payload = event.parse_data().unwrap();
159 assert_eq!(parsed, payload);
160 }
161
162 #[test]
163 fn json_round_trip() {
164 let event = Event::new("round.trip", "test-source")
165 .with_subject("sub")
166 .with_data(serde_json::json!({"key": "value"}))
167 .unwrap();
168
169 let bytes = event.to_json().unwrap();
170 let restored = Event::from_json(&bytes).unwrap();
171
172 assert_eq!(restored.id, event.id);
173 assert_eq!(restored.event_type, "round.trip");
174 assert_eq!(restored.source, "test-source");
175 assert_eq!(restored.subject, "sub");
176 assert_eq!(restored.data, serde_json::json!({"key": "value"}));
177 }
178
179 #[test]
180 fn serde_renames_type_field() {
181 let event = Event::new("check.rename", "src");
182 let json = serde_json::to_string(&event).unwrap();
183 assert!(json.contains(r#""type":"check.rename""#));
184 assert!(!json.contains("event_type"));
185 }
186}