范围: src/business/zulip/README.md - 补充对外提供的接口章节(14个公共方法) - 添加使用的项目内部依赖说明(7个依赖) - 完善核心特性描述(5个特性) - 添加潜在风险评估(4个风险及缓解措施) - 优化文档结构和内容完整性
839 lines
21 KiB
TypeScript
839 lines
21 KiB
TypeScript
/**
|
||
* WebSocket OpenAPI 文档控制器
|
||
*
|
||
* 功能描述:
|
||
* - 专门用于在OpenAPI/Swagger中展示WebSocket接口
|
||
* - 通过REST API的方式描述WebSocket的消息格式和交互流程
|
||
* - 提供WebSocket连接信息和测试工具推荐
|
||
*
|
||
* 架构定位:
|
||
* - 层级:Gateway层(网关层)
|
||
* - 职责:HTTP协议处理、OpenAPI文档暴露
|
||
* - 依赖:无业务逻辑依赖,纯文档展示
|
||
*
|
||
* 职责分离:
|
||
* - 文档展示:在Swagger中展示WebSocket消息格式
|
||
* - 连接信息:提供WebSocket连接配置和认证信息
|
||
* - 消息流程:展示WebSocket消息交互流程
|
||
* - 测试工具:提供测试工具推荐和示例代码
|
||
*
|
||
* 最近修改:
|
||
* - 2026-01-14: 架构优化 - 从Business层迁移到Gateway层,符合四层架构规范 (修改者: moyin)
|
||
* - 2026-01-14: 代码规范优化 - 完善文件头注释和职责分离描述 (修改者: moyin)
|
||
* - 2026-01-09: 功能新增 - 初始创建WebSocket OpenAPI文档控制器 (修改者: moyin)
|
||
*
|
||
* @author moyin
|
||
* @version 2.0.0
|
||
* @since 2026-01-09
|
||
* @lastModified 2026-01-14
|
||
*/
|
||
|
||
import { Controller, Get, Post, Body } from '@nestjs/common';
|
||
import {
|
||
ApiTags,
|
||
ApiOperation,
|
||
ApiResponse,
|
||
ApiProperty,
|
||
ApiExtraModels,
|
||
} from '@nestjs/swagger';
|
||
|
||
// WebSocket 消息格式 DTO
|
||
class WebSocketLoginRequest {
|
||
@ApiProperty({
|
||
description: '消息类型',
|
||
example: 'login',
|
||
enum: ['login']
|
||
})
|
||
type: string;
|
||
|
||
@ApiProperty({
|
||
description: 'JWT认证令牌',
|
||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
||
})
|
||
token: string;
|
||
}
|
||
|
||
class WebSocketLoginSuccessResponse {
|
||
@ApiProperty({
|
||
description: '响应类型',
|
||
example: 'login_success'
|
||
})
|
||
t: string;
|
||
|
||
@ApiProperty({
|
||
description: '会话ID',
|
||
example: '89aff162-52d9-484e-9a35-036ba63a2280'
|
||
})
|
||
sessionId: string;
|
||
|
||
@ApiProperty({
|
||
description: '用户ID',
|
||
example: 'user_123'
|
||
})
|
||
userId: string;
|
||
|
||
@ApiProperty({
|
||
description: '用户名',
|
||
example: 'Player_123'
|
||
})
|
||
username: string;
|
||
|
||
@ApiProperty({
|
||
description: '当前地图',
|
||
example: 'whale_port'
|
||
})
|
||
currentMap: string;
|
||
}
|
||
|
||
class WebSocketChatRequest {
|
||
@ApiProperty({
|
||
description: '消息类型',
|
||
example: 'chat',
|
||
enum: ['chat']
|
||
})
|
||
t: string;
|
||
|
||
@ApiProperty({
|
||
description: '消息内容',
|
||
example: '大家好!我刚进入游戏',
|
||
maxLength: 1000
|
||
})
|
||
content: string;
|
||
|
||
@ApiProperty({
|
||
description: '消息范围',
|
||
example: 'local',
|
||
enum: ['local', 'global']
|
||
})
|
||
scope: string;
|
||
}
|
||
|
||
class WebSocketChatResponse {
|
||
@ApiProperty({
|
||
description: '响应类型',
|
||
example: 'chat_render'
|
||
})
|
||
t: string;
|
||
|
||
@ApiProperty({
|
||
description: '发送者用户名',
|
||
example: 'Player_456'
|
||
})
|
||
from: string;
|
||
|
||
@ApiProperty({
|
||
description: '消息内容',
|
||
example: '欢迎新玩家!'
|
||
})
|
||
txt: string;
|
||
|
||
@ApiProperty({
|
||
description: '是否显示气泡',
|
||
example: true
|
||
})
|
||
bubble: boolean;
|
||
|
||
@ApiProperty({
|
||
description: '消息范围',
|
||
example: 'local'
|
||
})
|
||
scope: string;
|
||
|
||
@ApiProperty({
|
||
description: '地图ID(本地消息时)',
|
||
example: 'whale_port',
|
||
required: false
|
||
})
|
||
mapId?: string;
|
||
}
|
||
|
||
class WebSocketPositionRequest {
|
||
@ApiProperty({
|
||
description: '消息类型',
|
||
example: 'position'
|
||
})
|
||
t: string;
|
||
|
||
@ApiProperty({
|
||
description: 'X坐标',
|
||
example: 150
|
||
})
|
||
x: number;
|
||
|
||
@ApiProperty({
|
||
description: 'Y坐标',
|
||
example: 400
|
||
})
|
||
y: number;
|
||
|
||
@ApiProperty({
|
||
description: '地图ID',
|
||
example: 'whale_port'
|
||
})
|
||
mapId: string;
|
||
}
|
||
|
||
class WebSocketErrorResponse {
|
||
@ApiProperty({
|
||
description: '错误类型',
|
||
example: 'error'
|
||
})
|
||
type: string;
|
||
|
||
@ApiProperty({
|
||
description: '错误消息',
|
||
example: '请先登录'
|
||
})
|
||
message: string;
|
||
}
|
||
|
||
@ApiTags('websocket')
|
||
@ApiExtraModels(
|
||
WebSocketLoginRequest,
|
||
WebSocketLoginSuccessResponse,
|
||
WebSocketChatRequest,
|
||
WebSocketChatResponse,
|
||
WebSocketPositionRequest,
|
||
WebSocketErrorResponse
|
||
)
|
||
@Controller('websocket-api')
|
||
export class WebSocketOpenApiController {
|
||
|
||
@Get('connection-info')
|
||
@ApiOperation({
|
||
summary: 'WebSocket 连接信息',
|
||
description: `
|
||
获取WebSocket连接的基本信息和配置
|
||
|
||
**连接地址**: \`wss://whaletownend.xinghangee.icu/game\`
|
||
|
||
**协议**: 原生WebSocket (非Socket.IO)
|
||
|
||
**认证**: 需要JWT Token
|
||
|
||
**架构更新**:
|
||
- ✅ 已从Socket.IO迁移到原生WebSocket
|
||
- ✅ 统一使用 /game 路径
|
||
- ✅ 支持地图房间管理
|
||
- ✅ 实现消息广播机制
|
||
|
||
**快速测试**:
|
||
- 🧪 [WebSocket 测试页面](/websocket-test?from=api-docs) - 交互式测试工具
|
||
- 📚 [完整 API 文档](/api-docs) - 返回 Swagger 文档
|
||
`
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: 'WebSocket连接配置信息',
|
||
schema: {
|
||
type: 'object',
|
||
properties: {
|
||
url: {
|
||
type: 'string',
|
||
example: 'wss://whaletownend.xinghangee.icu/game',
|
||
description: 'WebSocket服务器地址'
|
||
},
|
||
protocol: {
|
||
type: 'string',
|
||
example: 'native-websocket',
|
||
description: '使用原生WebSocket协议'
|
||
},
|
||
authentication: {
|
||
type: 'object',
|
||
properties: {
|
||
required: { type: 'boolean', example: true },
|
||
method: { type: 'string', example: 'JWT Token' },
|
||
tokenFormat: {
|
||
type: 'object',
|
||
properties: {
|
||
issuer: { type: 'string', example: 'whale-town' },
|
||
audience: { type: 'string', example: 'whale-town-users' },
|
||
type: { type: 'string', example: 'access' }
|
||
}
|
||
}
|
||
}
|
||
},
|
||
supportedMaps: {
|
||
type: 'array',
|
||
items: { type: 'string' },
|
||
example: ['whale_port', 'pumpkin_valley', 'novice_village']
|
||
}
|
||
}
|
||
}
|
||
})
|
||
getConnectionInfo() {
|
||
return {
|
||
url: 'wss://whaletownend.xinghangee.icu/game',
|
||
protocol: 'native-websocket',
|
||
path: '/game',
|
||
port: {
|
||
development: 3001,
|
||
production: 'via_nginx_proxy'
|
||
},
|
||
authentication: {
|
||
required: true,
|
||
method: 'JWT Token',
|
||
tokenFormat: {
|
||
issuer: 'whale-town',
|
||
audience: 'whale-town-users',
|
||
type: 'access',
|
||
requiredFields: ['sub', 'username', 'email', 'role']
|
||
}
|
||
},
|
||
supportedMaps: [
|
||
'whale_port',
|
||
'pumpkin_valley',
|
||
'novice_village'
|
||
],
|
||
features: [
|
||
'实时聊天',
|
||
'位置同步',
|
||
'地图房间管理',
|
||
'消息广播',
|
||
'连接状态监控',
|
||
'自动重连支持'
|
||
],
|
||
messageTypes: {
|
||
clientToServer: [
|
||
{
|
||
type: 'login',
|
||
description: '用户登录认证',
|
||
required: ['type', 'token']
|
||
},
|
||
{
|
||
type: 'chat',
|
||
description: '发送聊天消息',
|
||
required: ['t', 'content', 'scope']
|
||
},
|
||
{
|
||
type: 'position',
|
||
description: '更新位置信息',
|
||
required: ['t', 'x', 'y', 'mapId']
|
||
}
|
||
],
|
||
serverToClient: [
|
||
{
|
||
type: 'connected',
|
||
description: '连接确认'
|
||
},
|
||
{
|
||
type: 'login_success',
|
||
description: '登录成功'
|
||
},
|
||
{
|
||
type: 'login_error',
|
||
description: '登录失败'
|
||
},
|
||
{
|
||
type: 'chat_render',
|
||
description: '接收聊天消息'
|
||
},
|
||
{
|
||
type: 'position_update',
|
||
description: '位置更新广播'
|
||
},
|
||
{
|
||
type: 'error',
|
||
description: '通用错误消息'
|
||
}
|
||
]
|
||
},
|
||
connectionLimits: {
|
||
maxConnections: 1000,
|
||
sessionTimeout: 1800, // 30分钟
|
||
heartbeatInterval: 30000 // 30秒
|
||
}
|
||
};
|
||
}
|
||
|
||
@Post('login')
|
||
@ApiOperation({
|
||
summary: '用户登录 (WebSocket消息格式)',
|
||
description: `
|
||
**注意**: 这不是真实的REST API端点,而是WebSocket消息格式的文档展示
|
||
|
||
通过WebSocket发送此格式的消息来进行用户登录认证
|
||
|
||
**WebSocket连接后发送**:
|
||
\`\`\`json
|
||
{
|
||
"type": "login",
|
||
"token": "your_jwt_token_here"
|
||
}
|
||
\`\`\`
|
||
|
||
**成功响应**:
|
||
\`\`\`json
|
||
{
|
||
"t": "login_success",
|
||
"sessionId": "uuid",
|
||
"userId": "user_id",
|
||
"username": "username",
|
||
"currentMap": "whale_port"
|
||
}
|
||
\`\`\`
|
||
`
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: '登录成功响应格式',
|
||
type: WebSocketLoginSuccessResponse
|
||
})
|
||
@ApiResponse({
|
||
status: 400,
|
||
description: '登录失败响应格式',
|
||
schema: {
|
||
type: 'object',
|
||
properties: {
|
||
t: { type: 'string', example: 'login_error' },
|
||
message: { type: 'string', example: 'Token验证失败' }
|
||
}
|
||
}
|
||
})
|
||
websocketLogin(@Body() loginRequest: WebSocketLoginRequest) {
|
||
// 这个方法不会被实际调用,仅用于文档展示
|
||
return {
|
||
note: '这是WebSocket消息格式文档,请通过WebSocket连接发送消息',
|
||
websocketUrl: 'wss://whaletownend.xinghangee.icu/game',
|
||
messageFormat: loginRequest
|
||
};
|
||
}
|
||
|
||
@Post('chat')
|
||
@ApiOperation({
|
||
summary: '发送聊天消息 (WebSocket消息格式)',
|
||
description: `
|
||
**注意**: 这不是真实的REST API端点,而是WebSocket消息格式的文档展示
|
||
|
||
通过WebSocket发送聊天消息的格式
|
||
|
||
**发送消息**:
|
||
\`\`\`json
|
||
{
|
||
"t": "chat",
|
||
"content": "消息内容",
|
||
"scope": "local"
|
||
}
|
||
\`\`\`
|
||
|
||
**接收消息**:
|
||
\`\`\`json
|
||
{
|
||
"t": "chat_render",
|
||
"from": "发送者",
|
||
"txt": "消息内容",
|
||
"bubble": true,
|
||
"scope": "local",
|
||
"mapId": "whale_port"
|
||
}
|
||
\`\`\`
|
||
|
||
**消息范围说明**:
|
||
- \`local\`: 仅当前地图的玩家可见
|
||
- \`global\`: 所有在线玩家可见
|
||
`
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: '聊天消息广播格式',
|
||
type: WebSocketChatResponse
|
||
})
|
||
@ApiResponse({
|
||
status: 400,
|
||
description: '发送失败响应',
|
||
schema: {
|
||
type: 'object',
|
||
properties: {
|
||
t: { type: 'string', example: 'chat_error' },
|
||
message: { type: 'string', example: '消息内容不能为空' }
|
||
}
|
||
}
|
||
})
|
||
websocketChat(@Body() chatRequest: WebSocketChatRequest) {
|
||
return {
|
||
note: '这是WebSocket消息格式文档,请通过WebSocket连接发送消息',
|
||
websocketUrl: 'wss://whaletownend.xinghangee.icu/game',
|
||
messageFormat: chatRequest
|
||
};
|
||
}
|
||
|
||
@Post('position')
|
||
@ApiOperation({
|
||
summary: '位置更新 (WebSocket消息格式)',
|
||
description: `
|
||
**注意**: 这不是真实的REST API端点,而是WebSocket消息格式的文档展示
|
||
|
||
更新玩家位置信息,支持地图切换
|
||
|
||
**发送格式**:
|
||
\`\`\`json
|
||
{
|
||
"t": "position",
|
||
"x": 150,
|
||
"y": 400,
|
||
"mapId": "whale_port"
|
||
}
|
||
\`\`\`
|
||
|
||
**功能说明**:
|
||
- 自动处理地图房间切换
|
||
- 向同地图其他玩家广播位置更新
|
||
- 支持实时位置同步
|
||
`
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: '位置更新成功,无特定响应消息'
|
||
})
|
||
websocketPosition(@Body() positionRequest: WebSocketPositionRequest) {
|
||
return {
|
||
note: '这是WebSocket消息格式文档,请通过WebSocket连接发送消息',
|
||
websocketUrl: 'wss://whaletownend.xinghangee.icu/game',
|
||
messageFormat: positionRequest
|
||
};
|
||
}
|
||
|
||
@Get('message-flow')
|
||
@ApiOperation({
|
||
summary: 'WebSocket 消息流程图',
|
||
description: '展示WebSocket连接和消息交互的完整流程'
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: 'WebSocket交互流程',
|
||
schema: {
|
||
type: 'object',
|
||
properties: {
|
||
connectionFlow: {
|
||
type: 'array',
|
||
items: { type: 'string' },
|
||
example: [
|
||
'1. 建立WebSocket连接到 wss://whaletownend.xinghangee.icu/game',
|
||
'2. 发送login消息进行认证',
|
||
'3. 接收login_success确认',
|
||
'4. 发送chat/position消息进行交互',
|
||
'5. 接收其他玩家的消息广播'
|
||
]
|
||
}
|
||
}
|
||
}
|
||
})
|
||
getMessageFlow() {
|
||
return {
|
||
connectionFlow: [
|
||
'1. 建立WebSocket连接到 wss://whaletownend.xinghangee.icu/game',
|
||
'2. 发送login消息进行认证',
|
||
'3. 接收login_success确认',
|
||
'4. 发送chat/position消息进行交互',
|
||
'5. 接收其他玩家的消息广播'
|
||
],
|
||
messageTypes: {
|
||
clientToServer: [
|
||
'login - 用户登录认证',
|
||
'chat - 发送聊天消息',
|
||
'position - 更新位置信息'
|
||
],
|
||
serverToClient: [
|
||
'connected - 连接确认',
|
||
'login_success/login_error - 登录结果',
|
||
'chat_sent/chat_error - 消息发送结果',
|
||
'chat_render - 接收聊天消息',
|
||
'position_update - 位置更新广播',
|
||
'error - 通用错误消息'
|
||
]
|
||
},
|
||
exampleSession: {
|
||
step1: {
|
||
action: '建立连接',
|
||
client: 'new WebSocket("wss://whaletownend.xinghangee.icu/game")',
|
||
server: '{"type":"connected","message":"连接成功","socketId":"ws_123"}'
|
||
},
|
||
step2: {
|
||
action: '用户登录',
|
||
client: '{"type":"login","token":"jwt_token"}',
|
||
server: '{"t":"login_success","sessionId":"uuid","userId":"user_123","username":"Player","currentMap":"whale_port"}'
|
||
},
|
||
step3: {
|
||
action: '发送消息',
|
||
client: '{"t":"chat","content":"Hello!","scope":"local"}',
|
||
server: '{"t":"chat_sent","messageId":137,"message":"消息发送成功"}'
|
||
},
|
||
step4: {
|
||
action: '接收广播',
|
||
server: '{"t":"chat_render","from":"Player","txt":"Hello!","bubble":true,"scope":"local","mapId":"whale_port"}'
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
@Get('testing-tools')
|
||
@ApiOperation({
|
||
summary: 'WebSocket 测试工具推荐',
|
||
description: '推荐的WebSocket测试工具和示例代码'
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: '测试工具和示例代码',
|
||
})
|
||
getTestingTools() {
|
||
return {
|
||
onlineTools: [
|
||
{
|
||
name: 'WebSocket King',
|
||
url: 'https://websocketking.com/',
|
||
description: '在线WebSocket测试工具,支持消息发送和接收'
|
||
},
|
||
{
|
||
name: 'WebSocket Test Client',
|
||
url: 'https://www.websocket.org/echo.html',
|
||
description: '简单的WebSocket回显测试'
|
||
},
|
||
{
|
||
name: '内置测试页面',
|
||
url: '/websocket-test',
|
||
description: '项目内置的WebSocket测试界面,支持完整功能测试'
|
||
}
|
||
],
|
||
codeExamples: {
|
||
javascript: `
|
||
// JavaScript WebSocket 客户端示例
|
||
const ws = new WebSocket('wss://whaletownend.xinghangee.icu/game');
|
||
|
||
ws.onopen = function() {
|
||
console.log('连接成功');
|
||
// 发送登录消息
|
||
ws.send(JSON.stringify({
|
||
type: 'login',
|
||
token: 'your_jwt_token_here'
|
||
}));
|
||
};
|
||
|
||
ws.onmessage = function(event) {
|
||
const data = JSON.parse(event.data);
|
||
console.log('收到消息:', data);
|
||
|
||
if (data.t === 'login_success') {
|
||
// 登录成功,发送聊天消息
|
||
ws.send(JSON.stringify({
|
||
t: 'chat',
|
||
content: 'Hello from JavaScript!',
|
||
scope: 'local'
|
||
}));
|
||
}
|
||
};
|
||
|
||
ws.onclose = function(event) {
|
||
console.log('连接关闭:', event.code, event.reason);
|
||
};
|
||
|
||
ws.onerror = function(error) {
|
||
console.error('WebSocket错误:', error);
|
||
};
|
||
`,
|
||
python: `
|
||
# Python WebSocket 客户端示例
|
||
import websocket
|
||
import json
|
||
import threading
|
||
|
||
def on_message(ws, message):
|
||
data = json.loads(message)
|
||
print(f"收到消息: {data}")
|
||
|
||
if data.get('t') == 'login_success':
|
||
# 登录成功,发送聊天消息
|
||
ws.send(json.dumps({
|
||
't': 'chat',
|
||
'content': 'Hello from Python!',
|
||
'scope': 'local'
|
||
}))
|
||
|
||
def on_error(ws, error):
|
||
print(f"WebSocket错误: {error}")
|
||
|
||
def on_close(ws, close_status_code, close_msg):
|
||
print(f"连接关闭: {close_status_code} - {close_msg}")
|
||
|
||
def on_open(ws):
|
||
print("连接成功")
|
||
# 发送登录消息
|
||
ws.send(json.dumps({
|
||
'type': 'login',
|
||
'token': 'your_jwt_token_here'
|
||
}))
|
||
|
||
# 创建WebSocket连接
|
||
ws = websocket.WebSocketApp("wss://whaletownend.xinghangee.icu/game",
|
||
on_message=on_message,
|
||
on_error=on_error,
|
||
on_close=on_close,
|
||
on_open=on_open)
|
||
|
||
# 启动连接
|
||
ws.run_forever()
|
||
`,
|
||
nodejs: `
|
||
// Node.js WebSocket 客户端示例
|
||
const WebSocket = require('ws');
|
||
|
||
const ws = new WebSocket('wss://whaletownend.xinghangee.icu/game');
|
||
|
||
ws.on('open', function() {
|
||
console.log('连接成功');
|
||
|
||
// 发送登录消息
|
||
ws.send(JSON.stringify({
|
||
type: 'login',
|
||
token: 'your_jwt_token_here'
|
||
}));
|
||
});
|
||
|
||
ws.on('message', function(data) {
|
||
const message = JSON.parse(data.toString());
|
||
console.log('收到消息:', message);
|
||
|
||
if (message.t === 'login_success') {
|
||
// 登录成功,发送聊天消息
|
||
ws.send(JSON.stringify({
|
||
t: 'chat',
|
||
content: 'Hello from Node.js!',
|
||
scope: 'local'
|
||
}));
|
||
}
|
||
});
|
||
|
||
ws.on('close', function(code, reason) {
|
||
console.log(\`连接关闭: \${code} - \${reason}\`);
|
||
});
|
||
|
||
ws.on('error', function(error) {
|
||
console.error('WebSocket错误:', error);
|
||
});
|
||
`
|
||
},
|
||
testingSteps: [
|
||
'1. 访问测试页面: /websocket-test?from=api-docs',
|
||
'2. 点击"🚀 一键测试"按钮自动完成所有步骤',
|
||
'3. 或手动操作: 获取JWT Token → 连接 → 登录',
|
||
'4. 发送chat消息测试聊天功能',
|
||
'5. 发送position消息测试位置更新',
|
||
'6. 观察其他客户端的消息广播'
|
||
],
|
||
troubleshooting: {
|
||
connectionFailed: [
|
||
'检查网络连接是否正常',
|
||
'验证WebSocket服务器是否启动',
|
||
'确认防火墙设置允许WebSocket连接',
|
||
'检查SSL证书是否有效(WSS连接)'
|
||
],
|
||
authenticationFailed: [
|
||
'验证JWT Token是否有效且未过期',
|
||
'检查Token格式是否正确',
|
||
'确认Token包含必需的字段(sub, username, email, role)',
|
||
'验证Token的issuer和audience是否匹配'
|
||
],
|
||
messageFailed: [
|
||
'确认已完成登录认证',
|
||
'检查消息格式是否符合API规范',
|
||
'验证必需字段是否都已提供',
|
||
'检查消息内容是否符合长度限制'
|
||
]
|
||
}
|
||
};
|
||
}
|
||
|
||
@Get('architecture')
|
||
@ApiOperation({
|
||
summary: 'WebSocket 架构信息',
|
||
description: '展示WebSocket服务的技术架构和实现细节'
|
||
})
|
||
@ApiResponse({
|
||
status: 200,
|
||
description: 'WebSocket架构信息',
|
||
})
|
||
getArchitecture() {
|
||
return {
|
||
overview: {
|
||
title: 'WebSocket 架构概览',
|
||
description: '基于原生WebSocket的实时通信架构',
|
||
version: '2.1.0',
|
||
migrationFrom: 'Socket.IO',
|
||
migrationDate: '2026-01-09'
|
||
},
|
||
technicalStack: {
|
||
server: {
|
||
framework: 'NestJS',
|
||
websocketLibrary: 'ws (原生WebSocket)',
|
||
adapter: '@nestjs/platform-ws',
|
||
port: 3001,
|
||
path: '/game'
|
||
},
|
||
proxy: {
|
||
server: 'Nginx',
|
||
sslTermination: true,
|
||
loadBalancing: 'Single Instance',
|
||
pathRouting: '/game -> localhost:3001'
|
||
},
|
||
authentication: {
|
||
method: 'JWT Bearer Token',
|
||
validation: 'Real-time on connection',
|
||
sessionManagement: 'In-memory with Redis backup'
|
||
}
|
||
},
|
||
features: {
|
||
connectionManagement: {
|
||
maxConnections: 1000,
|
||
connectionPooling: true,
|
||
automaticReconnection: 'Client-side',
|
||
heartbeat: '30s interval'
|
||
},
|
||
messaging: {
|
||
messageTypes: ['login', 'chat', 'position'],
|
||
messageRouting: 'Room-based (by map)',
|
||
messageFiltering: 'Content and rate limiting',
|
||
messageHistory: 'Not stored (real-time only)'
|
||
},
|
||
roomManagement: {
|
||
strategy: 'Map-based rooms',
|
||
autoJoin: 'On position update',
|
||
autoLeave: 'On disconnect or map change',
|
||
broadcasting: 'Room-scoped and global'
|
||
}
|
||
},
|
||
performance: {
|
||
latency: '< 50ms (local network)',
|
||
throughput: '1000+ messages/second',
|
||
memoryUsage: '~1MB per 100 connections',
|
||
cpuUsage: 'Low (event-driven)'
|
||
},
|
||
monitoring: {
|
||
metrics: [
|
||
'Active connections count',
|
||
'Messages per second',
|
||
'Authentication success rate',
|
||
'Error rate by type'
|
||
],
|
||
logging: [
|
||
'Connection events',
|
||
'Authentication attempts',
|
||
'Message routing',
|
||
'Error conditions'
|
||
],
|
||
healthCheck: '/chat/status endpoint'
|
||
},
|
||
security: {
|
||
authentication: 'JWT Token validation',
|
||
authorization: 'Role-based access control',
|
||
rateLimit: 'Per-user message rate limiting',
|
||
contentFilter: 'Sensitive word filtering',
|
||
inputValidation: 'Message format validation'
|
||
},
|
||
deployment: {
|
||
environment: 'Production ready',
|
||
scaling: 'Horizontal scaling supported',
|
||
backup: 'Session state in Redis',
|
||
monitoring: 'Integrated with application monitoring'
|
||
}
|
||
};
|
||
}
|
||
} |