From 6198905bd622a48f203e98631e39692cdff77e9b Mon Sep 17 00:00:00 2001 From: root <295172551@qq.com> Date: Sat, 6 Sep 2025 15:44:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8DStopTerminalServiceCo?= =?UTF-8?q?mmandHandler=E5=B9=B6=E4=BC=98=E5=8C=96=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=A6=BB=E7=BA=BF=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主要修改: - 修复StopTerminalServiceCommandHandler语法错误和方法签名问题 - 修复WebSocket API接口不匹配问题(POST vs DELETE) - 优化设备离线状态设置逻辑,只处理在线设备 - 改进代码命名规范和日志记录 技术细节: - 修复第97行缺少分号和第94行返回类型错误 - 将CreateWebSocketConnectionAsync重命名为DisconnectWebSocketAsync - 修复C#客户端HTTP方法从DELETE改为POST以匹配Python API - 优化设备处理逻辑,只获取和更新在线设备,提高性能 - 添加详细的操作日志记录 影响范围: - StopTerminalServiceCommandHandler: 停止终端服务功能 - TestTerminalRequestClient: WebSocket客户端断开连接 - 设备状态管理: 性能优化和业务逻辑改进 测试建议: - 验证WebSocket客户端断开连接功能 - 检查设备离线状态设置是否正确 - 确认大量设备场景下的性能表现 --- .../StartTerminalServiceCommandHandler.cs | 8 +- .../StopTerminalServiceCommandHandler.cs | 95 +++++++++++++++- .../Service/TestTerminalRequestClient.cs | 7 +- ...fy_20250121_device_offline_optimization.md | 107 ++++++++++++++++++ ...modify_20250121_stopterminalservice_fix.md | 62 ++++++++++ src/modify_20250121_websocket_api_fix.md | 101 +++++++++++++++++ 6 files changed, 374 insertions(+), 6 deletions(-) create mode 100644 src/modify_20250121_device_offline_optimization.md create mode 100644 src/modify_20250121_stopterminalservice_fix.md create mode 100644 src/modify_20250121_websocket_api_fix.md diff --git a/src/X1.Application/Features/TerminalServices/Commands/StartTerminalService/StartTerminalServiceCommandHandler.cs b/src/X1.Application/Features/TerminalServices/Commands/StartTerminalService/StartTerminalServiceCommandHandler.cs index 9143bb4..887bf2d 100644 --- a/src/X1.Application/Features/TerminalServices/Commands/StartTerminalService/StartTerminalServiceCommandHandler.cs +++ b/src/X1.Application/Features/TerminalServices/Commands/StartTerminalService/StartTerminalServiceCommandHandler.cs @@ -5,6 +5,7 @@ using X1.Domain.Repositories.Terminal; using X1.Domain.Services; using X1.Domain.ThirdPartyDeviceHttpClient.ITerminal; using X1.Domain.Entities.Terminal; +using X1.Domain.Repositories.Base; namespace X1.Application.Features.TerminalServices.Commands.StartTerminalService; @@ -17,6 +18,7 @@ public class StartTerminalServiceCommandHandler : IRequestHandler _logger; private readonly ICurrentUserService _currentUserService; private readonly IBaseTerminalClient _terminalClient; + private readonly IUnitOfWork _unitOfWork; /// /// 初始化命令处理器 @@ -25,12 +27,14 @@ public class StartTerminalServiceCommandHandler : IRequestHandler logger, - ICurrentUserService currentUserService) + ICurrentUserService currentUserService, + IUnitOfWork unitOfWork) { _serviceRepository = serviceRepository; _logger = logger; _currentUserService = currentUserService; _terminalClient = terminalClient; + _unitOfWork = unitOfWork; } /// @@ -111,6 +115,8 @@ public class StartTerminalServiceCommandHandler : IRequestHandler _logger; private readonly ICurrentUserService _currentUserService; - + private readonly IUnitOfWork _unitOfWork; + private readonly ITerminalDeviceRepository _deviceRepository; + private readonly IBaseTerminalClient _terminalClient; /// /// 初始化命令处理器 /// public StopTerminalServiceCommandHandler( ITerminalServiceRepository serviceRepository, ILogger logger, - ICurrentUserService currentUserService) + ICurrentUserService currentUserService, + IUnitOfWork unitOfWork, + ITerminalDeviceRepository deviceRepository, + IBaseTerminalClient terminalClient) { _serviceRepository = serviceRepository; _logger = logger; _currentUserService = currentUserService; + _unitOfWork = unitOfWork; + _deviceRepository = deviceRepository; + _terminalClient = terminalClient; } /// @@ -59,9 +72,42 @@ public class StopTerminalServiceCommandHandler : IRequestHandler.CreateFailure("无法获取服务端点信息,请检查系统配置"); + } + + await DisconnectWebSocketAsync(existingService.ServiceCode, serviceEndpoint, cancellationToken); + // 构建响应 var response = new StopTerminalServiceResponse { @@ -81,4 +127,49 @@ public class StopTerminalServiceCommandHandler : IRequestHandler.CreateFailure("停止终端服务时发生错误"); } } + + + /// + /// 断开WebSocket连接 + /// + private async Task> DisconnectWebSocketAsync( + string serviceCode, + string serviceEndpoint, + CancellationToken cancellationToken) + { + try + { + _logger.LogDebug("断开WebSocket连接请求 - 服务编码: {ServiceCode}, 服务端点: {ServiceEndpoint}", + serviceCode, serviceEndpoint); + + // 断开WebSocket连接 + var webSocketResponse = await _terminalClient.DisconnectTerminalWebSocketAsync(serviceCode, cancellationToken: cancellationToken); + + if (webSocketResponse == null) + { + _logger.LogError("WebSocket断开连接响应为空,服务编码: {ServiceCode}", serviceCode); + return OperationResult.CreateFailure("WebSocket断开连接失败:服务器无响应"); + } + + if (!webSocketResponse.Success) + { + var errorMessage = string.IsNullOrWhiteSpace(webSocketResponse.Message) + ? "未知错误" + : webSocketResponse.Message; + _logger.LogError("WebSocket断开连接失败,服务编码: {ServiceCode}, 错误信息: {ErrorMessage}", + serviceCode, errorMessage); + return OperationResult.CreateFailure($"WebSocket断开连接失败:{errorMessage}"); + } + + _logger.LogInformation("WebSocket断开连接成功,服务编码: {ServiceCode}", serviceCode); + return OperationResult.CreateSuccess(true); + } + catch (Exception ex) + { + _logger.LogError(ex, "断开WebSocket连接时发生异常,服务编码: {ServiceCode}, 服务端点: {ServiceEndpoint}", + serviceCode, serviceEndpoint); + return OperationResult.CreateFailure($"WebSocket断开连接异常:{ex.Message}"); + } + } + } diff --git a/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs b/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs index 5c20489..4eedf82 100644 --- a/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs +++ b/src/X1.DynamicClientCore/Service/TestTerminalRequestClient.cs @@ -189,9 +189,9 @@ namespace X1.DynamicClientCore.Service /// 当clientName为null时抛出 /// 当clientName为空时抛出 /// - /// 该方法通过HTTP DELETE请求调用WebSocket客户端断开连接API,断开指定的WebSocket客户端连接。 + /// 该方法通过HTTP POST请求调用WebSocket客户端断开连接API,断开指定的WebSocket客户端连接。 /// 使用固定的服务名称"websocket"进行API调用,端点格式为"/api/v1/websocket/clients/{clientName}/disconnect"。 - /// 返回的TerminalWebSocketResponse包含断开连接的结果信息。 + /// 返回的TestTerminalResponse包含断开连接的结果信息。 /// public async Task DisconnectTerminalWebSocketAsync( string clientName, @@ -210,9 +210,10 @@ namespace X1.DynamicClientCore.Service var endpoint = $"websocket/clients/{clientName}/disconnect"; // 调用WebSocket客户端断开连接API - var response = await _dynamicHttpClient.DeleteAsync( + var response = await _dynamicHttpClient.PostAsync( clientName, endpoint, + null, // POST请求体为空 options, cancellationToken); diff --git a/src/modify_20250121_device_offline_optimization.md b/src/modify_20250121_device_offline_optimization.md new file mode 100644 index 0000000..b1083c5 --- /dev/null +++ b/src/modify_20250121_device_offline_optimization.md @@ -0,0 +1,107 @@ +# 2025-01-21 优化设备离线状态设置逻辑 + +## 概述 +优化了 `StopTerminalServiceCommandHandler` 中设备离线状态设置的逻辑,采用方案1:只更新在线设备为离线状态,提高性能并确保业务逻辑的合理性。 + +## 问题分析 + +### 原始代码问题 +```csharp +var devices = await _deviceRepository.GetAllAsync(); // 加载所有设备到内存 +foreach (var device in devices) +{ + device.SetOffline(); // 逐个处理 +} +_deviceRepository.UpdateRange(devices); // 批量更新 +``` + +**问题**: +1. **性能问题**: 当设备数量很大时,会消耗大量内存 +2. **业务逻辑问题**: 即使设备已经是离线状态,也会重复处理 +3. **资源浪费**: 加载所有设备,但只需要处理在线设备 + +## 优化方案 + +### 方案1: 只更新在线设备(已采用) +```csharp +// 只获取在线设备并设置为离线状态 +var onlineDevices = await _deviceRepository.GetOnlineDevicesAsync(cancellationToken); +if (onlineDevices.Any()) +{ + _logger.LogInformation("开始设置在线设备为离线状态,在线设备数量: {OnlineDeviceCount}", onlineDevices.Count); + + foreach (var device in onlineDevices) + { + device.SetOffline(); + } + _deviceRepository.UpdateRange(onlineDevices); + + _logger.LogInformation("成功设置 {DeviceCount} 个设备为离线状态", onlineDevices.Count); +} +else +{ + _logger.LogInformation("没有在线设备需要设置为离线状态"); +} +``` + +## 优化效果 + +### 1. 性能提升 +- **内存使用**: 只加载在线设备,减少内存消耗 +- **处理效率**: 只处理需要更新的设备,避免无效操作 +- **数据库负载**: 减少不必要的数据传输 + +### 2. 业务逻辑优化 +- **合理性**: 只处理在线设备,符合业务逻辑 +- **一致性**: 服务停止时,所有在线设备必须离线 +- **准确性**: 避免重复处理已离线的设备 + +### 3. 日志完善 +- **操作日志**: 记录在线设备数量和处理结果 +- **状态跟踪**: 清晰记录设备状态变更过程 +- **问题排查**: 便于后续问题定位和调试 + +## 技术实现 + +### 使用的仓储方法 +```csharp +// 获取在线设备列表 +var onlineDevices = await _deviceRepository.GetOnlineDevicesAsync(cancellationToken); +``` + +### 设备状态设置 +```csharp +// 设置设备离线状态 +device.SetOffline(); // 设置状态为离线,更新LastDisconnectedAt和UpdatedAt +``` + +### 批量更新 +```csharp +// 批量更新设备状态 +_deviceRepository.UpdateRange(onlineDevices); +``` + +## 业务逻辑说明 + +### 服务停止时的设备处理 +1. **服务停止**: 终端服务停止运行 +2. **设备离线**: 所有在线设备必须设置为离线状态 +3. **状态同步**: 确保设备状态与服务状态保持一致 +4. **日志记录**: 记录设备状态变更过程 + +### 为什么只处理在线设备 +- **效率**: 离线设备无需重复处理 +- **逻辑**: 只有在线设备需要设置为离线 +- **性能**: 减少不必要的数据操作 +- **准确性**: 避免状态混乱 + +## 文件修改 +- **文件**: `X1.Application/Features/TerminalServices/Commands/StopTerminalService/StopTerminalServiceCommandHandler.cs` +- **修改类型**: 性能优化、业务逻辑优化、日志完善 +- **影响范围**: 停止终端服务功能 + +## 测试建议 +1. 验证只有在线设备被设置为离线状态 +2. 检查离线设备不会被重复处理 +3. 确认日志记录正确显示设备数量 +4. 测试大量设备场景下的性能表现 diff --git a/src/modify_20250121_stopterminalservice_fix.md b/src/modify_20250121_stopterminalservice_fix.md new file mode 100644 index 0000000..ec6982f --- /dev/null +++ b/src/modify_20250121_stopterminalservice_fix.md @@ -0,0 +1,62 @@ +# 2025-01-21 修复 StopTerminalServiceCommandHandler 问题 + +## 概述 +修复 `StopTerminalServiceCommandHandler` 中的语法错误、方法签名问题、冗余字段和命名规范问题。 + +## 主要修复 + +### 1. 语法错误修复 +- **第97行**: 添加缺失的分号 +- **第94行**: 修正返回类型从 `StartTerminalServiceResponse` 到 `StopTerminalServiceResponse` + +### 2. 方法签名修复 +- **重命名方法**: `CreateWebSocketConnectionAsync` → `DisconnectWebSocketAsync` +- **修正参数**: 移除未使用的 `webSocketRequest` 参数 +- **更新日志**: 将"创建连接"改为"断开连接",更符合停止服务的语义 + +### 3. 冗余字段删除 +- **删除未使用变量**: 移除 `webSocketRequest` 相关代码 +- **清理日志参数**: 移除不存在的变量引用 + +### 4. 命名规范改进 +- **变量命名**: `ss` → `devices`,`item` → `device` +- **方法命名**: 使用更清晰的方法名 `DisconnectWebSocketAsync` +- **参数命名**: 使用 `serviceCode` 而不是 `ServiceCode` + +### 5. 代码优化 +- **添加注释**: 为私有方法添加完整的XML文档注释 +- **日志优化**: 改进日志消息的清晰度和准确性 +- **错误处理**: 保持一致的错误处理模式 + +## 技术细节 + +### 修复前的问题 +```csharp +// 语法错误:缺少分号 +await CreateWebSocketConnectionAsync(existingService.ServiceCode) + +// 返回类型错误 +return OperationResult.CreateFailure(...) + +// 未定义的变量 +_logger.LogDebug("WebSocket连接请求参数 - 客户端名称: {ClientName}, 连接地址: {Url}, 心跳间隔: {HeartbeatInterval}秒", + webSocketRequest.Name, webSocketRequest.Url, webSocketRequest.HeartbeatInterval); +``` + +### 修复后的代码 +```csharp +// 正确的语法 +await DisconnectWebSocketAsync(existingService.ServiceCode, serviceEndpoint, cancellationToken); + +// 正确的返回类型 +return OperationResult.CreateFailure(...); + +// 清晰的日志 +_logger.LogDebug("断开WebSocket连接请求 - 服务编码: {ServiceCode}, 服务端点: {ServiceEndpoint}", + serviceCode, serviceEndpoint); +``` + +## 文件修改 +- **文件**: `X1.Application/Features/TerminalServices/Commands/StopTerminalService/StopTerminalServiceCommandHandler.cs` +- **修改类型**: 语法修复、方法重构、命名优化 +- **影响范围**: 停止终端服务功能 diff --git a/src/modify_20250121_websocket_api_fix.md b/src/modify_20250121_websocket_api_fix.md new file mode 100644 index 0000000..e83eeb1 --- /dev/null +++ b/src/modify_20250121_websocket_api_fix.md @@ -0,0 +1,101 @@ +# 2025-01-21 修复 WebSocket API 接口不匹配问题 + +## 概述 +修复了C#客户端与Python WebSocket API之间的HTTP方法不匹配问题,确保接口调用的一致性。 + +## 问题分析 + +### 发现的不匹配问题 +1. **HTTP方法不匹配** + - **Python API**: 使用 `@router.post` (POST方法) + - **C# 客户端**: 使用 `DeleteAsync` (DELETE方法) + +2. **接口对应关系** + - **Python API**: `/websocket/clients/{name}/disconnect` + - **C# 客户端**: `websocket/clients/{clientName}/disconnect` + +## 修复内容 + +### 1. HTTP方法修复 +**文件**: `X1.DynamicClientCore/Service/TestTerminalRequestClient.cs` + +#### 修复前 +```csharp +// 调用WebSocket客户端断开连接API +var response = await _dynamicHttpClient.DeleteAsync( + clientName, + endpoint, + options, + cancellationToken); +``` + +#### 修复后 +```csharp +// 调用WebSocket客户端断开连接API +var response = await _dynamicHttpClient.PostAsync( + clientName, + endpoint, + null, // POST请求体为空 + options, + cancellationToken); +``` + +### 2. 注释更新 +更新了方法注释,将HTTP方法从DELETE改为POST: + +```csharp +/// +/// 该方法通过HTTP POST请求调用WebSocket客户端断开连接API,断开指定的WebSocket客户端连接。 +/// 使用固定的服务名称"websocket"进行API调用,端点格式为"/api/v1/websocket/clients/{clientName}/disconnect"。 +/// 返回的TestTerminalResponse包含断开连接的结果信息。 +/// +``` + +## 接口对应关系确认 + +### Python API +```python +@router.post("/websocket/clients/{name}/disconnect", summary="断开WebSocket客户端", response_model=SuccessResponse) +@handle_api_errors +async def disconnect_client(name: str): + """断开已存在客户端""" + success = await websocket_manager.disconnect_client(name) + # ... +``` + +### C# 客户端 +```csharp +public async Task DisconnectTerminalWebSocketAsync( + string clientName, + RequestOptions? options = null, + CancellationToken cancellationToken = default) +{ + var endpoint = $"websocket/clients/{clientName}/disconnect"; + var response = await _dynamicHttpClient.PostAsync( + clientName, + endpoint, + null, // POST请求体为空 + options, + cancellationToken); + // ... +} +``` + +## 验证结果 + +### ✅ 修复完成 +- **HTTP方法**: POST ✅ +- **端点格式**: `/websocket/clients/{name}/disconnect` ✅ +- **参数传递**: 路径参数 ✅ +- **请求体**: 空请求体 ✅ + +### 影响范围 +- **文件**: `X1.DynamicClientCore/Service/TestTerminalRequestClient.cs` +- **方法**: `DisconnectTerminalWebSocketAsync` +- **功能**: WebSocket客户端断开连接 +- **调用方**: `StopTerminalServiceCommandHandler` + +## 测试建议 +1. 验证WebSocket客户端断开连接功能 +2. 检查API调用是否成功 +3. 确认错误处理机制正常工作