Files
whale-town-end/docs/systems/zulip/README.md
angjustinl 8f9a6e7f9d feat(login, zulip): 引入 JWT 验证并重构 API 密钥管理
### 详细变更描述

* **修复 JWT 签名冲突**:重构 `LoginService.generateTokenPair()`,移除载荷(Payload)中的 `iss` (issuer) 与 `aud` (audience) 字段,解决签名校验失败的问题。
* **统一验证逻辑**:更新 `ZulipService` 以调用 `LoginService.verifyToken()`,消除重复的 JWT 校验代码,确保逻辑单一职责化(Single Responsibility)。
* **修复硬编码 API 密钥问题**:消息发送功能不再依赖静态配置,改为从 Redis 动态读取用户真实的 API 密钥。
* **解耦依赖注入**:在 `ZulipModule` 中注入 `AuthModule` 依赖,以支持标准的 Token 验证流程。
* **完善技术文档**:补充了关于 JWT 验证流程及 API 密钥管理逻辑的详细文档。
* **新增测试工具**:添加 `test-get-messages.js` 脚本,用于验证通过 WebSocket 接收消息的功能。
* **更新自动化脚本**:同步更新了 API 密钥验证及用户注册校验的快速测试脚本。
* **端到端功能验证**:确保消息发送逻辑能够正确映射并调用用户真实的 Zulip API 密钥。
2026-01-06 18:51:37 +08:00

