Message¶
1. 结构定位¶
1.1 核心作用¶
Message 是系统的核心数据结构,定义了消息在系统内部流转的标准格式,是所有组件之间通信的"通用语言"。
一句话定义:Message 是 gort 系统中消息的"标准信封",所有组件通过它传递信息。
1.2 设计目标¶
| 目标 | 说明 |
|---|---|
| 统一格式 | 屏蔽不同平台的消息格式差异 |
| 信息完整 | 包含消息处理所需的所有信息 |
| 可扩展 | 通过 Metadata 支持平台特定字段 |
| 易于序列化 | 支持 JSON 序列化,便于传输和存储 |
1.3 使用范围¶
graph TB
subgraph "Message 使用范围"
CH[Channel]
GW[Gateway]
MW[Middleware]
SM[SessionManager]
BL[业务层]
end
MSG[Message]
CH --> MSG
GW --> MSG
MW --> MSG
SM --> MSG
BL --> MSG
style MSG fill:#9f9
2. 设计决策¶
2.1 为什么需要标准消息格式?¶
问题背景: - 不同平台消息格式差异巨大 - 组件之间需要统一的数据结构 - 需要支持消息的双向流转
各平台消息格式对比:
graph LR
subgraph "微信消息格式"
W1["<xml><ToUserName>...</ToUserName><FromUserName>...</FromUserName><Content>...</Content></xml>"]
end
subgraph "钉钉消息格式"
D1["{msgtype: text, text: {content: ...}, senderNick: ...}"]
end
subgraph "飞书消息格式"
F1["{event: {sender: ..., message: {content: ...}}}"]
end
subgraph "标准 Message ✅"
S1["{id, channel_id, from, to, content, type, ...}"]
end
style S1 fill:#9f9
2.2 为什么使用扁平结构?¶
决策:Message 使用扁平结构,而非深层嵌套。
graph TB
subgraph "扁平结构 ✅"
A1["Message"]
A2["id: string"]
A3["channel_id: string"]
A4["from: UserInfo"]
A5["content: string"]
A6["type: MessageType"]
end
A1 --> A2
A1 --> A3
A1 --> A4
A1 --> A5
A1 --> A6
style A1 fill:#9f9
理由: 1. 易于访问:直接访问字段,无需多层导航 2. 易于序列化:JSON 结构简单 3. 易于调试:日志输出清晰
2.3 为什么需要 Direction 字段?¶
决策:Message 包含 Direction 字段区分消息方向。
graph LR
subgraph "入站 Inbound"
I1[外部平台] --> I2[Channel] --> I3[Gateway] --> I4[客户端]
end
subgraph "出站 Outbound"
O1[客户端] --> O2[Gateway] --> O3[Channel] --> O4[外部平台]
end
理由: 1. 路由决策:中间件可根据方向做不同处理 2. 日志追踪:便于区分消息来源 3. 业务逻辑:业务层可针对方向做不同响应
3. 结构定义¶
3.1 Message 结构¶
// Message 标准消息格式
type Message struct {
ID string `json:"id"` // 消息唯一标识
ChannelID string `json:"channel_id"` // 来源/目标渠道
Direction Direction `json:"direction"` // 消息方向
From UserInfo `json:"from"` // 发送者信息
To UserInfo `json:"to"` // 接收者信息
Content string `json:"content"` // 消息内容
Type MessageType `json:"type"` // 消息类型
Metadata map[string]interface{} `json:"metadata"` // 扩展元数据
Timestamp time.Time `json:"timestamp"` // 时间戳
}
3.2 UserInfo 结构¶
// UserInfo 用户信息
type UserInfo struct {
ID string `json:"id"` // 平台用户 ID
Name string `json:"name"` // 显示名称
Avatar string `json:"avatar"` // 头像 URL
Platform string `json:"platform"` // 所属平台
}
3.3 枚举类型¶
// Direction 消息方向
type Direction string
const (
DirectionInbound Direction = "inbound" // 入站:外部 → 系统
DirectionOutbound Direction = "outbound" // 出站:系统 → 外部
)
// MessageType 消息类型
type MessageType string
const (
MessageTypeText MessageType = "text" // 文本消息
MessageTypeImage MessageType = "image" // 图片消息
MessageTypeFile MessageType = "file" // 文件消息
MessageTypeAudio MessageType = "audio" // 语音消息
MessageTypeVideo MessageType = "video" // 视频消息
MessageTypeEvent MessageType = "event" // 事件消息
)
4. 字段设计说明¶
4.1 核心字段¶
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
ID |
string | 是 | 消息唯一标识,用于追踪和去重 |
ChannelID |
string | 是 | 渠道标识,用于路由到正确的 Channel |
Direction |
Direction | 是 | 消息方向,区分入站/出站 |
From |
UserInfo | 是 | 发送者信息 |
To |
UserInfo | 否 | 接收者信息(群聊时使用) |
Content |
string | 是 | 消息内容 |
Type |
MessageType | 是 | 消息类型 |
Timestamp |
time.Time | 是 | 消息时间戳 |
4.2 扩展字段¶
| 字段 | 类型 | 说明 |
|---|---|---|
Metadata |
map | 平台特定字段,如微信的 MsgId、钉钉的 MsgType |
4.3 Metadata 使用场景¶
| 平台 | Metadata 字段 |
|---|---|
| 微信 | msg_id, msg_type, create_time |
| 钉钉 | msgtype, sessionWebhook, conversationType |
| 飞书 | event_type, chat_id, message_id |
5. 消息流转¶
5.1 入站消息转换¶
sequenceDiagram
participant EP as 外部平台
participant CH as Channel
participant MSG as Message
EP->>CH: 平台协议消息
CH->>MSG: 构建 Message
Note over MSG: ID = generateID()
ChannelID = "wechat"
Direction = Inbound
From = 解析发送者
Content = 解析内容
Type = 解析类型
Metadata = 平台字段
5.2 出站消息转换¶
sequenceDiagram
participant MSG as Message
participant CH as Channel
participant EP as 外部平台
MSG->>CH: SendMessage(msg)
CH->>CH: 根据 ChannelID 选择渠道
CH->>CH: 根据 Type 选择发送方式
CH->>EP: 平台 API 调用
6. 与其他模块的关系¶
6.1 依赖关系¶
graph TB
MSG[Message]
MSG --> UID[UserInfo]
MSG --> DIR[Direction]
MSG --> MT[MessageType]
style MSG fill:#9f9
6.2 使用方式¶
| 模块 | 创建 Message | 消费 Message |
|---|---|---|
| Channel | 入站时创建 | 出站时消费 |
| Gateway | 不创建 | 路由时消费 |
| Middleware | 不创建 | 处理时消费 |
| SessionManager | 不创建 | 推送时消费 |
| 业务层 | 出站时创建 | 入站时消费 |
7. 约束与限制¶
7.1 字段约束¶
| 约束 | 说明 |
|---|---|
ID 必须唯一 |
用于消息追踪和去重 |
ChannelID 必须对应已注册渠道 |
否则路由失败 |
Content 不能为空 |
空消息无意义 |
Timestamp 使用 UTC 时间 |
保证时区一致性 |
7.2 序列化约束¶
| 约束 | 说明 |
|---|---|
| 使用 JSON 序列化 | 便于传输和日志 |
| Metadata 值必须是可序列化类型 | 避免序列化失败 |
| 时间使用 RFC3339 格式 | 标准时间格式 |
8. 扩展设计¶
8.1 支持的消息类型¶
graph TB
MT[MessageType]
MT --> Text[Text 文本]
MT --> Image[Image 图片]
MT --> File[File 文件]
MT --> Audio[Audio 语音]
MT --> Video[Video 视频]
MT --> Event[Event 事件]
8.2 扩展消息类型¶
新增消息类型只需添加常量:
const (
MessageTypeLocation MessageType = "location" // 位置消息
MessageTypeContact MessageType = "contact" // 名片消息
)
9. 使用示例¶
9.1 入站消息示例¶
msg := &Message{
ID: "msg_123456",
ChannelID: "wechat",
Direction: DirectionInbound,
From: UserInfo{
ID: "wx_user_001",
Name: "张三",
Platform: "wechat",
},
Content: "你好",
Type: MessageTypeText,
Metadata: map[string]interface{}{
"msg_id": "1234567890",
"msg_type": "text",
"create_time": 1234567890,
},
Timestamp: time.Now(),
}
9.2 出站消息示例¶
msg := &Message{
ID: "msg_789012",
ChannelID: "dingtalk",
Direction: DirectionOutbound,
From: UserInfo{
ID: "system",
Name: "AI助手",
Platform: "gort",
},
To: UserInfo{
ID: "dt_user_001",
Name: "李四",
Platform: "dingtalk",
},
Content: "收到你的消息",
Type: MessageTypeText,
Timestamp: time.Now(),
}
10. 相关文档¶
- 01-gateway.md - Gateway 模块设计
- 02-channel.md - Channel 模块设计
- 03-session-manager.md - SessionManager 模块设计
- 04-middleware.md - Middleware 模块设计