1use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
31pub enum GlobalMessage {
32 Direct {
34 sender: String,
36 recipient: String,
38 content: MessageContent,
40 },
41
42 Broadcast {
44 sender: String,
46 topic: String,
48 content: MessageContent,
50 },
51
52 Request {
54 sender: String,
56 recipient: String,
58 request_id: String,
60 content: MessageContent,
62 expect_reply: bool,
64 },
65
66 Response {
68 responder: String,
70 request_id: String,
72 content: MessageContent,
74 },
75
76 PubSub {
78 publisher: String,
80 topic: String,
82 content: MessageContent,
84 },
85}
86
87impl GlobalMessage {
88 pub fn sender(&self) -> &str {
90 match self {
91 Self::Direct { sender, .. }
92 | Self::Broadcast { sender, .. }
93 | Self::Request { sender, .. } => sender,
94 Self::Response { responder, .. } => responder,
95 Self::PubSub { publisher, .. } => publisher,
96 }
97 }
98
99 pub fn message_type(&self) -> &'static str {
101 match self {
102 Self::Direct { .. } => "direct",
103 Self::Broadcast { .. } => "broadcast",
104 Self::Request { .. } => "request",
105 Self::Response { .. } => "response",
106 Self::PubSub { .. } => "pubsub",
107 }
108 }
109
110 pub fn direct(
112 sender: impl Into<String>,
113 recipient: impl Into<String>,
114 content: MessageContent,
115 ) -> Self {
116 Self::Direct {
117 sender: sender.into(),
118 recipient: recipient.into(),
119 content,
120 }
121 }
122
123 pub fn broadcast(
125 sender: impl Into<String>,
126 topic: impl Into<String>,
127 content: MessageContent,
128 ) -> Self {
129 Self::Broadcast {
130 sender: sender.into(),
131 topic: topic.into(),
132 content,
133 }
134 }
135
136 pub fn request(
138 sender: impl Into<String>,
139 recipient: impl Into<String>,
140 request_id: impl Into<String>,
141 content: MessageContent,
142 ) -> Self {
143 Self::Request {
144 sender: sender.into(),
145 recipient: recipient.into(),
146 request_id: request_id.into(),
147 content,
148 expect_reply: true,
149 }
150 }
151
152 pub fn response(
154 responder: impl Into<String>,
155 request_id: impl Into<String>,
156 content: MessageContent,
157 ) -> Self {
158 Self::Response {
159 responder: responder.into(),
160 request_id: request_id.into(),
161 content,
162 }
163 }
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
174pub enum MessageContent {
175 Text(String),
177
178 Json(serde_json::Value),
180
181 Binary(Vec<u8>),
183
184 Structured {
186 msg_type: String,
188 data: serde_json::Value,
190 },
191}
192
193impl MessageContent {
194 pub fn text(text: impl Into<String>) -> Self {
196 Self::Text(text.into())
197 }
198
199 pub fn json(value: serde_json::Value) -> Self {
201 Self::Json(value)
202 }
203
204 pub fn binary(data: Vec<u8>) -> Self {
206 Self::Binary(data)
207 }
208
209 pub fn structured(msg_type: impl Into<String>, data: serde_json::Value) -> Self {
211 Self::Structured {
212 msg_type: msg_type.into(),
213 data,
214 }
215 }
216
217 pub fn to_text(&self) -> String {
219 match self {
220 Self::Text(s) => s.clone(),
221 Self::Json(v) => v.to_string(),
222 Self::Binary(b) => format!("[binary {} bytes]", b.len()),
223 Self::Structured { msg_type, data } => format!("{}: {}", msg_type, data),
224 }
225 }
226
227 pub fn as_text(&self) -> Option<&str> {
229 match self {
230 Self::Text(s) => Some(s),
231 _ => None,
232 }
233 }
234
235 pub fn as_json(&self) -> Option<&serde_json::Value> {
237 match self {
238 Self::Json(v) => Some(v),
239 Self::Structured { data, .. } => Some(data),
240 _ => None,
241 }
242 }
243
244 pub fn as_binary(&self) -> Option<&[u8]> {
246 match self {
247 Self::Binary(b) => Some(b),
248 _ => None,
249 }
250 }
251}
252
253impl From<String> for MessageContent {
254 fn from(s: String) -> Self {
255 Self::Text(s)
256 }
257}
258
259impl From<&str> for MessageContent {
260 fn from(s: &str) -> Self {
261 Self::Text(s.to_string())
262 }
263}
264
265impl From<serde_json::Value> for MessageContent {
266 fn from(v: serde_json::Value) -> Self {
267 Self::Json(v)
268 }
269}
270
271impl From<Vec<u8>> for MessageContent {
272 fn from(v: Vec<u8>) -> Self {
273 Self::Binary(v)
274 }
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct MessageMetadata {
286 pub id: String,
288
289 pub timestamp: u64,
291
292 pub properties: HashMap<String, String>,
294}
295
296impl Default for MessageMetadata {
297 fn default() -> Self {
298 Self {
299 id: uuid::Uuid::new_v4().to_string(),
300 timestamp: std::time::SystemTime::now()
301 .duration_since(std::time::UNIX_EPOCH)
302 .unwrap()
303 .as_millis() as u64,
304 properties: HashMap::new(),
305 }
306 }
307}
308
309impl MessageMetadata {
310 pub fn new() -> Self {
312 Self::default()
313 }
314
315 pub fn with_property(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
317 self.properties.insert(key.into(), value.into());
318 self
319 }
320}
321
322#[cfg(test)]
327mod tests {
328 use super::*;
329
330 #[test]
331 fn test_message_content_text() {
332 let content = MessageContent::text("Hello, World!");
333 assert_eq!(content.as_text(), Some("Hello, World!"));
334 assert_eq!(content.to_text(), "Hello, World!");
335 }
336
337 #[test]
338 fn test_message_content_json() {
339 let json = serde_json::json!({ "key": "value" });
340 let content = MessageContent::json(json.clone());
341 assert_eq!(content.as_json(), Some(&json));
342 }
343
344 #[test]
345 fn test_global_message_direct() {
346 let msg = GlobalMessage::direct("agent1", "agent2", MessageContent::text("test"));
347 assert_eq!(msg.sender(), "agent1");
348 assert_eq!(msg.message_type(), "direct");
349 }
350
351 #[test]
352 fn test_global_message_request_response() {
353 let request =
354 GlobalMessage::request("client", "server", "req-123", MessageContent::text("ping"));
355
356 let response = GlobalMessage::response("server", "req-123", MessageContent::text("pong"));
357
358 assert_eq!(request.message_type(), "request");
359 assert_eq!(response.message_type(), "response");
360 }
361
362 #[test]
363 fn test_message_from_conversions() {
364 let _: MessageContent = "hello".into();
365 let _: MessageContent = String::from("world").into();
366 let _: MessageContent = serde_json::json!(42).into();
367 let _: MessageContent = vec![1, 2, 3].into();
368 }
369}