Gateway¶
1. 模块定位¶
1.1 核心作用¶
Gateway 是 gort 的核心协调器,作为整个系统的中枢,负责协调各组件协同工作。
一句话定义:Gateway 是消息的"交通指挥官",负责将消息从来源正确地路由到目的地。
1.2 设计目标¶
| 目标 | 说明 |
|---|---|
| 统一入口 | 所有外部消息通过 Gateway 进入系统 |
| 协调分发 | 协调 Channel、SessionManager、业务层之间的消息流转 |
| 生命周期管理 | 管理所有组件的启动和停止顺序 |
| 解耦组件 | 各组件通过 Gateway 交互,不直接依赖 |
1.3 职责边界¶
graph TB
subgraph "Gateway 职责范围"
subgraph "✅ 负责"
A1[接收 Channel 转发的消息]
A2[接收客户端消息]
A3[管理 Channel 注册和生命周期]
A4[管理 HTTP/WebSocket 服务器]
A5[协调中间件链执行]
end
subgraph "❌ 不负责"
B1[具体协议解析 - Channel]
B2[WebSocket 连接维护 - SessionManager]
B3[业务逻辑处理 - 业务层]
B4[消息持久化存储]
end
end
2. 设计决策¶
2.1 为什么需要 Gateway?¶
问题背景: - 多个 Channel(微信、钉钉、飞书)需要统一接入 - 多个 WebSocket 客户端需要接收消息 - 消息需要在 Channel 和客户端之间双向流转
没有 Gateway 的情况:
graph LR
WC[微信 Channel] <--> DC[钉钉 Channel]
DC <--> FC[飞书 Channel]
WC <--> WS[WebSocket 客户端]
DC <--> WS
FC <--> WS
style WC fill:#f99
style DC fill:#f99
style FC fill:#f99
style WS fill:#f99
问题:组件之间直接依赖,耦合严重,难以扩展
有 Gateway 的情况:
graph TB
subgraph "外部渠道"
WC[微信 Channel]
DC[钉钉 Channel]
FC[飞书 Channel]
end
subgraph "核心"
GW[Gateway]
end
subgraph "客户端"
WS[WebSocket 客户端]
end
subgraph "业务"
BH[业务层 Handler]
end
WC --> GW
DC --> GW
FC --> GW
GW <--> WS
GW --> BH
style GW fill:#9f9
优势:所有组件通过 Gateway 交互,职责清晰,易于扩展
2.2 为什么使用统一 HTTP 服务器?¶
决策:所有 Channel 共享一个 HTTP 服务器,通过路径区分不同渠道。
方案对比:
graph LR
subgraph "方案A: 独立端口"
A1[微信 :8080]
A2[钉钉 :8081]
A3[飞书 :8082]
end
subgraph "方案B: 统一服务器 ✅"
B1[HTTP :8080]
B2["/webhook/wechat"]
B3["/webhook/dingtalk"]
B4["/webhook/feishu"]
B1 --> B2
B1 --> B3
B1 --> B4
end
style B1 fill:#9f9
| 方案 | 优点 | 缺点 |
|---|---|---|
| 独立端口 | 隔离性好 | 防火墙配置复杂,端口管理困难 |
| 统一服务器 ✅ | 只需开放一个端口,配置简单 | 需要路径路由 |
选择统一服务器的原因: 1. 桌面 App 场景下,简化网络配置更重要 2. 路径路由是成熟模式,实现简单 3. 便于统一日志、监控、安全控制
2.3 为什么使用回调模式注入 Handler?¶
决策:Channel 启动时通过参数注入消息处理器,而非后续设置。
sequenceDiagram
participant GW as Gateway
participant CH as Channel
Note over GW,CH: ✅ 采用的方式
GW->>CH: Start(ctx, handler)
Note right of CH: handler 是必需参数
不会遗漏
Note over GW,CH: ❌ 不采用的方式
GW->>CH: Start(ctx)
Note right of CH: 可能忘记设置 handler
GW--xCH: SetOnMessage(handler)?
Note right of CH: 设置时机不确定
理由: 1. 避免状态不一致:启动时必须提供 handler,不会遗漏 2. 明确依赖关系:handler 是 Channel 运行的必要条件 3. 简化生命周期:不需要管理 handler 的设置时机
3. 接口契约¶
3.1 核心接口¶
// Gateway 网关接口
type Gateway interface {
// 生命周期
Start(ctx context.Context) error
Stop(ctx context.Context) error
IsRunning() bool
// Channel 管理
RegisterChannel(channel Channel) error
GetChannel(name string) (Channel, bool)
// 消息处理
HandleChannelMessage(ctx context.Context, msg *Message) error
HandleClientMessage(ctx context.Context, clientID string, msg *Message) error
// 业务处理器注册
RegisterClientHandler(handler ClientHandler)
RegisterChannelHandler(handler ChannelHandler)
// 中间件
Use(middleware Middleware)
// 状态查询
GetClientCount() int
}
3.2 接口设计说明¶
| 方法 | 调用时机 | 行为约定 |
|---|---|---|
RegisterChannel |
Start 之前 | 注册 Channel,重复注册返回错误 |
Start |
初始化完成后 | 启动所有组件,失败时自动回滚 |
Stop |
收到关闭信号 | 等待消息处理完成,超时强制关闭 |
HandleChannelMessage |
Channel 收到消息 | 执行中间件 → 业务处理 → 推送客户端 |
HandleClientMessage |
客户端发送消息 | 执行中间件 → 业务处理 → 发送到 Channel |
3.3 配置项¶
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Name |
string | "gort-gateway" | 网关名称,用于日志标识 |
HTTPAddr |
string | ":8080" | HTTP 服务监听地址 |
WebSocketAddr |
string | ":9000" | WebSocket 服务监听地址 |
ReadTimeout |
duration | 30s | 读取超时 |
WriteTimeout |
duration | 30s | 写入超时 |
4. 消息流转设计¶
4.1 入站消息流程¶
来源:外部 IM 平台(微信、钉钉等) 目的地:WebSocket 客户端
sequenceDiagram
participant EP as 外部平台
participant WH as Webhook
participant CH as Channel
participant GW as Gateway
participant MW as 中间件链
participant BH as ChannelHandler
participant SM as SessionManager
participant WS as WebSocket客户端
EP->>WH: HTTP POST
WH->>CH: 触发 Webhook
CH->>CH: 协议解析
CH->>GW: HandleChannelMessage(msg)
GW->>MW: 执行中间件链
MW-->>GW: 继续
GW->>BH: 业务处理
BH-->>GW: 返回响应消息
GW->>SM: Broadcast(response)
SM->>WS: WebSocket 推送
设计要点: - 中间件按注册顺序执行 - 业务 Handler 可返回 nil 表示无需响应 - 广播失败记录日志,不中断流程
4.2 出站消息流程¶
来源:WebSocket 客户端 目的地:外部 IM 平台
sequenceDiagram
participant WS as WebSocket客户端
participant SM as SessionManager
participant GW as Gateway
participant MW as 中间件链
participant BH as ClientHandler
participant CH as Channel
participant EP as 外部平台
WS->>SM: 发送消息
SM->>GW: HandleClientMessage(clientID, msg)
GW->>MW: 执行中间件链
MW-->>GW: 继续
GW->>BH: 业务处理
BH-->>GW: 返回响应消息
GW->>CH: SendMessage(msg)
CH->>CH: 转换为平台格式
CH->>EP: HTTP POST/API 调用
EP-->>CH: 响应
设计要点: - 消息必须指定目标 ChannelID - Channel 不存在时返回错误 - 发送失败由 Channel 内部重试
5. 与其他模块的关系¶
5.1 依赖关系¶
graph TB
GW[Gateway]
GW --> CH[Channel
协议适配]
GW --> SM[SessionManager
连接管理]
GW --> MW[Middleware
横切处理]
BL[业务层] --> GW
style GW fill:#9f9
5.2 交互方式¶
| 交互方 | 交互方式 | 说明 |
|---|---|---|
| Channel | 回调注入 | Channel 启动时注入消息处理器 |
| SessionManager | 直接持有 | Gateway 创建并管理 SessionManager |
| Middleware | 链式调用 | 按注册顺序执行中间件 |
| 业务层 | Handler 注册 | 业务层注册处理函数 |
6. 约束与限制¶
6.1 使用约束¶
| 约束 | 原因 |
|---|---|
RegisterChannel 必须在 Start 之前调用 |
启动时需要知道所有 Channel |
Stop 后不能重新 Start |
简化生命周期管理 |
| 消息处理是异步的 | 避免阻塞调用方 |
6.2 性能限制¶
| 限制 | 说明 |
|---|---|
| 单实例运行 | 不支持分布式部署 |
| 内存级转发 | 消息不持久化 |
| 无内置限流 | 依赖外部平台限制 |
6.3 错误处理约定¶
| 错误类型 | 处理方式 |
|---|---|
| 启动失败 | 返回错误,已启动组件自动回滚 |
| 消息处理失败 | 记录日志,不影响其他消息 |
| Channel 发送失败 | 由 Channel 内部重试 |
7. 扩展点¶
7.1 可扩展的设计¶
| 扩展点 | 扩展方式 |
|---|---|
| 新增渠道 | 实现 Channel 接口,注册到 Gateway |
| 新增中间件 | 实现 Middleware 接口,通过 Use 添加 |
| 自定义业务逻辑 | 注册 ClientHandler / ChannelHandler |
7.2 不支持扩展的设计¶
| 限制 | 原因 |
|---|---|
| 不支持运行时添加 Channel | 简化生命周期管理 |
| 不支持动态修改中间件链 | 避免并发问题 |
8. 使用场景¶
8.1 典型场景:AI 助手¶
sequenceDiagram
participant U as 用户
participant WX as 微信
participant WC as WeChatChannel
participant GW as Gateway
participant AI as AI业务处理
participant BR as 浏览器客户端
U->>WX: 发送消息
WX->>WC: Webhook
WC->>GW: 标准消息
GW->>AI: 处理
AI-->>GW: AI回复
GW->>BR: 推送显示
GW->>WC: 发送回复
WC->>WX: API调用
WX->>U: 收到回复
8.2 典型场景:多端同步¶
sequenceDiagram
participant DA as 桌面App
participant GW as Gateway
participant DC as DingTalkChannel
participant DT as 钉钉群
participant BR as 浏览器客户端
DA->>GW: 发送消息
GW->>DC: 转发
DC->>DT: 发送到群
GW->>BR: 同步推送
9. 相关文档¶
- 02-channel.md - Channel 模块设计
- 03-session-manager.md - SessionManager 模块设计
- 04-middleware.md - Middleware 模块设计