You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

17 KiB

修改记录

2025-08-11

WebSocket SSL证书验证冲突修复

问题:WebSocket客户端连接时出现SSL配置冲突错误

Cannot set verify_mode to CERT_NONE when check_hostname is enabled.

根本原因:在SSL上下文中,当设置verify_mode = ssl.CERT_NONE时,如果check_hostname仍然为True,就会出现配置冲突。

解决方案:修复SSL配置逻辑,确保当不验证证书时同时禁用主机名检查

文件变更

  • 更新 app/core/websocket/client.py - 修复SSL配置冲突

修改内容

# 根据配置决定是否验证证书和主机名
# 先设置check_hostname,再设置verify_mode
if not config.websocket.ssl_verify_hostname:
    ssl_context.check_hostname = False

if not config.websocket.ssl_verify_certificate:
    ssl_context.verify_mode = ssl.CERT_NONE

修复逻辑

  • 先设置check_hostname,再设置verify_mode,避免配置冲突
  • ssl_verify_hostname = False时,设置check_hostname = False
  • ssl_verify_certificate = False时,设置verify_mode = ssl.CERT_NONE
  • 确保SSL配置的正确顺序和一致性

配置建议

# 开发环境(跳过所有SSL验证)
WEBSOCKET_SSL_VERIFY_CERTIFICATE=false
WEBSOCKET_SSL_VERIFY_HOSTNAME=false

# 生产环境(启用SSL验证)
WEBSOCKET_SSL_VERIFY_CERTIFICATE=true
WEBSOCKET_SSL_VERIFY_HOSTNAME=true

注意事项

  • 修复了SSL配置冲突问题
  • 保持了配置的灵活性
  • 开发环境默认跳过SSL验证
  • 生产环境建议启用SSL验证

测试验证: 创建了 test_websocket_ssl_fix.py 测试脚本验证修复效果:

python test_websocket_ssl_fix.py

测试结果:

  • 配置值测试通过
  • WebSocket客户端创建测试通过
  • SSL配置逻辑测试通过
  • 所有测试通过,修复成功

WebSocket SSL证书验证问题修复

WebSocket SSL证书验证问题修复

问题:WebSocket客户端连接时出现SSL证书验证失败错误

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:997)

解决方案:在WebSocket客户端连接时跳过SSL证书验证(仅用于开发测试)

文件变更

  • 更新 app/core/websocket/client.py - 在connect方法中添加SSL证书验证跳过逻辑

修改内容

# 建立WebSocket连接
# 根据配置决定是否跳过SSL证书验证
ssl_context = None
if self.url.startswith('wss://'):
    from app.core.config.settings import config
    import ssl
    ssl_context = ssl.create_default_context()
    
    # 根据配置决定是否验证证书和主机名
    if not config.websocket.ssl_verify_certificate:
        ssl_context.verify_mode = ssl.CERT_NONE
    if not config.websocket.ssl_verify_hostname:
        ssl_context.check_hostname = False

self._websocket = await websockets.connect(self.url, ssl=ssl_context)

配置化设计

  • app/core/config/settings.py 中添加 WebSocketConfig
  • 支持通过环境变量或配置文件控制SSL验证行为
  • 默认开发环境跳过证书验证,生产环境可通过配置启用

环境变量配置

# 开发环境(跳过SSL验证)
WEBSOCKET_SSL_VERIFY_CERTIFICATE=false
WEBSOCKET_SSL_VERIFY_HOSTNAME=false

# 生产环境(启用SSL验证)
WEBSOCKET_SSL_VERIFY_CERTIFICATE=true
WEBSOCKET_SSL_VERIFY_HOSTNAME=true

注意事项

  • 开发环境默认跳过SSL证书验证
  • 生产环境建议启用SSL证书验证
  • 可通过环境变量灵活配置

相关修改

  • 启用 requirements.txt 中的 websockets==12.0 依赖
  • 添加 WebSocketConfig 配置类到 app/core/config/settings.py
  • 创建 test_websocket_ssl.py 测试脚本验证修复效果

测试验证: 运行测试脚本验证修复效果:

python test_websocket_ssl.py

2025-08-07

日志系统简化优化

问题:用户要求简化日志系统,不要创建太多日志文件,只分异常和非异常两种

解决方案:重构日志系统,只创建两个日志文件:

  • logs/app.log - 正常日志(DEBUG、INFO、WARNING级别)
  • logs/error.log - 异常日志(ERROR、CRITICAL级别)