387 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Zulip 集成系统文档
## 概述
Zulip 集成系统是一个为 2D 社交 MMO 游戏设计的跨平台聊天解决方案。该系统实现了游戏内外的无缝互通,让不玩游戏的 Zulip 社群成员也能与游戏内玩家实时交流。
### 核心设计理念
系统采用 **统一网关 (Unified Gateway)** 架构,利用 Zulip 的 Stream-Topic 线程模型与游戏世界的空间概念进行映射:
| 游戏概念 | Zulip 概念 | 示例 |
|---------|-----------|------|
| Game World / Map | Stream | #Novice_Village |
| Interactive Object / Event | Topic | Notice Board, Tavern Gossip |
| Whisper / Party | Private Message | 私聊消息 |
### 架构优势
1. **客户端极度简化**: Godot 客户端无需处理 HTTP 请求、Long Polling 或复杂 JSON 解析
2. **安全性**: Zulip API Key 永不下发到客户端,位置欺诈完全消除
3. **协议统一**: 单一 WebSocket 协议,网络层代码减半
## 系统架构
```
┌─────────────────┐ WebSocket ┌─────────────────────────────────────┐
│ Godot Client │◄──────────────────►│ NestJS 中间件服务器 │
│ (Game Client) │ Game Protocol │ ┌─────────────────────────────────┐│
└─────────────────┘ │ │ WebSocket Gateway ││
│ │ ├─ Session Manager ││
│ │ ├─ Message Filter ││
│ │ └─ Zulip Client Pool ││
│ └─────────────────────────────────┘│
└──────────────┬──────────────────────┘
│ REST API / Long Polling
┌─────────────────────────────────────┐
│ Zulip Server │
│ ├─ REST API │
│ └─ Event Queue │
└─────────────────────────────────────┘
```
## 核心组件
### 1. WebSocket Gateway (`zulip-websocket.gateway.ts`)
统一网关,处理所有 Godot 客户端连接,实现游戏协议到 Zulip 协议的转换。
**主要功能:**
- 连接认证和会话管理
- 消息路由和协议转换
- 权限控制和上下文注入
**支持的消息类型:**
- `login`: 玩家登录
- `chat`: 发送聊天消息
- `position_update`: 位置更新
- `logout`: 玩家登出
### 2. Session Manager (`session-manager.service.ts`)
会话管理器,维护 Socket_ID 与 Zulip_Queue_ID 的绑定关系。
**主要功能:**
- 会话创建/销毁
- 玩家位置跟踪
- 上下文注入(根据位置确定 Stream/Topic
- 空间过滤(获取指定地图的所有 Socket
### 3. Zulip Client Pool (`zulip-client-pool.service.ts`)
Zulip 客户端池,为每个用户维护专用的 Zulip 客户端实例。
**主要功能:**
- API Key 管理
- 事件队列注册
- 消息发送/接收
- 客户端生命周期管理
### 4. Message Filter (`message-filter.service.ts`)
消息过滤器,实施内容审核和频率控制。
**主要功能:**
- 敏感词过滤
- 频率限制(默认 10 条/分钟)
- 消息长度限制(默认 1000 字符)
- 重复内容检测
- 权限验证
### 5. Config Manager (`config-manager.service.ts`)
配置管理器,管理地图映射配置和系统参数。
**主要功能:**
- 地图到 Stream 的映射
- 交互对象到 Topic 的映射
- 配置热重载
- 配置验证
### 6. Stream Initializer Service (`stream-initializer.service.ts`)
Stream 初始化服务,在系统启动时自动检查并创建缺失的 Zulip Streams。
**主要功能:**
- 启动时自动检查所有地图对应的 Streams
- 自动创建缺失的 Streams
- 使用 Bot API Key 或管理员账号创建 Streams
- 记录初始化结果和错误
**权限说明:**
- Bot 账号可能缺少创建 Stream 的权限
- 建议使用管理员账号手动创建 Streams
- 或在 Zulip 服务器中为 Bot 授予相应权限
### 7. Monitoring Service (`monitoring.service.ts`)
监控服务,提供系统健康检查和指标收集。
**主要功能:**
- 连接指标监控
- 消息指标监控
- 系统健康检查
- 告警通知
## 消息协议
### 客户端发送格式
#### 登录消息
```json
{
"type": "login",
"token": "user_game_token"
}
```
#### 聊天消息
```json
{
"t": "chat",
"content": "Hello",
"scope": "local"
}
```
#### 位置更新
```json
{
"t": "position",
"x": 100,
"y": 200,
"mapId": "novice_village"
}
```
### 客户端接收格式
#### 聊天渲染消息
```json
{
"t": "chat_render",
"from": "User_B",
"txt": "Hi",
"bubble": true
}
```
#### 登录确认
```json
{
"t": "login_success",
"sessionId": "session_123",
"currentMap": "novice_village"
}
```
#### 错误消息
```json
{
"t": "error",
"code": "RATE_LIMIT",
"message": "消息发送过于频繁,请稍后再试"
}
```
## 配置说明
### 环境变量配置
```bash
# Zulip 服务器配置
ZULIP_SERVER_URL=https://your-zulip-server.com
ZULIP_BOT_EMAIL=bot@your-zulip-server.com
ZULIP_BOT_API_KEY=your-bot-api-key
# WebSocket 配置
WEBSOCKET_PORT=3001
WEBSOCKET_NAMESPACE=/game
# 消息配置
MESSAGE_RATE_LIMIT=10 # 消息频率限制(条/分钟)
MESSAGE_MAX_LENGTH=1000 # 消息最大长度
# 会话配置
SESSION_TIMEOUT=30 # 会话超时时间(分钟)
CLEANUP_INTERVAL=5 # 清理间隔(分钟)
```
### Stream 初始化
系统在启动时会自动检查并尝试创建缺失的 Zulip Streams。
**注意事项:**
- Bot 账号可能缺少创建 Stream 的权限
- 建议使用管理员账号预先创建所有 Streams
- 或在 Zulip 服务器中为 Bot 授予 "Create streams" 权限
**手动创建 Streams:**
```bash
# 使用测试脚本创建所有地图区域的 Streams
node test-stream-initialization.js
```
详细配置说明请参考 [配置管理指南](./configuration.md)。
### 地图映射配置
配置文件位置: `config/zulip/map-config.json`
系统支持 9 个地图区域,每个区域对应一个 Zulip Stream
1. **鲸之港 (Whale Port)** - 中心城区,默认出生点
2. **南瓜谷 (Pumpkin Valley)** - 新手学习区
3. **Offer 城 (Offer City)** - 职业发展区
4. **模型工厂 (Model Factory)** - AI/代码构建区
5. **内核岛 (Kernel Island)** - 核心技术研究区
6. **摸鱼海滩 (Moyu Beach)** - 休闲娱乐区
7. **天梯峰 (Ladder Peak)** - 挑战竞赛区
8. **星河湾 (Galaxy Bay)** - 创意设计区
9. **数据遗迹 (Data Ruins)** - 数据库归档区
配置示例:
```json
{
"version": "2.0.0",
"description": "基于像素大地图的 Zulip 映射配置",
"maps": [
{
"mapId": "whale_port",
"mapName": "鲸之港",
"zulipStream": "Whale Port",
"description": "中心城区,交通枢纽与主要聚会点",
"interactionObjects": [
{
"objectId": "whale_statue",
"objectName": "鲸鱼雕像",
"zulipTopic": "Announcements",
"position": { "x": 600, "y": 400 }
}
]
}
]
}
```
## 数据流程
### 发送消息流程 (游戏 → Zulip)
1. 玩家在游戏中输入消息
2. Godot 客户端通过 WebSocket 发送 `chat` 消息
3. WebSocket Gateway 接收消息
4. Session Manager 获取玩家当前位置
5. 上下文注入:根据位置确定目标 Stream/Topic
6. Message Filter 进行内容过滤和频率检查
7. Zulip Client Pool 使用用户的 API Key 发送消息到 Zulip
8. 返回发送确认给客户端
### 接收消息流程 (Zulip → 游戏)
1. Zulip 服务器推送消息事件到 Event Queue
2. Zulip Event Processor 接收并处理事件
3. Session Manager 进行空间过滤,确定目标玩家
4. 消息转换为游戏协议格式
5. WebSocket Gateway 推送 `chat_render` 消息给目标客户端
6. Godot 客户端显示聊天气泡
## 错误处理
### 错误码说明
| 错误码 | 说明 | 处理建议 |
|-------|------|---------|
| `AUTH_FAILED` | 认证失败 | 检查 Token 有效性 |
| `RATE_LIMIT` | 频率限制 | 等待后重试 |
| `CONTENT_FILTERED` | 内容被过滤 | 修改消息内容 |
| `PERMISSION_DENIED` | 权限不足 | 检查用户权限 |
| `ZULIP_ERROR` | Zulip 服务错误 | 系统自动重试 |
| `SESSION_EXPIRED` | 会话过期 | 重新登录 |
### 降级策略
当 Zulip 服务不可用时,系统会自动切换到本地聊天模式:
- 消息仅在游戏内传播
- 不同步到 Zulip
- 服务恢复后自动切换回正常模式
## 安全机制
### API Key 安全
- API Key 加密存储在数据库中
- 永不下发到客户端
- 支持强制刷新机制
### 消息安全
- 敏感词过滤
- 频率限制防刷屏
- 位置验证防欺诈
- 消息长度限制
### 连接安全
- Token 验证
- 会话超时自动断开
- 异常连接检测和拒绝
## 监控指标
### 连接指标
- `zulip.connections.active`: 活跃连接数
- `zulip.connections.total`: 总连接数
- `zulip.connections.errors`: 连接错误数
### 消息指标
- `zulip.messages.sent`: 发送消息数
- `zulip.messages.received`: 接收消息数
- `zulip.messages.filtered`: 被过滤消息数
- `zulip.messages.latency`: 消息延迟
### 系统指标
- `zulip.sessions.active`: 活跃会话数
- `zulip.zulip_clients.active`: 活跃 Zulip 客户端数
- `zulip.event_queues.active`: 活跃事件队列数
## 相关文档
- [zulip-js 库使用指南](./zulip-js.md)
- [API 接口文档](./api.md)
- [WebSocket 协议详解](./websocket-protocol.md)
- [配置管理指南](./configuration.md)
## 更新日志
### v1.1.0 (2026-01-06)
- **修复 JWT Token 验证和 API Key 管理**
- 修复 `LoginService.generateTokenPair()` 的 JWT 签名冲突问题
- `ZulipService` 现在复用 `LoginService.verifyToken()` 进行 Token 验证
- 修复消息发送时使用错误的硬编码 API Key 问题
- 现在正确从 Redis 读取用户注册时存储的真实 API Key
- 添加 `AuthModule``ZulipModule` 的依赖注入
- 消息发送功能现已完全正常工作 ✅
### v1.0.1 (2025-12-25)
- 更新地图配置为 9 区域系统
- 添加 Stream Initializer Service 自动初始化服务
- 更新默认出生点为鲸之港 (Whale Port)
- 添加地图区域描述字段
- 修复上下文注入使用 ConfigManager
- 改进错误处理和日志记录
### v1.0.0 (2025-12-25)
- 初始版本发布
- 实现 WebSocket Gateway 统一网关
- 实现 Session Manager 会话管理
- 实现 Zulip Client Pool 客户端池
- 实现 Message Filter 消息过滤
- 实现 Config Manager 配置管理
- 实现 Monitoring Service 监控服务
- 完成集成测试覆盖