forked from datawhale/whale-town-end
feat(zulip): 添加全面的 Zulip 集成系统
* **新增 Zulip 模块**:包含完整的集成服务,涵盖客户端池(client pool)、会话管理及事件处理。 * **新增 WebSocket 网关**:用于处理 Zulip 的实时事件监听与双向通信。 * **新增安全服务**:支持 API 密钥加密存储及凭据的安全管理。 * **新增配置管理服务**:支持配置热加载(hot-reload),实现动态配置更新。 * **新增错误处理与监控服务**:提升系统的可靠性与可观测性。 * **新增消息过滤服务**:用于内容校验及速率限制(流控)。 * **新增流初始化与会话清理服务**:优化资源管理与回收。 * **完善测试覆盖**:包含单元测试及端到端(e2e)集成测试。 * **完善详细文档**:包括 API 参考手册、配置指南及集成概述。 * **新增地图配置系统**:实现游戏地点与 Zulip Stream(频道)及 Topic(话题)的逻辑映射。 * **新增环境变量配置**:涵盖 Zulip 服务器地址、身份验证及监控相关设置。 * **更新 App 模块**:注册并启用新的 Zulip 集成模块。 * **更新 Redis 接口**:以支持增强型的会话管理功能。 * **实现 WebSocket 协议支持**:确保与 Zulip 之间的实时双向通信。
This commit is contained in:
285
docs/systems/zulip/api.md
Normal file
285
docs/systems/zulip/api.md
Normal file
@@ -0,0 +1,285 @@
|
||||
# Zulip 集成系统 API 文档
|
||||
|
||||
## WebSocket 连接
|
||||
|
||||
### 连接地址
|
||||
|
||||
```
|
||||
ws://localhost:3000/game
|
||||
```
|
||||
|
||||
### 连接参数
|
||||
|
||||
连接时无需额外参数,认证通过 `login` 消息完成。
|
||||
|
||||
## 消息类型
|
||||
|
||||
### 1. 登录 (login)
|
||||
|
||||
**请求:**
|
||||
```json
|
||||
{
|
||||
"type": "login",
|
||||
"token": "user_game_token"
|
||||
}
|
||||
```
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"t": "login_success",
|
||||
"sessionId": "session_abc123",
|
||||
"currentMap": "novice_village",
|
||||
"username": "player_name"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"t": "error",
|
||||
"code": "AUTH_FAILED",
|
||||
"message": "Token 验证失败"
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 发送聊天消息 (chat)
|
||||
|
||||
**请求:**
|
||||
```json
|
||||
{
|
||||
"t": "chat",
|
||||
"content": "Hello, world!",
|
||||
"scope": "local"
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|-----|------|-----|------|
|
||||
| t | string | 是 | 固定值 "chat" |
|
||||
| content | string | 是 | 消息内容,最大 1000 字符 |
|
||||
| scope | string | 是 | 消息范围: "local" 或具体 topic 名称 |
|
||||
|
||||
**成功响应:**
|
||||
```json
|
||||
{
|
||||
"t": "chat_sent",
|
||||
"messageId": "msg_123",
|
||||
"timestamp": 1703500800000
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应:**
|
||||
```json
|
||||
{
|
||||
"t": "error",
|
||||
"code": "RATE_LIMIT",
|
||||
"message": "消息发送过于频繁,请稍后再试"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 接收聊天消息 (chat_render)
|
||||
|
||||
**服务器推送:**
|
||||
```json
|
||||
{
|
||||
"t": "chat_render",
|
||||
"from": "other_player",
|
||||
"txt": "Hi there!",
|
||||
"bubble": true,
|
||||
"timestamp": 1703500800000
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
| 参数 | 类型 | 说明 |
|
||||
|-----|------|------|
|
||||
| t | string | 固定值 "chat_render" |
|
||||
| from | string | 发送者名称 |
|
||||
| txt | string | 消息内容 |
|
||||
| bubble | boolean | 是否显示气泡 |
|
||||
| timestamp | number | 消息时间戳 |
|
||||
|
||||
### 4. 位置更新 (position_update)
|
||||
|
||||
**请求:**
|
||||
```json
|
||||
{
|
||||
"t": "position",
|
||||
"x": 150,
|
||||
"y": 200,
|
||||
"mapId": "novice_village"
|
||||
}
|
||||
```
|
||||
|
||||
**参数说明:**
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|-----|------|-----|------|
|
||||
| t | string | 是 | 固定值 "position" |
|
||||
| x | number | 是 | X 坐标 |
|
||||
| y | number | 是 | Y 坐标 |
|
||||
| mapId | string | 是 | 地图 ID |
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"t": "position_updated",
|
||||
"stream": "Novice Village",
|
||||
"topic": "General"
|
||||
}
|
||||
```
|
||||
|
||||
### 5. 登出 (logout)
|
||||
|
||||
**请求:**
|
||||
```json
|
||||
{
|
||||
"type": "logout"
|
||||
}
|
||||
```
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"t": "logout_success"
|
||||
}
|
||||
```
|
||||
|
||||
## 错误码
|
||||
|
||||
| 错误码 | HTTP 等效 | 说明 | 处理建议 |
|
||||
|-------|----------|------|---------|
|
||||
| `AUTH_FAILED` | 401 | 认证失败,Token 无效或过期 | 重新获取 Token 并登录 |
|
||||
| `RATE_LIMIT` | 429 | 消息发送频率超限 | 等待 60 秒后重试 |
|
||||
| `CONTENT_FILTERED` | 400 | 消息内容被过滤 | 修改消息内容后重试 |
|
||||
| `CONTENT_TOO_LONG` | 400 | 消息内容超长 | 缩短消息长度 |
|
||||
| `PERMISSION_DENIED` | 403 | 权限不足 | 检查用户权配置 |
|
||||
| `SESSION_EXPIRED` | 401 | 会话已过期 | 重新登录 |
|
||||
| `SESSION_NOT_FOUND` | 404 | 会话不存在 | 重新登录 |
|
||||
| `ZULIP_ERROR` | 502 | Zulip 服务错误 | 系统自动重试,无需处理 |
|
||||
| `INTERNAL_ERROR` | 500 | 内部服务器错误 | 联系管理员 |
|
||||
|
||||
## 频率限制
|
||||
|
||||
### 消息发送限制
|
||||
|
||||
- 默认限制: 10 条/分钟
|
||||
- 超限后返回 `RATE_LIMIT` 错误
|
||||
- 限制窗口: 滑动窗口,60 秒
|
||||
|
||||
### 连接限制
|
||||
|
||||
- 单用户最大连接数: 3
|
||||
- 超限后新连接被拒绝
|
||||
|
||||
## 消息过滤规则
|
||||
|
||||
### 内容过滤
|
||||
|
||||
1. **敏感词过滤**: 包含敏感词的消息将被拒绝
|
||||
2. **长度限制**: 消息最大 1000 字符
|
||||
3. **重复检测**: 连续发送相同内容将被拒绝
|
||||
|
||||
### 权限验证
|
||||
|
||||
1. **位置验证**: 只能向当前所在地图对应的 Stream 发送消息
|
||||
2. **Stream 权限**: 只能访问配置中允许的 Stream
|
||||
|
||||
## 示例代码
|
||||
|
||||
### JavaScript/TypeScript
|
||||
|
||||
```typescript
|
||||
// 连接 WebSocket
|
||||
const socket = new WebSocket('ws://localhost:3000/game');
|
||||
|
||||
// 连接成功
|
||||
socket.onopen = () => {
|
||||
// 发送登录消息
|
||||
socket.send(JSON.stringify({
|
||||
type: 'login',
|
||||
token: 'your_game_token'
|
||||
}));
|
||||
};
|
||||
|
||||
// 接收消息
|
||||
socket.onmessage = (event) => {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
switch (data.t) {
|
||||
case 'login_success':
|
||||
console.log('登录成功:', data.sessionId);
|
||||
break;
|
||||
case 'chat_render':
|
||||
console.log(`${data.from}: ${data.txt}`);
|
||||
break;
|
||||
case 'error':
|
||||
console.error(`错误 [${data.code}]: ${data.message}`);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// 发送聊天消息
|
||||
function sendChat(content: string) {
|
||||
socket.send(JSON.stringify({
|
||||
t: 'chat',
|
||||
content: content,
|
||||
scope: 'local'
|
||||
}));
|
||||
}
|
||||
|
||||
// 更新位置
|
||||
function updatePosition(x: number, y: number, mapId: string) {
|
||||
socket.send(JSON.stringify({
|
||||
t: 'position',
|
||||
x: x,
|
||||
y: y,
|
||||
mapId: mapId
|
||||
}));
|
||||
}
|
||||
```
|
||||
|
||||
## 健康检查接口
|
||||
|
||||
### GET /health
|
||||
|
||||
检查系统健康状态。
|
||||
|
||||
**响应:**
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"components": {
|
||||
"websocket": "healthy",
|
||||
"zulip": "healthy",
|
||||
"redis": "healthy"
|
||||
},
|
||||
"metrics": {
|
||||
"activeConnections": 42,
|
||||
"activeSessions": 40,
|
||||
"messagesSentLastMinute": 156
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GET /metrics
|
||||
|
||||
获取系统指标(Prometheus 格式)。
|
||||
|
||||
**响应:**
|
||||
```
|
||||
# HELP zulip_connections_active Active WebSocket connections
|
||||
# TYPE zulip_connections_active gauge
|
||||
zulip_connections_active 42
|
||||
|
||||
# HELP zulip_messages_sent_total Total messages sent
|
||||
# TYPE zulip_messages_sent_total counter
|
||||
zulip_messages_sent_total 15678
|
||||
|
||||
# HELP zulip_message_latency_seconds Message processing latency
|
||||
# TYPE zulip_message_latency_seconds histogram
|
||||
zulip_message_latency_seconds_bucket{le="0.1"} 14500
|
||||
zulip_message_latency_seconds_bucket{le="0.5"} 15600
|
||||
zulip_message_latency_seconds_bucket{le="1"} 15678
|
||||
```
|
||||
Reference in New Issue
Block a user