文件变更

  • 更新 app/utils/structured_log.py - 重构 _setup_handlers() 方法

优化内容

# 根据日志级别选择文件
# ERROR和CRITICAL级别写入异常日志文件
# 其他级别写入正常日志文件
error_handler = logging.FileHandler("logs/error.log", encoding='utf-8')
error_handler.setLevel(logging.ERROR)
error_handler.setFormatter(StructuredFormatter(include_stack_trace=True))

normal_handler = logging.FileHandler("logs/app.log", encoding='utf-8')
normal_handler.setLevel(logging.DEBUG)
normal_handler.setFormatter(StructuredFormatter(include_stack_trace=False))

优势

  • 简化日志文件管理,只有两个文件
  • 异常日志包含完整堆栈跟踪
  • 正常日志不包含堆栈跟踪,减少文件大小
  • 按日志级别自动分流
  • 保持控制台输出功能

WebSocket API优化

WebSocket API优化

问题:用户指出"创建Channel请求 不是请求的时候创建",需要优化WebSocket API架构

解决方案:重新设计WebSocket API,使用预创建Channel模式,并简化为只包含获取、连接、停止功能

文件变更

  • 创建 app/schemas/websocket.py - WebSocket相关的Pydantic模型
  • 创建 app/utils/api_decorators.py - API错误处理装饰器
  • 更新 app/services/websocket_service.py - 支持预创建Channel和初始化配置
  • 更新 app/api/v1/endpoints/websocket.py - 使用Pydantic模型,简化为获取、连接、停止功能
  • 更新 app/core/app/factory.py - 应用启动时初始化WebSocket服务

架构优化

1. 预创建Channel模式

  • 应用启动时自动创建默认Channel(default, system, events)
  • 移除动态创建Channel的API
  • 支持配置化的Channel管理

2. 简化的API设计

根据用户要求"websocket.py 应只需要获取 跟 连接 跟 停止",简化为三个核心功能:

获取功能

  • GET /websocket/clients - 获取所有客户端
  • GET /websocket/channels - 获取所有Channel
  • GET /websocket/stats - 获取统计信息

连接功能

  • POST /websocket/clients - 创建客户端
  • POST /websocket/clients/{name}/connect - 连接客户端
  • POST /websocket/subscribe - 订阅Channel
  • POST /websocket/message/send - 发送消息
  • POST /websocket/message/broadcast - 广播消息

停止功能

  • POST /websocket/clients/{name}/disconnect - 断开客户端
  • DELETE /websocket/clients/{name} - 移除客户端
  • POST /websocket/unsubscribe - 取消订阅

3. Pydantic模型验证

  • 使用Pydantic进行请求参数验证
  • 统一的响应格式
  • 类型安全的API接口

4. 错误处理优化

  • 统一的错误处理装饰器
  • 标准化的错误响应格式
  • 更好的错误日志记录

移除的API

  • POST /websocket/channels - 动态创建Channel
  • DELETE /websocket/channels/{name} - 移除Channel
  • GET /websocket/adapters - 获取适配器
  • POST /websocket/adapters - 创建适配器
  • DELETE /websocket/adapters - 移除适配器
  • POST /websocket/initialize - 初始化服务

配置化设计

class WebSocketConfig(BaseModel):
    default_channels: List[str] = ["default", "system", "events"]
    max_channel_size: int = 1000
    heartbeat_interval: int = 30
    reconnect_attempts: int = 5
    reconnect_delay: float = 1.0

优势

  • 更清晰的API设计,只包含核心功能
  • 预创建Channel,避免运行时创建
  • 统一的参数验证和错误处理
  • 配置化的服务管理
  • 更好的类型安全性
  • 简化的使用流程

WebSocket架构重构

问题:用户反馈"client.py 为啥有 channel 不应该只要读取channel 数据发 接收数据往channel 插入吗",指出WebSocket架构设计不合理。

解决方案:引入适配器模式,重新设计WebSocket架构

  • WebSocketClient: 只负责WebSocket连接和数据收发
  • WebSocketChannel: 负责数据存储和队列管理
  • WebSocketAdapter: 负责连接Client和Channel,实现数据双向流动

文件变更

  • 创建 app/core/websocket/ 模块
  • 创建 app/core/websocket/client.py - WebSocket客户端
  • 创建 app/core/websocket/channel.py - 数据通道
  • 创建 app/core/websocket/adapter.py - 适配器
  • 创建 app/core/websocket/manager.py - 管理器
  • 创建 app/services/websocket_service.py - 业务服务
  • 创建 app/api/v1/endpoints/websocket.py - API接口

