Skip to main content

mofa_kernel/agent/types/
global.rs

1//! 全局消息协议
2//!
3//! 本模块提供全局抽象消息协议,用于替代多个重复的 AgentMessage 定义。
4//!
5//! # 设计目标
6//!
7//! - 提供单一的消息类型,避免多处重复定义
8//! - 支持多种通信模式(点对点、广播、请求-响应、发布-订阅)
9//! - 支持多种内容格式(文本、JSON、二进制、结构化数据)
10//! - 类型安全且可序列化
11
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14
15// ============================================================================
16// GlobalMessage - 全局消息类型
17// ============================================================================
18
19/// 全局消息类型
20///
21/// 替代多处重复的 `AgentMessage` 定义,提供全局消息抽象。
22///
23/// # 消息模式
24///
25/// - `Direct`: 点对点直接消息
26/// - `Broadcast`: 广播消息到所有订阅者
27/// - `Request`: 请求消息(期待响应)
28/// - `Response`: 响应消息
29/// - `PubSub`: 发布-订阅模式
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub enum GlobalMessage {
32    /// 点对点直接消息
33    Direct {
34        /// 发送者 ID
35        sender: String,
36        /// 接收者 ID
37        recipient: String,
38        /// 消息内容
39        content: MessageContent,
40    },
41
42    /// 广播消息
43    Broadcast {
44        /// 发送者 ID
45        sender: String,
46        /// 主题
47        topic: String,
48        /// 消息内容
49        content: MessageContent,
50    },
51
52    /// 请求消息(期待响应)
53    Request {
54        /// 发送者 ID
55        sender: String,
56        /// 接收者 ID
57        recipient: String,
58        /// 请求 ID(用于匹配响应)
59        request_id: String,
60        /// 消息内容
61        content: MessageContent,
62        /// 是否期待响应
63        expect_reply: bool,
64    },
65
66    /// 响应消息
67    Response {
68        /// 响应者 ID
69        responder: String,
70        /// 请求 ID(用于匹配原始请求)
71        request_id: String,
72        /// 消息内容
73        content: MessageContent,
74    },
75
76    /// 发布-订阅消息
77    PubSub {
78        /// 发布者 ID
79        publisher: String,
80        /// 主题
81        topic: String,
82        /// 消息内容
83        content: MessageContent,
84    },
85}
86
87impl GlobalMessage {
88    /// 获取消息发送者 ID
89    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    /// 获取消息类型标识
100    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    /// 创建点对点消息
111    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    /// 创建广播消息
124    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    /// 创建请求消息
137    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    /// 创建响应消息
153    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// ============================================================================
167// MessageContent - 消息内容
168// ============================================================================
169
170/// 消息内容类型
171///
172/// 支持多种内容格式,提供灵活的消息传递能力。
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub enum MessageContent {
175    /// 纯文本内容
176    Text(String),
177
178    /// JSON 数据
179    Json(serde_json::Value),
180
181    /// 二进制数据
182    Binary(Vec<u8>),
183
184    /// 结构化数据(带类型标识)
185    Structured {
186        /// 消息类型标识
187        msg_type: String,
188        /// 数据
189        data: serde_json::Value,
190    },
191}
192
193impl MessageContent {
194    /// 创建文本内容
195    pub fn text(text: impl Into<String>) -> Self {
196        Self::Text(text.into())
197    }
198
199    /// 创建 JSON 内容
200    pub fn json(value: serde_json::Value) -> Self {
201        Self::Json(value)
202    }
203
204    /// 创建二进制内容
205    pub fn binary(data: Vec<u8>) -> Self {
206        Self::Binary(data)
207    }
208
209    /// 创建结构化内容
210    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    /// 转换为文本表示
218    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    /// 尝试获取文本内容
228    pub fn as_text(&self) -> Option<&str> {
229        match self {
230            Self::Text(s) => Some(s),
231            _ => None,
232        }
233    }
234
235    /// 尝试获取 JSON 内容
236    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    /// 尝试获取二进制内容
245    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// ============================================================================
278// MessageMetadata - 消息元数据
279// ============================================================================
280
281/// 消息元数据
282///
283/// 用于携带额外的消息属性。
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct MessageMetadata {
286    /// 消息 ID
287    pub id: String,
288
289    /// 时间戳(毫秒)
290    pub timestamp: u64,
291
292    /// 自定义属性
293    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    /// 创建新的元数据
311    pub fn new() -> Self {
312        Self::default()
313    }
314
315    /// 添加属性
316    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// ============================================================================
323// Tests
324// ============================================================================
325
326#[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}