Channel¶
1. 模块定位¶
1.1 核心作用¶
Channel 是协议适配器,负责将外部 IM 平台(微信、钉钉、飞书等)的异构协议转换为系统内部的标准消息格式。
一句话定义:Channel 是外部平台与 gort 之间的"翻译官",负责协议转换和消息标准化。
1.2 设计目标¶
| 目标 | 说明 |
|---|---|
| 协议适配 | 将各平台的 Webhook 协议转换为标准 Message |
| 签名验证 | 验证来自平台的请求签名,确保安全性 |
| 消息标准化 | 屏蔽平台差异,向上提供统一接口 |
| 可扩展 | 新增平台只需实现 Channel 接口 |
1.3 职责边界¶
graph TB
subgraph "Channel 职责范围"
subgraph "✅ 负责"
A1[接收 Webhook 请求]
A2[验证平台签名]
A3[解析平台协议]
A4[转换为标准 Message]
A5[发送消息到平台 API]
end
subgraph "❌ 不负责"
B1[消息路由决策]
B2[业务逻辑处理]
B3[WebSocket 连接管理]
B4[消息持久化]
end
end
2. 设计决策¶
2.1 为什么需要 Channel 抽象?¶
问题背景: - 不同 IM 平台协议差异巨大 - 微信、钉钉、飞书的 Webhook 格式各不相同 - 签名验证逻辑各平台独立
没有 Channel 抽象的情况:
graph LR
WX[微信] --> GW[Gateway]
DT[钉钉] --> GW
FS[飞书] --> GW
subgraph "Gateway 内部"
WX1[微信协议解析]
DT1[钉钉协议解析]
FS1[飞书协议解析]
WX2[微信签名验证]
DT2[钉钉签名验证]
FS2[飞书签名验证]
end
style GW fill:#f99
问题:Gateway 承担过多职责,难以维护和扩展
有 Channel 抽象的情况:
graph TB
subgraph "外部平台"
WX[微信]
DT[钉钉]
FS[飞书]
end
subgraph "Channel 层"
WC[WeChatChannel]
DC[DingTalkChannel]
FC[FeishuChannel]
end
subgraph "核心"
GW[Gateway]
end
WX --> WC
DT --> DC
FS --> FC
WC --> GW
DC --> GW
FC --> GW
style GW fill:#9f9
优势:协议适配逻辑隔离,Gateway 只处理标准消息
2.2 为什么使用 Webhook 模式?¶
决策:Channel 作为 Webhook 接收端,被动接收平台推送的消息。
sequenceDiagram
participant EP as 外部平台
participant WH as Channel Webhook
participant CH as Channel
EP->>WH: HTTP POST (消息推送)
WH->>CH: 触发处理
CH->>CH: 验证签名
CH->>CH: 解析协议
CH-->>EP: HTTP 200 OK
理由: | 模式 | 优点 | 缺点 | | --------------- | ------------------ | ------------------ | | Webhook(推送) | 实时性好,无需轮询 | 需要公网可访问地址 | | 轮询(拉取) | 无需公网地址 | 延迟高,资源浪费 |
选择 Webhook 的原因: 1. 主流 IM 平台都支持 Webhook 2. 消息实时性对聊天场景至关重要 3. 桌面 App 可通过内网穿透解决公网访问问题
2.3 为什么 Channel 不持有 HTTP 服务器?¶
决策:Channel 只定义 Webhook 处理逻辑,HTTP 服务器由 Gateway 统一管理。
graph TB
subgraph "Gateway"
HTTP[HTTP Server :8080]
end
subgraph "Channel 注册路由"
R1["/webhook/wechat"]
R2["/webhook/dingtalk"]
R3["/webhook/feishu"]
end
WC[WeChatChannel]
DC[DingTalkChannel]
FC[FeishuChannel]
HTTP --> R1 --> WC
HTTP --> R2 --> DC
HTTP --> R3 --> FC
style HTTP fill:#9f9
理由: 1. 简化配置:只需开放一个 HTTP 端口 2. 统一管理:日志、监控、安全控制集中处理 3. 解耦:Channel 不关心 HTTP 服务器细节
3. 接口契约¶
3.1 Channel 接口¶
// Channel 协议适配器接口
type Channel interface {
// 基本信息
Name() string // 渠道名称,如 "wechat"
Type() ChannelType // 渠道类型枚举
// 生命周期
Start(ctx context.Context, handler MessageHandler) error
Stop(ctx context.Context) error
IsRunning() bool
// 消息发送(出站)
SendMessage(ctx context.Context, msg *Message) error
// 状态查询
GetStatus() ChannelStatus
}
// MessageHandler 消息处理回调
type MessageHandler func(ctx context.Context, msg *Message) error
// WebhookHandler Webhook 处理接口(可选实现)
type WebhookHandler interface {
HandleWebhook(w http.ResponseWriter, r *http.Request)
}
3.2 接口设计说明¶
| 方法 | 调用时机 | 行为约定 |
|---|---|---|
Name() |
任意时刻 | 返回唯一标识符,用于路由 |
Start() |
Gateway 启动时 | 注入消息处理器,初始化资源 |
Stop() |
Gateway 停止时 | 释放资源,等待进行中的请求完成 |
SendMessage() |
出站消息时 | 将标准 Message 转换为平台格式并发送 |
HandleWebhook() |
收到 Webhook 时 | 验证签名、解析协议、调用处理器 |
3.3 渠道类型枚举¶
type ChannelType string
const (
ChannelTypeWeChat ChannelType = "wechat"
ChannelTypeDingTalk ChannelType = "dingtalk"
ChannelTypeFeishu ChannelType = "feishu"
ChannelTypeTelegram ChannelType = "telegram"
ChannelTypeMock ChannelType = "mock" // 用于测试
)
4. 消息转换设计¶
4.1 入站消息转换¶
sequenceDiagram
participant EP as 外部平台
participant WH as Webhook Handler
participant CH as Channel
participant MH as MessageHandler
EP->>WH: HTTP POST (平台协议)
WH->>CH: HandleWebhook()
CH->>CH: 1. 验证签名
CH->>CH: 2. 解析平台协议
CH->>CH: 3. 构建标准 Message
Note over CH: Message {
ChannelID: "wechat",
From: UserInfo,
Content: "...",
Type: "text"
}
CH->>MH: handler(ctx, msg)
MH-->>CH: error
CH-->>WH: HTTP Response
4.2 出站消息转换¶
sequenceDiagram
participant GW as Gateway
participant CH as Channel
participant API as 平台 API
participant EP as 外部平台
GW->>CH: SendMessage(ctx, msg)
CH->>CH: 1. 验证消息有效性
CH->>CH: 2. 转换为平台格式
CH->>CH: 3. 构建请求参数
CH->>API: HTTP POST (平台 API)
API->>EP: 推送消息
API-->>CH: HTTP Response
CH-->>GW: error
4.3 标准消息格式¶
type Message struct {
ID string // 消息唯一 ID
ChannelID string // 来源/目标渠道
Direction Direction // inbound/outbound
From UserInfo // 发送者信息
To UserInfo // 接收者信息
Content string // 消息内容
Type MessageType // text/image/file
Metadata map[string]any // 平台特定元数据
Timestamp time.Time // 时间戳
}
type UserInfo struct {
ID string // 平台用户 ID
Name string // 显示名称
Avatar string // 头像 URL
Platform string // 所属平台
}
5. 与其他模块的关系¶
5.1 依赖关系¶
graph TB
CH[Channel]
CH --> MSG[Message
标准消息格式]
CH --> CFG[Config
渠道配置]
GW[Gateway] --> CH
style CH fill:#9f9
5.2 交互方式¶
| 交互方 | 交互方式 | 说明 |
|---|---|---|
| Gateway | 被管理 | Gateway 调用 Start/Stop |
| Gateway | 回调注入 | 启动时注入 MessageHandler |
| 外部平台 | Webhook | 接收 HTTP POST 请求 |
| 外部平台 | API 调用 | 发送消息时调用平台 API |
6. 约束与限制¶
6.1 实现约束¶
| 约束 | 原因 |
|---|---|
必须实现 Name() 返回唯一标识 |
用于路由和日志 |
SendMessage 必须是线程安全的 |
可能被多个 goroutine 调用 |
| Webhook 处理必须快速返回 | 避免平台超时重试 |
6.2 平台限制¶
| 平台 | 限制 |
|---|---|
| 微信 | 5 秒内必须响应,消息加密 |
| 钉钉 | 签名验证必需,回调地址需配置 |
| 飞书 | 事件订阅需验证 URL |
6.3 错误处理约定¶
| 错误类型 | 处理方式 |
|---|---|
| 签名验证失败 | 返回 HTTP 401 |
| 协议解析失败 | 返回 HTTP 400 |
| 处理器调用失败 | 记录日志,返回 HTTP 500 |
| API 调用失败 | 内部重试 3 次,记录日志 |
7. 扩展指南¶
7.1 新增渠道步骤¶
flowchart TB
A[1. 定义渠道类型常量] --> B[2. 实现 Channel 接口]
B --> C[3. 实现 WebhookHandler 接口]
C --> D[4. 实现签名验证逻辑]
D --> E[5. 实现协议解析逻辑]
E --> F[6. 实现 SendMessage 方法]
F --> G[7. 注册到 Gateway]
7.2 实现检查清单¶
| 检查项 | 说明 |
|---|---|
☐ 实现 Name() 返回唯一标识 |
|
☐ 实现 Type() 返回渠道类型 |
|
☐ 实现 Start() 注入处理器 |
|
☐ 实现 Stop() 清理资源 |
|
☐ 实现 HandleWebhook() 处理 Webhook |
|
☐ 实现 SendMessage() 发送消息 |
|
| ☐ 实现签名验证 | 安全必需 |
| ☐ 处理平台特定错误码 | |
| ☐ 编写单元测试 |
8. 使用场景¶
8.1 微信渠道示例¶
sequenceDiagram
participant U as 微信用户
participant WX as 微信服务器
participant WC as WeChatChannel
participant GW as Gateway
U->>WX: 发送消息
WX->>WC: POST /webhook/wechat
Note right of WC: 签名验证
Note right of WC: XML 解析
Note right of WC: 构建 Message
WC->>GW: handler(ctx, msg)
GW-->>WC: 处理完成
WC-->>WX: 200 OK
8.2 钉钉渠道示例¶
sequenceDiagram
participant U as 钉钉用户
participant DT as 钉钉服务器
participant DC as DingTalkChannel
participant GW as Gateway
U->>DT: 发送消息
DT->>DC: POST /webhook/dingtalk
Note right of DC: 签名验证
Note right of DC: JSON 解析
Note right of DC: 构建 Message
DC->>GW: handler(ctx, msg)
GW-->>DC: 处理完成
DC-->>DT: 200 OK
9. 相关文档¶
- 01-gateway.md - Gateway 模块设计
- 05-message.md - Message 数据结构
- 06-config.md - 配置管理