架构优势

  • 遵循单一职责原则
  • 清晰的层次结构
  • 易于扩展和维护
  • 支持数据双向流动

数据流

WebSocket服务器 ↔ WebSocketClient ↔ WebSocketAdapter ↔ WebSocketChannel

Channel生命周期管理完善

问题:用户指出"没有遵循单一原则是 channel.py他stop 之后能使用吗 ,二次连接webscoket 还能有吗 生命周期"

解决方案:完善Channel的生命周期管理

  • 添加 reconnect() 方法 - 重新连接功能
  • 添加 reset() 方法 - 重置状态功能
  • 添加 destroy() 方法 - 完全销毁功能
  • 添加 connection_count 属性 - 连接次数统计
  • 完善状态管理和错误处理

文件变更

  • 更新 app/core/websocket/channel.py - 完善生命周期管理

功能验证

  • 支持连接/断开/重连循环
  • 状态管理正确
  • 资源清理完整
  • 二次连接支持

WebSocket Stop方法分析

问题:检查WebSocket架构中各个组件的stop方法是否停止干净,以及二次连接的支持情况

分析结果

Stop方法停止干净度: 优秀

  • WebSocketClient.disconnect(): 正确取消任务、关闭连接、清理资源
  • WebSocketAdapter.stop(): 正确取消发送任务、清理消息处理器
  • WebSocketManager.cleanup(): 按正确顺序清理所有资源

二次连接支持: 完整

  • WebSocketClient: 支持重复连接,状态检查正确
  • WebSocketChannel: 支持重新连接,连接次数统计
  • WebSocketAdapter: 可以重新启动,任务重新创建

架构优势

  • 所有组件都正确取消异步任务
  • 正确清理资源引用
  • 状态管理完整
  • 支持完整的连接-断开-重连循环

设备管理API重构

问题:用户要求"注册新设备 更新设备 注册设备 api 不对外开放 因为 这是都是需要自动"

解决方案:移除外部设备管理API,保留内部自动化接口

文件变更

  • 更新 app/api/v1/endpoints/devices.py - 移除以下API:
    • POST /devices/register - 注册新设备
    • PUT /devices/{device_id}/update - 更新设备
    • DELETE /devices/{device_id}/unregister - 注销设备
    • GET /devices/{device_id}/status - 获取设备状态
    • GET /devices/protocol/{protocol_type} - 按协议过滤设备

保留功能

  • 设备操作API(点击、输入、截图等)
  • ADB管理功能
  • 设备列表查询(只读)

设计原则

  • 设备注册/更新/注销由系统自动管理
  • 外部API只提供设备操作功能
  • 提高系统安全性和稳定性

设备管理架构重构

问题:用户反馈"不用代理冗余代码,后面难以维护",要求移除冗余API文件

解决方案:完全移除冗余文件,统一到devices.py

文件变更

  • 删除 app/api/v1/endpoints/device_operations.py
  • 删除 app/api/v1/endpoints/enhanced_adb.py
  • 删除 app/api/v1/endpoints/unified_devices.py
  • 更新 app/api/v1/endpoints/devices.py - 整合所有设备管理功能
  • 重命名 app/services/unified_device_service.pyapp/services/device_service.py
  • 重命名 app/services/enhanced_adb_service.pyapp/services/auto_discovery_adb_service.py

架构优化

  • 单一入口点:/api/v1/devices
  • 统一设备管理:支持注册设备和自动发现设备
  • 清晰的责任分离:API层、服务层、核心层

设备管理器增强

问题:用户选择"方案B:在 DeviceManager 中添加自动发现设备管理"

解决方案:在DeviceManager中集成自动发现设备管理

文件变更

  • 更新 app/core/device/manager.py - 添加自动发现设备管理
  • 更新 app/services/device_service.py - 使用统一设备管理

新增功能

  • handle_auto_discovered_device_event() - 处理自动发现设备事件
  • get_auto_discovered_devices() - 获取自动发现设备
  • get_all_devices_unified() - 获取所有设备(统一视图)
  • get_device_source() - 获取设备来源
  • remove_auto_discovered_device() - 移除自动发现设备
  • update_auto_discovered_device_info() - 更新自动发现设备信息
  • cleanup_offline_auto_discovered_devices() - 清理离线设备

