From 3d204980a2a7461d7123c00622d41a3417fdece7 Mon Sep 17 00:00:00 2001 From: MoeSnowyFox Date: Wed, 1 Oct 2025 18:06:24 +0800 Subject: [PATCH] =?UTF-8?q?docs(websocket):=20=E6=B7=BB=E5=8A=A0useWebSock?= =?UTF-8?q?et=E5=8F=82=E8=80=83=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/useWebSocket_API_Reference.md | 427 +++++++++++++++++++++++++++++ docs/useWebSocket_Analysis.md | 336 +++++++++++++++++++++++ 2 files changed, 763 insertions(+) create mode 100644 docs/useWebSocket_API_Reference.md create mode 100644 docs/useWebSocket_Analysis.md diff --git a/docs/useWebSocket_API_Reference.md b/docs/useWebSocket_API_Reference.md new file mode 100644 index 0000000..7cc0450 --- /dev/null +++ b/docs/useWebSocket_API_Reference.md @@ -0,0 +1,427 @@ +# useWebSocket API 参考文档 + +## 概述 + +`useWebSocket()` 组合式函数提供了完整的 WebSocket 通信接口,包含消息订阅、连接管理、状态监控等核心功能。 + +## 导出函数详解 + +### 1. subscribe() - 订阅消息 + +```typescript +const subscribe = ( + filter: SubscriptionFilter, + handler: (message: WebSocketBaseMessage) => void +): string +``` + +#### 参数说明 + +**filter: SubscriptionFilter** +```typescript +interface SubscriptionFilter { + type?: string // 消息类型过滤器(可选) + id?: string // 消息ID过滤器(可选) + needCache?: boolean // 是否启用缓存回放(可选) +} +``` + +**handler: Function** +- 消息处理回调函数 +- 参数: `message: WebSocketBaseMessage` +- 无返回值 + +#### 返回值 +- `string`: 唯一的订阅ID,用于后续取消订阅 + +#### 使用示例 + +```typescript +// 订阅所有消息 +const allMsgSub = subscribe({}, (msg) => { + console.log('收到消息:', msg) +}) + +// 订阅特定类型消息 +const taskSub = subscribe( + { type: 'TaskUpdate', needCache: true }, + (msg) => { + console.log('任务更新:', msg.data) + } +) + +// 订阅特定ID消息 +const specificSub = subscribe( + { id: 'TaskManager' }, + (msg) => { + console.log('任务管理器消息:', msg) + } +) + +// 精确订阅(同时匹配type和id) +const preciseSub = subscribe( + { type: 'Progress', id: 'task_001', needCache: true }, + (msg) => { + console.log('特定任务进度:', msg.data) + } +) +``` + +#### 特殊功能 +- **自动回放**: 如果 `needCache: true`,会立即回放匹配的历史消息 +- **过滤优先级**: type + id > type > id > 全部 +- **引用计数**: 多个订阅共享缓存,自动管理内存 + +--- + +### 2. unsubscribe() - 取消订阅 + +```typescript +const unsubscribe = (subscriptionId: string): void +``` + +#### 参数说明 + +**subscriptionId: string** +- 由 `subscribe()` 返回的订阅ID +- 必须是有效的订阅ID + +#### 使用示例 + +```typescript +const subId = subscribe({ type: 'TaskUpdate' }, handleTaskUpdate) + +// 取消订阅 +unsubscribe(subId) + +// Vue 组件中的最佳实践 +import { onUnmounted } from 'vue' + +const setupSubscription = () => { + const subId = subscribe({ type: 'TaskUpdate' }, handleTaskUpdate) + + onUnmounted(() => { + unsubscribe(subId) + }) +} +``` + +#### 自动清理 +- 自动减少缓存引用计数 +- 引用计数为0时清理相关缓存 +- 不会影响其他订阅者 + +--- + +### 3. sendRaw() - 发送消息 + +```typescript +const sendRaw = (type: string, data?: any, id?: string): void +``` + +#### 参数说明 + +**type: string** (必需) +- 消息类型标识 +- 后端用于路由消息 + +**data: any** (可选) +- 消息负载数据 +- 可以是任何可序列化的对象 + +**id: string** (可选) +- 消息标识符 +- 用于消息跟踪和响应匹配 + +#### 使用示例 + +```typescript +// 发送简单消息 +sendRaw('Hello') + +// 发送带数据的消息 +sendRaw('TaskStart', { + taskId: '12345', + config: { timeout: 30000 } +}) + +// 发送带ID的消息(便于追踪响应) +sendRaw('GetTaskStatus', { taskId: '12345' }, 'query_001') + +// 发送控制信号 +sendRaw('Signal', { + command: 'pause', + reason: '用户手动暂停' +}, 'TaskManager') +``` + +#### 发送条件 +- 仅在 WebSocket 连接为 `OPEN` 状态时发送 +- 连接异常时静默失败(不抛出异常) +- 自动JSON序列化 + +--- + +### 4. getConnectionInfo() - 获取连接信息 + +```typescript +const getConnectionInfo = (): ConnectionInfo +``` + +#### 返回值类型 + +```typescript +interface ConnectionInfo { + connectionId: string // 连接唯一标识 + status: WebSocketStatus // 当前连接状态 + subscriberCount: number // 当前订阅者数量 + moduleLoadCount: number // 模块加载计数 + wsReadyState: number | null // WebSocket原生状态 + isConnecting: boolean // 是否正在连接 + hasHeartbeat: boolean // 是否启用心跳 + hasEverConnected: boolean // 是否曾经连接成功 + reconnectAttempts: number // 重连尝试次数 + isPersistentMode: boolean // 是否持久化模式 +} +``` + +#### 使用示例 + +```typescript +const info = getConnectionInfo() + +console.log('连接ID:', info.connectionId) +console.log('连接状态:', info.status) +console.log('订阅者数量:', info.subscriberCount) + +// 检查连接是否健康 +const isHealthy = info.status === '已连接' && + info.hasHeartbeat && + info.wsReadyState === WebSocket.OPEN + +// 监控重连情况 +if (info.reconnectAttempts > 0) { + console.log(`已重连 ${info.reconnectAttempts} 次`) +} +``` + +#### 调试用途 +- 诊断连接问题 +- 监控连接质量 +- 统计使用情况 + +--- + +### 5. status - 连接状态 + +```typescript +const status: Ref +``` + +#### 状态类型 + +```typescript +type WebSocketStatus = '连接中' | '已连接' | '已断开' | '连接错误' +``` + +#### 状态说明 + +| 状态 | 描述 | 触发条件 | +|------|------|----------| +| `'连接中'` | 正在建立连接 | WebSocket.CONNECTING | +| `'已连接'` | 连接成功 | WebSocket.OPEN | +| `'已断开'` | 连接断开 | WebSocket.CLOSED | +| `'连接错误'` | 连接异常 | WebSocket.onerror | + +#### 使用示例 + +```typescript +import { watch } from 'vue' + +const { status } = useWebSocket() + +// 监听状态变化 +watch(status, (newStatus) => { + console.log('连接状态变化:', newStatus) + + switch (newStatus) { + case '已连接': + console.log('✅ WebSocket 连接成功') + break + case '已断开': + console.log('❌ WebSocket 连接断开') + break + case '连接错误': + console.log('⚠️ WebSocket 连接错误') + break + case '连接中': + console.log('🔄 WebSocket 连接中...') + break + } +}) + +// 在模板中显示状态 +//
连接状态: {{ status }}
+``` + +#### 响应式特性 +- Vue 响应式 Ref 对象 +- 自动更新 UI +- 可用于计算属性和监听器 + +--- + +### 6. backendStatus - 后端状态 + +```typescript +const backendStatus: Ref +``` + +#### 状态类型 + +```typescript +type BackendStatus = 'unknown' | 'starting' | 'running' | 'stopped' | 'error' +``` + +#### 状态说明 + +| 状态 | 描述 | 含义 | +|------|------|------| +| `'unknown'` | 未知状态 | 初始状态,尚未检测 | +| `'starting'` | 启动中 | 后端服务正在启动 | +| `'running'` | 运行中 | 后端服务正常运行 | +| `'stopped'` | 已停止 | 后端服务已停止 | +| `'error'` | 错误状态 | 后端服务异常 | + +#### 使用示例 + +```typescript +const { backendStatus, restartBackend } = useWebSocket() + +// 监听后端状态 +watch(backendStatus, (newStatus) => { + console.log('后端状态:', newStatus) + + switch (newStatus) { + case 'running': + console.log('✅ 后端服务运行正常') + break + case 'stopped': + console.log('⏹️ 后端服务已停止') + break + case 'error': + console.log('❌ 后端服务异常') + // 可以提示用户或自动重启 + break + case 'starting': + console.log('🚀 后端服务启动中...') + break + } +}) + +// 根据状态显示不同UI +const statusColor = computed(() => { + switch (backendStatus.value) { + case 'running': return 'green' + case 'error': return 'red' + case 'starting': return 'orange' + default: return 'gray' + } +}) +``` + +#### 自动管理 +- 每3秒自动检测一次 +- 异常时自动尝试重启(最多3次) +- 集成 Electron 进程管理 + +--- + +## 完整使用示例 + +```typescript +import { onMounted, onUnmounted, watch } from 'vue' +import { useWebSocket } from '@/composables/useWebSocket' + +export default { + setup() { + const { + subscribe, + unsubscribe, + sendRaw, + getConnectionInfo, + status, + backendStatus + } = useWebSocket() + + let taskSubscription: string + let systemSubscription: string + + onMounted(() => { + // 订阅任务消息 + taskSubscription = subscribe( + { type: 'TaskUpdate', needCache: true }, + (message) => { + console.log('任务更新:', message.data) + } + ) + + // 订阅系统消息 + systemSubscription = subscribe( + { id: 'System' }, + (message) => { + console.log('系统消息:', message) + } + ) + + // 发送初始化消息 + sendRaw('ClientReady', { + timestamp: Date.now() + }, 'System') + }) + + onUnmounted(() => { + // 清理订阅 + if (taskSubscription) unsubscribe(taskSubscription) + if (systemSubscription) unsubscribe(systemSubscription) + }) + + // 监听连接状态 + watch([status, backendStatus], ([wsStatus, beStatus]) => { + console.log(`WS: ${wsStatus}, Backend: ${beStatus}`) + }) + + // 获取连接信息 + const connectionInfo = getConnectionInfo() + + return { + status, + backendStatus, + connectionInfo, + sendMessage: (type: string, data: any) => sendRaw(type, data) + } + } +} +``` + +## 最佳实践 + +### 1. 订阅管理 +- 总是在组件卸载时取消订阅 +- 使用 `needCache: true` 确保不丢失消息 +- 避免重复订阅相同的消息类型 + +### 2. 错误处理 +- 监听连接状态变化 +- 根据后端状态调整UI显示 +- 实现重连提示和手动重启 + +### 3. 性能优化 +- 精确的过滤条件减少不必要的处理 +- 合理使用缓存避免消息丢失 +- 及时取消不需要的订阅 + +### 4. 调试技巧 +- 使用 `getConnectionInfo()` 诊断问题 +- 开发环境下查看控制台日志 +- 监控订阅者数量避免内存泄漏 \ No newline at end of file diff --git a/docs/useWebSocket_Analysis.md b/docs/useWebSocket_Analysis.md new file mode 100644 index 0000000..f7fb9d2 --- /dev/null +++ b/docs/useWebSocket_Analysis.md @@ -0,0 +1,336 @@ +## 核心架构设计 + +### 1. 全局持久化存储 + +```typescript +const WS_STORAGE_KEY = Symbol.for('GLOBAL_WEBSOCKET_PERSISTENT') +``` + +- 使用 `Symbol.for()` 确保全局唯一性 +- 存储在 `window` 对象上,实现跨组件共享 +- 避免多次实例化,确保连接唯一性 + +### 2. 状态管理结构 + +```typescript +interface GlobalWSStorage { + wsRef: WebSocket | null // WebSocket 实例 + status: Ref // 连接状态 + subscriptions: Ref> // 订阅管理 + cacheMarkers: Ref> // 缓存标记 + cachedMessages: Ref> // 消息缓存 + // ... 其他状态 +} +``` + +## 核心功能模块 + +### 1. 配置管理 + +```typescript +const BASE_WS_URL = 'ws://localhost:36163/api/core/ws' +const HEARTBEAT_INTERVAL = 15000 // 心跳间隔 +const HEARTBEAT_TIMEOUT = 5000 // 心跳超时 +const BACKEND_CHECK_INTERVAL = 3000 // 后端检查间隔 +const MAX_RESTART_ATTEMPTS = 3 // 最大重启尝试次数 +const RESTART_DELAY = 2000 // 重启延迟 +const MAX_QUEUE_SIZE = 50 // 最大队列大小 +const MESSAGE_TTL = 60000 // 消息过期时间 +``` + +**要点**: +- 所有时间配置使用毫秒为单位 +- 可根据网络环境调整超时时间 +- 队列大小限制防止内存泄漏 + +### 2. 消息订阅系统 + +#### 订阅过滤器 +```typescript +interface SubscriptionFilter { + type?: string // 消息类型过滤 + id?: string // 消息ID过滤 + needCache?: boolean // 是否需要缓存 +} +``` + +#### 订阅机制 +```typescript +export const subscribe = ( + filter: SubscriptionFilter, + handler: (message: WebSocketBaseMessage) => void +): string => { + // 1. 生成唯一订阅ID + // 2. 创建订阅记录 + // 3. 添加缓存标记 + // 4. 回放匹配的缓存消息 +} +``` + +**要点**: +- 支持按 `type` 和 `id` 的组合过滤 +- 自动回放缓存消息,确保不丢失历史数据 +- 返回订阅ID用于后续取消订阅 + +### 3. 智能缓存系统 + +#### 缓存标记机制 +```typescript +interface CacheMarker { + type?: string + id?: string + refCount: number // 引用计数 +} +``` + +#### 缓存策略 +- **引用计数**: 订阅时 +1,取消订阅时 -1 +- **自动清理**: 引用计数为 0 时删除标记 +- **TTL机制**: 消息超过 60 秒自动过期 +- **大小限制**: 每个队列最多保留 50 条消息 + + +### 4. 心跳检测机制 + +```typescript +const startGlobalHeartbeat = (ws: WebSocket) => { + global.heartbeatTimer = window.setInterval(() => { + if (ws.readyState === WebSocket.OPEN) { + const pingTime = Date.now() + global.lastPingTime = pingTime + ws.send(JSON.stringify({ + type: 'Signal', + data: { Ping: pingTime, connectionId: global.connectionId } + })) + } + }, HEARTBEAT_INTERVAL) +} +``` + + +### 5. 后端服务监控 + +#### 状态检测 +```typescript +type BackendStatus = 'unknown' | 'starting' | 'running' | 'stopped' | 'error' +``` + +#### 自动重启逻辑 +```typescript +const restartBackend = async (): Promise => { + // 1. 防重入检查 + // 2. 递增重启计数 + // 3. 调用 Electron API 启动后端 + // 4. 更新状态 +} +``` + + +### 6. 连接控制机制 + +#### 连接权限控制 +```typescript +const allowedConnectionReasons = ['后端启动后连接', '后端重启后重连'] +const checkConnectionPermission = () => getGlobalStorage().allowNewConnection +``` + +#### 连接锁机制 +```typescript +let isGlobalConnectingLock = false +const acquireConnectionLock = () => { + if (isGlobalConnectingLock) return false + isGlobalConnectingLock = true + return true +} +``` + +**AI 开发要点**: +- 防止并发连接导致的竞态条件 +- 只允许特定原因的连接请求 +- 确保全局唯一连接 + +## 消息流处理 + +### 1. 消息匹配算法 + +```typescript +const messageMatchesFilter = (message: WebSocketBaseMessage, filter: SubscriptionFilter): boolean => { + // 如果都不指定,匹配所有消息 + if (!filter.type && !filter.id) return true + + // 如果只指定type + if (filter.type && !filter.id) return message.type === filter.type + + // 如果只指定id + if (!filter.type && filter.id) return message.id === filter.id + + // 如果同时指定type和id,必须都匹配 + return message.type === filter.type && message.id === filter.id +} +``` + +### 2. 消息分发流程 + +``` +WebSocket 接收消息 + ↓ +JSON 解析 + ↓ +遍历所有订阅者 + ↓ +匹配过滤条件 + ↓ +调用处理器函数 + ↓ +检查是否需要缓存 + ↓ +添加到缓存队列 +``` + +## 外部接口设计 + +### 1. 主要导出函数 + +```typescript +export function useWebSocket() { + return { + subscribe, // 订阅消息 + unsubscribe, // 取消订阅 + sendRaw, // 发送消息 + getConnectionInfo, // 获取连接信息 + status, // 连接状态 + backendStatus, // 后端状态 + restartBackend, // 重启后端 + getBackendStatus, // 获取后端状态 + } +} +``` + +### 2. 特殊接口 + +```typescript +export const connectAfterBackendStart = async (): Promise +``` +- 后端启动后的连接入口 +- 启动后端监控 +- 设置连接权限 + +## 错误处理策略 + +### 1. 连接错误处理 +- WebSocket 连接失败时设置状态为 '连接错误' +- 通过后端监控检测服务状态 +- 自动重启后端服务 + +### 2. 消息处理错误 +- 订阅处理器异常时记录警告但不中断其他订阅者 +- JSON 解析失败时静默忽略 +- 发送消息失败时静默处理 + +### 3. 后端故障处理 +```typescript +const handleBackendFailure = async () => { + if (global.backendRestartAttempts >= MAX_RESTART_ATTEMPTS) { + // 显示错误对话框,提示重启应用 + Modal.error({ + title: '后端服务异常', + content: '后端服务多次重启失败,请重启整个应用程序。' + }) + return + } + // 自动重启逻辑 +} +``` + +## 调试和监控 + +### 1. 调试模式 +```typescript +const DEBUG = process.env.NODE_ENV === 'development' +const log = (...args: any[]) => { + if (DEBUG) console.log('[WebSocket]', ...args) +} +``` + +### 2. 连接信息监控 +```typescript +const getConnectionInfo = () => ({ + connectionId: global.connectionId, + status: global.status.value, + subscriberCount: global.subscriptions.value.size, + moduleLoadCount: global.moduleLoadCount, + wsReadyState: global.wsRef ? global.wsRef.readyState : null, + isConnecting: global.isConnecting, + hasHeartbeat: !!global.heartbeatTimer, + hasEverConnected: global.hasEverConnected, + reconnectAttempts: global.reconnectAttempts, + isPersistentMode: true, +}) +``` + +## AI 开发建议 + +### 1. 使用模式 +```typescript +// 在 Vue 组件中使用 +const { subscribe, unsubscribe, sendRaw, status } = useWebSocket() + +// 订阅特定类型消息 +const subId = subscribe( + { type: 'TaskUpdate', needCache: true }, + (message) => { + console.log('收到任务更新:', message.data) + } +) + +// 组件卸载时取消订阅 +onUnmounted(() => { + unsubscribe(subId) +}) +``` + +### 2. 扩展建议 +- 添加消息重试机制 +- 实现消息优先级队列 +- 支持消息压缩 +- 添加连接质量监控 + +### 3. 性能优化点 +- 使用 `Object.freeze()` 冻结配置对象 +- 考虑使用 Web Worker 处理大量消息 +- 实现消息批处理机制 +- 添加消息去重功能 + +### 4. 安全考虑 +- 验证消息来源 +- 实现消息签名机制 +- 添加连接认证 +- 防止消息注入攻击 + +## 依赖关系 + +### 1. 外部依赖 +- `vue`: 响应式系统和组合式API +- `ant-design-vue`: UI组件库(Modal) +- `schedulerHandlers`: 默认消息处理器 + +### 2. 运行时依赖 +- `window.electronAPI`: Electron主进程通信 +- WebSocket API: 浏览器原生支持 + +## 总结 + +这个 WebSocket 组合式函数是一个功能完整、设计精良的实时通信解决方案。它不仅解决了基本的 WebSocket 连接问题,还提供了高级功能如智能缓存、自动重连、后端监控等。 + +**核心优势**: +1. 全局持久化连接,避免重复建立 +2. 智能订阅系统,支持精确过滤 +3. 自动缓存回放,确保数据完整性 +4. 完善的错误处理和自动恢复 +5. 详细的调试和监控信息 + +**适用场景**: +- 实时数据展示 +- 任务状态监控 +- 系统通知推送 +- 双向通信应用 \ No newline at end of file