forked from datawhale/whale-town-end
* **新增 Zulip 模块**:包含完整的集成服务,涵盖客户端池(client pool)、会话管理及事件处理。 * **新增 WebSocket 网关**:用于处理 Zulip 的实时事件监听与双向通信。 * **新增安全服务**:支持 API 密钥加密存储及凭据的安全管理。 * **新增配置管理服务**:支持配置热加载(hot-reload),实现动态配置更新。 * **新增错误处理与监控服务**:提升系统的可靠性与可观测性。 * **新增消息过滤服务**:用于内容校验及速率限制(流控)。 * **新增流初始化与会话清理服务**:优化资源管理与回收。 * **完善测试覆盖**:包含单元测试及端到端(e2e)集成测试。 * **完善详细文档**:包括 API 参考手册、配置指南及集成概述。 * **新增地图配置系统**:实现游戏地点与 Zulip Stream(频道)及 Topic(话题)的逻辑映射。 * **新增环境变量配置**:涵盖 Zulip 服务器地址、身份验证及监控相关设置。 * **更新 App 模块**:注册并启用新的 Zulip 集成模块。 * **更新 Redis 接口**:以支持增强型的会话管理功能。 * **实现 WebSocket 协议支持**:确保与 Zulip 之间的实时双向通信。
517 lines
12 KiB
Markdown
517 lines
12 KiB
Markdown
# 配置管理指南
|
||
|
||
## 概述
|
||
|
||
Zulip 集成系统支持多种配置方式,包括环境变量、配置文件和运行时配置。本文档详细说明各配置项的用途和设置方法。
|
||
|
||
## 环境变量配置
|
||
|
||
### Zulip 服务器配置
|
||
|
||
```bash
|
||
# Zulip 服务器 URL
|
||
ZULIP_SERVER_URL=https://zulip.xinghangee.icu/
|
||
|
||
# Zulip Bot 邮箱
|
||
ZULIP_BOT_EMAIL=cbot-bot@zulip.xinghangee.icu
|
||
|
||
# Zulip Bot API Key
|
||
ZULIP_BOT_API_KEY=your-bot-api-key
|
||
|
||
# Zulip Realm (可选,默认从 URL 推断)
|
||
ZULIP_REALM=your-realm
|
||
```
|
||
|
||
### WebSocket 配置
|
||
|
||
```bash
|
||
# WebSocket 端口
|
||
WEBSOCKET_PORT=3000
|
||
|
||
# WebSocket 命名空间
|
||
WEBSOCKET_NAMESPACE=/game
|
||
|
||
# 最大连接数
|
||
WEBSOCKET_MAX_CONNECTIONS=100
|
||
|
||
# 连接超时时间 (毫秒)
|
||
WEBSOCKET_TIMEOUT=60000
|
||
```
|
||
|
||
### 消息配置
|
||
|
||
```bash
|
||
# 消息频率限制 (条/分钟)
|
||
MESSAGE_RATE_LIMIT=10
|
||
|
||
# 消息最大长度 (字符)
|
||
MESSAGE_MAX_LENGTH=1000
|
||
|
||
# 是否启用内容过滤
|
||
ENABLE_CONTENT_FILTER=true
|
||
|
||
# 是否启用重复检测
|
||
ENABLE_DUPLICATE_DETECTION=true
|
||
```
|
||
|
||
### 会话配置
|
||
|
||
```bash
|
||
# 会话超时时间 (分钟)
|
||
SESSION_TIMEOUT=30
|
||
|
||
# 会话清理间隔 (分钟)
|
||
SESSION_CLEANUP_INTERVAL=5
|
||
|
||
# 最大会话数
|
||
MAX_SESSIONS=5000
|
||
```
|
||
|
||
### Redis 配置
|
||
|
||
```bash
|
||
# Redis 主机
|
||
REDIS_HOST=localhost
|
||
|
||
# Redis 端口
|
||
REDIS_PORT=6379
|
||
|
||
# Redis 密码 (可选)
|
||
REDIS_PASSWORD=
|
||
|
||
# Redis 数据库索引
|
||
REDIS_DB=0
|
||
|
||
# Redis 键前缀
|
||
REDIS_KEY_PREFIX=zulip:
|
||
```
|
||
|
||
### 日志配置
|
||
|
||
```bash
|
||
# 日志级别 (debug, info, warn, error)
|
||
LOG_LEVEL=info
|
||
|
||
# 是否启用结构化日志
|
||
LOG_STRUCTURED=true
|
||
|
||
# 日志文件路径 (可选)
|
||
LOG_FILE_PATH=logs/zulip.log
|
||
```
|
||
|
||
## 配置文件
|
||
|
||
### 地图映射配置
|
||
|
||
文件位置: `config/zulip/map-config.json`
|
||
|
||
```json
|
||
{
|
||
"version": "2.0.0",
|
||
"lastModified": "2025-12-25T20:00:00.000Z",
|
||
"description": "基于像素大地图的 Zulip 映射配置",
|
||
"maps": [
|
||
{
|
||
"mapId": "whale_port",
|
||
"mapName": "鲸之港",
|
||
"zulipStream": "Whale Port",
|
||
"description": "中心城区,交通枢纽与主要聚会点",
|
||
"interactionObjects": [
|
||
{
|
||
"objectId": "whale_statue",
|
||
"objectName": "鲸鱼雕像",
|
||
"zulipTopic": "Announcements",
|
||
"position": { "x": 600, "y": 400 }
|
||
},
|
||
{
|
||
"objectId": "clock_tower",
|
||
"objectName": "大本钟",
|
||
"zulipTopic": "General Chat",
|
||
"position": { "x": 550, "y": 350 }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"mapId": "pumpkin_valley",
|
||
"mapName": "南瓜谷",
|
||
"zulipStream": "Pumpkin Valley",
|
||
"description": "新手成长、基础资源与学习社区",
|
||
"interactionObjects": [
|
||
{
|
||
"objectId": "pumpkin_patch",
|
||
"objectName": "南瓜田",
|
||
"zulipTopic": "Tutorials",
|
||
"position": { "x": 150, "y": 400 }
|
||
},
|
||
{
|
||
"objectId": "farm_house",
|
||
"objectName": "农舍",
|
||
"zulipTopic": "Study Group",
|
||
"position": { "x": 200, "y": 450 }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"mapId": "offer_city",
|
||
"mapName": "Offer 城",
|
||
"zulipStream": "Offer City",
|
||
"description": "职业发展、面试与商务区",
|
||
"interactionObjects": [
|
||
{
|
||
"objectId": "skyscrapers",
|
||
"objectName": "摩天大楼",
|
||
"zulipTopic": "Career Talk",
|
||
"position": { "x": 350, "y": 650 }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"mapId": "model_factory",
|
||
"mapName": "模型工厂",
|
||
"zulipStream": "Model Factory",
|
||
"description": "AI模型训练、代码构建与工业区",
|
||
"interactionObjects": [
|
||
{
|
||
"objectId": "assembly_line",
|
||
"objectName": "流水线",
|
||
"zulipTopic": "Code Review",
|
||
"position": { "x": 400, "y": 200 }
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
系统现在支持 9 个地图区域:
|
||
|
||
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)** - 数据库、归档与历史记录
|
||
|
||
### 配置字段说明
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|-----|------|-----|------|
|
||
| version | string | 是 | 配置版本号 |
|
||
| lastModified | string | 否 | 最后修改时间 (ISO 8601) |
|
||
| description | string | 否 | 配置文件描述 |
|
||
| maps | array | 是 | 地图配置数组 |
|
||
| maps[].mapId | string | 是 | 地图唯一标识 |
|
||
| maps[].mapName | string | 是 | 地图显示名称 |
|
||
| maps[].zulipStream | string | 是 | 对应的 Zulip Stream |
|
||
| maps[].description | string | 否 | 地图区域描述 |
|
||
| maps[].defaultTopic | string | 否 | 默认 Topic,默认 "General" |
|
||
| maps[].interactionObjects | array | 否 | 交互对象配置 |
|
||
| interactionObjects[].objectId | string | 是 | 对象唯一标识 |
|
||
| interactionObjects[].objectName | string | 是 | 对象显示名称 |
|
||
| interactionObjects[].zulipTopic | string | 是 | 对应的 Zulip Topic |
|
||
| interactionObjects[].position | object | 是 | 对象位置坐标 |
|
||
| interactionObjects[].radius | number | 否 | 交互半径,默认 50 |
|
||
|
||
### 敏感词配置
|
||
|
||
文件位置: `config/zulip/sensitive-words.json`
|
||
|
||
```json
|
||
{
|
||
"version": "1.0.0",
|
||
"words": [
|
||
"敏感词1",
|
||
"敏感词2"
|
||
],
|
||
"patterns": [
|
||
"正则表达式1",
|
||
"正则表达式2"
|
||
],
|
||
"replacements": {
|
||
"原词": "替换词"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 允许的 Stream 配置
|
||
|
||
文件位置: `config/zulip/allowed-streams.json`
|
||
|
||
```json
|
||
{
|
||
"version": "1.0.0",
|
||
"streams": [
|
||
"Novice Village",
|
||
"Market Square",
|
||
"Guild Hall",
|
||
"Arena"
|
||
],
|
||
"privateStreams": [
|
||
"Admin",
|
||
"Moderators"
|
||
]
|
||
}
|
||
```
|
||
|
||
## 运行时配置
|
||
|
||
### 通过 API 更新配置
|
||
|
||
```typescript
|
||
// 更新消息频率限制
|
||
await configManager.updateConfig('messageRateLimit', 20);
|
||
|
||
// 更新会话超时时间
|
||
await configManager.updateConfig('sessionTimeout', 60);
|
||
|
||
// 重新加载地图配置
|
||
await configManager.reloadMapConfig();
|
||
```
|
||
|
||
### 配置热重载
|
||
|
||
系统支持配置热重载,无需重启服务:
|
||
|
||
```bash
|
||
# 发送 SIGHUP 信号触发配置重载
|
||
kill -HUP <pid>
|
||
```
|
||
|
||
或通过 API:
|
||
|
||
```bash
|
||
curl -X POST http://localhost:3000/admin/config/reload \
|
||
-H "Authorization: Bearer <admin_token>"
|
||
```
|
||
|
||
## 配置验证
|
||
|
||
### 启动时验证
|
||
|
||
系统在启动时会验证所有配置的有效性:
|
||
|
||
```typescript
|
||
// 配置验证示例
|
||
const configValidator = new ConfigValidator();
|
||
|
||
// 验证环境变量
|
||
configValidator.validateEnv({
|
||
ZULIP_SERVER_URL: { required: true, type: 'url' },
|
||
ZULIP_BOT_EMAIL: { required: true, type: 'email' },
|
||
ZULIP_BOT_API_KEY: { required: true, type: 'string' },
|
||
MESSAGE_RATE_LIMIT: { required: false, type: 'number', default: 10 },
|
||
});
|
||
|
||
// 验证地图配置
|
||
configValidator.validateMapConfig(mapConfig);
|
||
```
|
||
|
||
### 验证错误处理
|
||
|
||
配置验证失败时,系统会:
|
||
|
||
1. 记录详细的错误日志
|
||
2. 输出错误信息到控制台
|
||
3. 阻止服务启动(严重错误)或使用默认值(非严重错误)
|
||
|
||
```
|
||
[ERROR] 配置验证失败:
|
||
- ZULIP_SERVER_URL: 必填项未设置
|
||
- MESSAGE_RATE_LIMIT: 值必须大于 0
|
||
- map-config.json: maps[0].zulipStream 不能为空
|
||
```
|
||
|
||
## Stream 初始化
|
||
|
||
### 自动初始化服务
|
||
|
||
系统在启动时会自动检查所有地图配置中定义的 Zulip Streams 是否存在。如果发现缺失的 Streams,会尝试自动创建。
|
||
|
||
**服务配置:**
|
||
|
||
```typescript
|
||
// Stream 初始化服务会在系统启动 5 秒后自动运行
|
||
// 位置: src/business/zulip/services/stream-initializer.service.ts
|
||
|
||
@Injectable()
|
||
export class StreamInitializerService implements OnModuleInit {
|
||
async onModuleInit() {
|
||
// 延迟 5 秒启动,确保其他服务已就绪
|
||
setTimeout(() => {
|
||
this.initializeStreams();
|
||
}, 5000);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 权限要求
|
||
|
||
创建 Zulip Streams 需要特定权限:
|
||
|
||
- **Bot 账号**: 默认情况下可能缺少创建 Stream 的权限
|
||
- **管理员账号**: 拥有完整的 Stream 创建权限
|
||
|
||
**解决方案:**
|
||
|
||
1. **方案一**: 在 Zulip 服务器中为 Bot 账号授予创建 Stream 的权限
|
||
- 登录 Zulip 管理后台
|
||
- 找到 Bot 账号设置
|
||
- 授予 "Create streams" 权限
|
||
|
||
2. **方案二**: 使用管理员账号手动创建 Streams
|
||
- 使用提供的测试脚本 `test-stream-initialization.js`
|
||
- 配置管理员 API Key
|
||
- 运行脚本自动创建所有 Streams
|
||
|
||
3. **方案三**: 在 Zulip 网页界面手动创建
|
||
- 登录 Zulip 网页界面
|
||
- 创建对应的 Streams (参考 `config/zulip/map-config.json`)
|
||
|
||
### 手动创建 Streams
|
||
|
||
使用测试脚本创建所有地图区域的 Streams:
|
||
|
||
```bash
|
||
# 编辑 test-stream-initialization.js,配置管理员 API Key
|
||
# 然后运行脚本
|
||
node test-stream-initialization.js
|
||
```
|
||
|
||
脚本会自动创建以下 Streams:
|
||
|
||
- Whale Port (鲸之港)
|
||
- Pumpkin Valley (南瓜谷)
|
||
- Offer City (Offer 城)
|
||
- Model Factory (模型工厂)
|
||
- Kernel Island (内核岛)
|
||
- Moyu Beach (摸鱼海滩)
|
||
- Ladder Peak (天梯峰)
|
||
- Galaxy Bay (星河湾)
|
||
- Data Ruins (数据遗迹)
|
||
|
||
### 初始化日志
|
||
|
||
系统会记录 Stream 初始化的详细日志:
|
||
|
||
```
|
||
[INFO] 开始初始化 Zulip Streams...
|
||
[INFO] 检查 Stream: Whale Port
|
||
[INFO] Stream 已存在: Whale Port
|
||
[WARN] Stream 不存在,尝试创建: Pumpkin Valley
|
||
[INFO] Stream 创建成功: Pumpkin Valley
|
||
[ERROR] Stream 创建失败: Offer City - Insufficient permission
|
||
```
|
||
|
||
## 配置最佳实践
|
||
|
||
### 1. 使用环境变量管理敏感信息
|
||
|
||
```bash
|
||
# 不要在代码中硬编码敏感信息
|
||
# 使用环境变量或密钥管理服务
|
||
|
||
# 开发环境
|
||
export ZULIP_BOT_API_KEY=dev-api-key
|
||
|
||
# 生产环境 (使用密钥管理服务)
|
||
export ZULIP_BOT_API_KEY=$(aws secretsmanager get-secret-value --secret-id zulip-api-key --query SecretString --output text)
|
||
```
|
||
|
||
### 2. 分环境配置
|
||
|
||
```
|
||
config/
|
||
├── zulip/
|
||
│ ├── map-config.json # 默认配置
|
||
│ ├── map-config.dev.json # 开发环境
|
||
│ ├── map-config.staging.json # 预发布环境
|
||
│ └── map-config.prod.json # 生产环境
|
||
```
|
||
|
||
```typescript
|
||
// 根据环境加载配置
|
||
const env = process.env.NODE_ENV || 'development';
|
||
const configPath = `config/zulip/map-config.${env}.json`;
|
||
```
|
||
|
||
### 3. 配置版本控制
|
||
|
||
- 将配置文件纳入版本控制
|
||
- 使用 `.env.example` 提供配置模板
|
||
- 敏感配置使用 `.gitignore` 排除
|
||
|
||
### 4. 配置文档化
|
||
|
||
为每个配置项提供清晰的文档说明:
|
||
|
||
```typescript
|
||
/**
|
||
* 消息频率限制配置
|
||
*
|
||
* @description 限制用户每分钟可发送的消息数量
|
||
* @default 10
|
||
* @range 1-100
|
||
* @env MESSAGE_RATE_LIMIT
|
||
*/
|
||
messageRateLimit: number;
|
||
```
|
||
|
||
## 故障排除
|
||
|
||
### 常见配置问题
|
||
|
||
#### 1. Zulip 连接失败
|
||
|
||
```
|
||
错误: ZULIP_CONNECTION_FAILED
|
||
原因: 无法连接到 Zulip 服务器
|
||
```
|
||
|
||
检查项:
|
||
- `ZULIP_SERVER_URL` 是否正确
|
||
- 网络是否可达
|
||
- API Key 是否有效
|
||
|
||
#### 2. 地图配置加载失败
|
||
|
||
```
|
||
错误: MAP_CONFIG_LOAD_FAILED
|
||
原因: 地图配置文件格式错误
|
||
```
|
||
|
||
检查项:
|
||
- JSON 格式是否正确
|
||
- 必填字段是否完整
|
||
- 字段类型是否正确
|
||
|
||
#### 3. Redis 连接失败
|
||
|
||
```
|
||
错误: REDIS_CONNECTION_FAILED
|
||
原因: 无法连接到 Redis 服务器
|
||
```
|
||
|
||
检查项:
|
||
- `REDIS_HOST` 和 `REDIS_PORT` 是否正确
|
||
- Redis 服务是否运行
|
||
- 密码是否正确
|
||
|
||
### 配置诊断命令
|
||
|
||
```bash
|
||
# 检查配置有效性
|
||
npm run config:validate
|
||
|
||
# 显示当前配置
|
||
npm run config:show
|
||
|
||
# 测试 Zulip 连接
|
||
npm run config:test-zulip
|
||
|
||
# 测试 Redis 连接
|
||
npm run config:test-redis
|
||
```
|