架构优势

  • 统一的设备状态管理
  • 自动发现和手动注册设备统一处理
  • 更好的可维护性

应用启动优化

问题:启动时出现"no running event loop"错误

解决方案:使用FastAPI事件处理器管理异步任务

文件变更

  • 更新 app/core/app/factory.py - 添加启动和关闭事件处理器
  • 更新 app/services/auto_discovery_adb_service.py - 移除自动启动监控

优化内容

  • 使用 @app.on_event("startup") 启动设备监控
  • 使用 @app.on_event("shutdown") 停止设备监控
  • 避免在构造函数中创建异步任务

路由注册修复

问题:路由注册失败,出现"no running event loop"错误

解决方案:修复异步任务创建时机

文件变更

  • 更新 app/api/v1/endpoints/enhanced_adb.py - 使用懒加载初始化服务
  • 更新 app/core/app/router.py - 简化路由注册

修复内容

  • 延迟服务初始化到实际使用时
  • 移除构造函数中的异步任务创建
  • 使用事件处理器管理生命周期

设备监控增强

问题:需要增强设备监控日志和启动触发

解决方案:增强监控功能和日志记录

文件变更

  • 更新 app/services/auto_discovery_adb_service.py - 增强监控功能

增强内容

  • 添加更详细的日志记录
  • 改进设备状态处理
  • 增强错误处理和恢复机制

初始问题修复

问题:应用启动失败,路由注册错误

解决方案:修复异步任务和事件循环问题

文件变更

  • 更新多个核心文件以修复启动问题
  • 优化异步任务管理
  • 改进错误处理机制

WebSocket最小API调整(2025-08-07)

  • app/api/v1/endpoints/websocket.py 简化为最小集合:

    • 保留 POST /websocket/clients(创建并连接客户端,合并原创建和连接)
    • 保留 POST /websocket/clients/{name}/disconnect(断开客户端)
    • 移除其余获取/订阅/广播/统计等接口,遵循“只需获取、连接、停止”的产品要求精简为仅连接与断开(获取由其他内部接口/日志替代)
  • 目的:

    • 降低对外API面,减少维护成本
    • 与“Channel预创建 + 适配器内部管理”策略一致
  • 影响:

    • 如需查询状态,暂通过内部服务统计或后续单独的只读接口再行补充
  • WebSocket改进:

    • app/core/websocket/client.py 支持 "*" 通配消息处理器(未匹配到具体type时回退)。
    • app/services/websocket_service.py 在创建并连接客户端后,自动为其:
      • 确保默认Channels存在并连接
      • 创建并启动与默认Channels的适配器
      • 从而保证“按Channel读写”链路即刻可用(发送走Adapter→Client,接收由Client注册的处理器经Adapter写入Channel)。

去服务层解耦(2025-08-07)

  • 目标:消除 websocket_service 与核心层的重复职责,API与启动流程直接依赖 websocket_managerWebSocketConfig

  • 变更:

    • app/api/v1/endpoints/websocket.py 直接调用 websocket_manager 完成创建/连接/断开,并在创建成功后初始化默认Channels与适配器。
    • app/core/app/factory.py 启动时直接创建并连接默认Channels,关闭时调用 websocket_manager.cleanup()
    • 后续可删除 app/services/websocket_service.py 文件(当前仍保留便于迁移过渡,无对外API依赖)。
  • WebSocket严格版重构:

    • 禁用直发与广播:websocket_service.send_message/broadcast_message 改为拒绝外部调用,仅允许写入 Channel 由 Adapter 转发。
    • 私有发送:WebSocketClient.send_message 重命名为 _send_message,仅供 Adapter 调用;心跳仍为内部私有发送。
    • 出入通道分离:WebSocketAdapter 支持 outbound_channelinbound_channel;默认两者同名同一Channel,后续可按需拆分不同Channel。
    • 适配器幂等恢复:WebSocketManager.create_adapter 若存在且任务未运行则自动重启,并确保 Channel 连接。
    • 创建客户端后自动为默认 Channels 建立适配器并连接,保证 Channel→Adapter→Client 链路即刻可用。
    • 心跳数据格式收敛:按用户指定的 .NET 模型,仅发送 { "Type": "heartbeat", "Payload": { "Message": "ping" } },不附加任何其他字段;由 WebSocketAdapter 在优先级Channel写入并由发送循环优先发送。