1145 lines
49 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DotNetty.Common.Utilities;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Dynamic.Core.Tokenizer;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ToolLibrary;
using YunDa.Server.Communication.CommunicationModels;
using YunDa.Server.Communication.Framework;
using YunDa.Server.ISMSTcp.Domain;
using YunDa.Server.ISMSTcp.Filters.Enums;
using YunDa.Server.ISMSTcp.Filters.Extensions;
using YunDa.Server.ISMSTcp.Filters.Interfaces;
using YunDa.Server.ISMSTcp.Interfaces;
using YunDa.Server.ISMSTcp.Models;
using YunDa.SOMS.DataTransferObject.GeneralInformation.EquipmentLiveDataDto;
using YunDa.SOMS.DataTransferObject.GeneralInformation.ProtectionDeviceInfoDto;
using YunDa.SOMS.DataTransferObject.MaintenanceAndOperations.SecondaryEquipment;
using YunDa.SOMS.Redis.Repositories;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace YunDa.Server.ISMSTcp.Services
{
/// <summary>
/// 数据处理器实现
///
/// 重构说明:
/// - 移除了不必要的 _dataBuffer 缓冲区逻辑,因为当前实现可以正确解析完整的数据包
/// - 简化了数据处理流程,直接处理接收到的数据而不需要缓冲不完整的数据包
/// - 保留了数据包解析和验证的核心逻辑
/// - 移除了相关的线程安全保护,因为不再需要管理共享的缓冲区状态
/// </summary>
public class DataProcessor
{
private readonly ILogger<DataProcessor> _logger;
private readonly MessageParser _messageParser;
private readonly IAlarmService _alarmService;
private readonly IPacketParser _packetParser;
private readonly TelemeteringHandle _telemeteringHandle;
private readonly TelesignalisationHandle _telesignalisationHandle;
private readonly VirtualTerminalHandler _virtualTerminalHandler;
private readonly IFilterControlService _filterControlService;
private readonly IDeviceCommunicationStateService _deviceCommunicationStateService;
private readonly IQueryCoordinationService _queryCoordinationService;
private readonly IWebSocketPushService _webSocketPushService;
private readonly IRedisRepository<ProtectionDeviceCommInfoOutput, string> _protectionDeviceCommInfoRedis;
private readonly IApiEndpoints _apiEndpoints;
private readonly WebApiRequest _webApiRequest;
private readonly GwErrorRatioService _gwErrorRatioService;
//孪生体服务
private readonly ThingService _thingService;
// 高频数据处理优化常量
private const int MaxDataSize = 50000; // 单次处理的最大数据大小50KB
private const int CriticalDataSize = 100000; // 临界数据大小100KB
private const int MaxPacketsPerBatch = 100; // 单批次最大处理数据包数量
private const int MinHeaderSize = 6; // 最小头部大小
// 性能统计
private long _totalProcessedBytes = 0;
private int _totalProcessedPackets = 0;
private int _discardedDataCount = 0;
//二次回路巡检计划
private readonly SecondaryCircuitInspectionPlanService _secondaryCircuitInspectionPlanService;
public DataProcessor(
ILogger<DataProcessor> logger,
MessageParser messageParser,
IAlarmService alarmService,
ICommandStateMachine commandStateMachine,
IPacketParser packetParser,
TelemeteringHandle telemeteringHandle,
TelesignalisationHandle telesignalisationHandle,
VirtualTerminalHandler virtualTerminalHandler,
IFilterControlService filterControlService,
IDeviceCommunicationStateService deviceCommunicationStateService,
IQueryCoordinationService queryCoordinationService,
IWebSocketPushService webSocketPushService,
IRedisRepository<ProtectionDeviceCommInfoOutput, string> protectionDeviceCommInfoRedis,
IApiEndpoints apiEndpoints,
WebApiRequest webApiRequest,
SecondaryCircuitInspectionPlanService secondaryCircuitInspectionPlanService,
ThingService thingService,
GwErrorRatioService gwErrorRatioService)
{
_logger = logger;
_messageParser = messageParser;
_alarmService = alarmService;
CommandStateMachine = commandStateMachine;
_packetParser = packetParser ?? throw new ArgumentNullException(nameof(packetParser));
_telemeteringHandle = telemeteringHandle ?? throw new ArgumentNullException(nameof(telemeteringHandle));
_telesignalisationHandle = telesignalisationHandle ?? throw new ArgumentNullException(nameof(telesignalisationHandle));
_virtualTerminalHandler = virtualTerminalHandler ?? throw new ArgumentNullException(nameof(virtualTerminalHandler));
_filterControlService = filterControlService ?? throw new ArgumentNullException(nameof(filterControlService));
_deviceCommunicationStateService = deviceCommunicationStateService ?? throw new ArgumentNullException(nameof(deviceCommunicationStateService));
_queryCoordinationService = queryCoordinationService ?? throw new ArgumentNullException(nameof(queryCoordinationService));
_webSocketPushService = webSocketPushService ?? throw new ArgumentNullException(nameof(webSocketPushService));
_protectionDeviceCommInfoRedis = protectionDeviceCommInfoRedis ?? throw new ArgumentNullException(nameof(protectionDeviceCommInfoRedis));
_apiEndpoints = apiEndpoints ?? throw new ArgumentNullException(nameof(apiEndpoints));
_webApiRequest = webApiRequest ?? throw new ArgumentNullException(nameof(webApiRequest));
_secondaryCircuitInspectionPlanService = secondaryCircuitInspectionPlanService ?? throw new ArgumentNullException(nameof(secondaryCircuitInspectionPlanService));
_thingService = thingService ?? throw new ArgumentNullException(nameof(thingService));
_gwErrorRatioService = gwErrorRatioService ?? throw new ArgumentNullException(nameof(gwErrorRatioService));
}
/// <summary>
/// 命令状态机
/// </summary>
public ICommandStateMachine CommandStateMachine { get; }
/// <summary>
/// TCP响应接收事件
/// 当成功接收并解析TCP响应数据时触发
/// </summary>
public event Action? TcpResponseReceived;
/// <summary>
/// 根据消息类型处理消息内容
/// </summary>
/// <param name="messageType">消息类型</param>
/// <param name="contentToken">消息内容</param>
/// <param name="originalJson">原始JSON字符串</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult?> ProcessMessageByTypeAsync(string messageType, JToken contentToken, string originalJson)
{
try
{
if (messageType.ToUpper()!= "YC"&& messageType.ToUpper()!= "YX"&& "HeartBeat"!= messageType&& "CommState" != messageType)
{
Log.Information(messageType + ":" + originalJson);
}
// 触发TCP响应接收事件
TcpResponseReceived?.Invoke();
Models.ProcessResult result = messageType.ToUpper() switch
{
"YC" => await ProcessYCMessageAsync(contentToken) ,
"YX" => await ProcessYXMessageAsync(contentToken),
"VA" => await ProcessVAMessageAsync(contentToken),
"DZ" => await ProcessDZMessageAsync(contentToken),
"COMMSTATE" => await ProcessCommStateMessageAsync(contentToken),
"ALERT" => await ProcessAlertMessageAsync(contentToken, originalJson),
"VERSION" => await ProcessVersionMessageAsync(contentToken),
"ERROR" => await ProcessErrorMessageAsync(contentToken, originalJson),
"HEARTBEAT" => await ProcessHeartBeatMessageAsync(contentToken),
"WAVECFG" => await ProcessWaveCfgMessageAsync(contentToken),
"WAVEDATA" => await ProcessWaveDataMessageAsync(contentToken),
"故障报告" => await ProcessFaultRptMessageAsync(contentToken),
"ALLDATA" => await ProcessAllDataMessageAsync(contentToken),
"GWERRORRATIO" => await ProcessGwErrorRatioMessageAsync(contentToken),
_ => ProcessUnknownMessageType(messageType, originalJson)
};
return result;
}
catch (Exception ex)
{
var errorMessageType = ISMSMessageTypeExtensions.ParseMessageType(messageType);
_logger.LogErrorWithFilter(_filterControlService, errorMessageType, ex,
"处理消息类型 {MessageType} 时发生异常", messageType);
return Models.ProcessResult.Error($"Message processing error for type {messageType}: {ex.Message}");
}
}
private async Task<ProcessResult> ProcessFaultRptMessageAsync(JToken contentToken)
{
HandleRecvMsg(contentToken, "FAULTRPT");
var alertDatas = contentToken.ToObject<List<AlertData>>();
foreach (var item in alertDatas)
{
var json = JsonConvert.SerializeObject(item);
Log.Warning("故障报告:"+json);
}
return Models.ProcessResult.Success(contentToken, "FAULTRPT");
}
/// <summary>
/// 处理未知消息类型
/// </summary>
/// <param name="messageType">消息类型</param>
/// <param name="originalJson">原始JSON</param>
/// <returns>处理结果</returns>
private Models.ProcessResult ProcessUnknownMessageType(string messageType, string originalJson)
{
var unknownMessageType = ISMSMessageTypeExtensions.ParseMessageType(messageType);
_logger.LogWarningWithFilter(_filterControlService, unknownMessageType,
"未知消息类型: {MessageType}", messageType);
return Models.ProcessResult.Success(default,messageType);
}
#region
/// <summary>
/// 处理YC遥测消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessYCMessageAsync(JToken contentToken)
{
try
{
if (!_telemeteringHandle._isInitialized)
{
await _telemeteringHandle.InitAsync();
}
//_logger.LogInformation("Processing YC (telemetering) message");
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
// 批量处理遥测数据
await _telemeteringHandle.ProcessYCDataAsync(contentArray);
}
else
{
_logger.LogWarning("YC message content is not a valid array or is empty");
}
return Models.ProcessResult.Success( contentToken,"YC");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing YC message");
return Models.ProcessResult.Error($"YC processing error: {ex.Message}");
}
}
/// <summary>
/// 处理YX遥信消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessYXMessageAsync(JToken contentToken)
{
try
{
if (!_telesignalisationHandle._isInitialized)
{
await _telesignalisationHandle.InitAsync();
}
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
List<TelesignalisationModel> telesignalisationModels = new List<TelesignalisationModel>();
// 🔧 优化:根据数据量区分处理方式
// 大批量数据(>10仅更新Redis不触发转发逻辑命令响应场景
// 小批量数据(<=10完整处理包括转发主动变位场景
if (contentArray.Count > 10)
{
_logger.LogDebug("检测到大批量遥信数据({Count}条仅更新Redis跳过转发逻辑", contentArray.Count);
// 仅更新Redis不触发WebSocket转发和其他处理逻辑
foreach (var item in contentArray)
{
var model = await _telesignalisationHandle.ProcessYXDataAsync(item, skipForwarding: true);
if(model != null)
telesignalisationModels.Add(model);
}
}
else
{
_logger.LogDebug("检测到小批量遥信数据({Count}条),执行完整处理逻辑", contentArray.Count);
// 完整处理更新Redis + WebSocket转发 + 告警处理等
foreach (var item in contentArray)
{
var model = await _telesignalisationHandle.ProcessYXDataAsync(item, skipForwarding: false);
if (model != null)
telesignalisationModels.Add(model);
}
}
//将状态推送到孪生体
_thingService.UpdateThingYXStatus(telesignalisationModels);
}
else
{
_logger.LogWarning("YX message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "YX");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing YX message");
return Models.ProcessResult.Error($"YX processing error: {ex.Message}");
}
}
/// <summary>
/// 处理VA虚端子消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessVAMessageAsync(JToken contentToken)
{
try
{
_logger.LogInformation("Processing VA (virtual terminal) message");
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
List<VirtualTerminalData> virtualTerminalDatas = new List<VirtualTerminalData>();
foreach (var item in contentArray)
{
if (item is JObject itemObject)
{
if (_virtualTerminalHandler.TryParseVirtualTerminalData(item.ToString(), out var virtualTerminalData))
{
virtualTerminalDatas.Add(virtualTerminalData);
await _virtualTerminalHandler.ProcessVirtualTerminalDataAsync(virtualTerminalData);
}
else
{
_logger.LogWarning("Failed to parse virtual terminal data: {Data}", item.ToString());
}
}
}
//向孪生体推送断线数据
_thingService.UpdateOpticalFiberAlarmStatus(virtualTerminalDatas, null, null);
_thingService.UpdateOpticalCableAlarmStatus(virtualTerminalDatas, null);
}
else
{
_logger.LogWarning("VA message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "VA");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing VA message");
return Models.ProcessResult.Error($"VA processing error: {ex.Message}");
}
}
/// <summary>
/// 处理DZ定值消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessDZMessageAsync(JToken contentToken)
{
try
{
_logger.LogInformation("Processing DZ (device setting) message");
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
var processedCount = 0;
var errorCount = 0;
var validDzDataList = new List<DZData>();
foreach (var item in contentArray)
{
try
{
// 预处理JSON数据处理Value字段可能包含非数字值的情况
var processedItem = PreprocessDZDataItem(item);
var dzData = processedItem.ToObject<DZData>();
if (dzData != null)
{
validDzDataList.Add(dzData);
}
}
catch (Exception itemEx)
{
_logger.LogError(itemEx, "处理单个定值数据失败: {Item}", item?.ToString());
}
}
_logger.LogInformation("定值消息处理完成 - 成功: {ProcessedCount}, 错误: {ErrorCount}",
processedCount, errorCount);
_logger.LogError("DZ Data: {DzData}", JsonConvert.SerializeObject(validDzDataList));
HandleCommandResponseAsync(contentToken.ToString(), false);
HandleRecvMsg(contentToken, "dz", false);
}
else
{
_logger.LogWarning("DZ message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "DZ");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing DZ message");
return Models.ProcessResult.Error($"DZ processing error: {ex.Message}");
}
}
/// <summary>
/// 处理CommState通信状态消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessCommStateMessageAsync(JToken contentToken)
{
try
{
_logger.LogInformation("开始处理通信状态消息");
// 解析通信状态消息内容
if (contentToken == null || !contentToken.HasValues)
{
_logger.LogWarning("通信状态消息内容为空");
return Models.ProcessResult.Error("通信状态消息内容为空");
}
const string redisKey = "ProtectionDeviceCommInfos";
var deviceUpdates = new List<(string deviceId, bool isOnline)>();
int processedCount = 0;
int errorCount = 0;
// 解析Content数组中的每个设备通信状态信息
if (contentToken is JArray contentArray)
{
foreach (var item in contentArray)
{
try
{
var deviceId = item["DeviceID"]?.ToString();
var commState = item["CommState"]?.ToString();
if (string.IsNullOrWhiteSpace(deviceId))
{
_logger.LogWarning("设备ID为空跳过此条记录: {Item}", item.ToString());
errorCount++;
continue;
}
if (string.IsNullOrWhiteSpace(commState))
{
_logger.LogWarning("通信状态为空设备ID: {DeviceId},跳过此条记录", deviceId);
errorCount++;
continue;
}
// 将通信状态转换为布尔值 ("1" = true, 其他 = false)
bool isOnline = commState == "1";
deviceUpdates.Add((deviceId, isOnline));
processedCount++;
}
catch (Exception itemEx)
{
_logger.LogError(itemEx, "解析单个设备通信状态失败: {Item}", item?.ToString());
errorCount++;
}
}
}
else
{
_logger.LogWarning("通信状态消息Content不是数组格式: {Content}", contentToken.ToString());
return Models.ProcessResult.Error("通信状态消息格式错误");
}
// 批量更新Redis中的设备通信状态
if (deviceUpdates.Count > 0)
{
int savedCount = 0;
foreach (var (deviceId, isOnline) in deviceUpdates)
{
try
{
// 从Redis获取现有的设备信息
var existingDevice = await _protectionDeviceCommInfoRedis.HashSetGetOneAsync(redisKey, deviceId);
if (existingDevice != null)
{
// 只更新IsOnline字段
existingDevice.IsOnline = isOnline;
await _protectionDeviceCommInfoRedis.HashSetUpdateOneAsync(redisKey, deviceId, existingDevice);
savedCount++;
}
else
{
_logger.LogWarning("Redis中未找到设备信息设备ID: {DeviceId}", deviceId);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "更新Redis中设备通信状态失败设备ID: {DeviceId}", deviceId);
}
}
_logger.LogInformation("通信状态消息处理完成 - 解析成功: {ProcessedCount}, 保存成功: {SavedCount}, 错误: {ErrorCount}",
processedCount, savedCount, errorCount);
if (savedCount != deviceUpdates.Count)
{
_logger.LogWarning("部分设备通信状态保存失败 - 预期: {Expected}, 实际: {Actual}", deviceUpdates.Count, savedCount);
}
// 保持原有的缓存服务调用以确保兼容性
var deviceStates = deviceUpdates.ToDictionary(x => x.deviceId, x => x.isOnline ? "1" : "0");
await _deviceCommunicationStateService.SetDeviceCommunicationStatesAsync(deviceStates);
// WebSocket实时推送
try
{
// 推送到COMMSTATE分组
await _webSocketPushService.PushCommStateDataAsync(contentToken);
}
catch (Exception pushEx)
{
_logger.LogWarning(pushEx, "通信状态数据WebSocket推送失败但不影响主要处理流程");
}
}
else
{
_logger.LogWarning("没有有效的设备通信状态数据需要保存");
}
return Models.ProcessResult.Success(contentToken, "COMMSTATE");
}
catch (Exception ex)
{
_logger.LogError(ex, "处理通信状态消息时发生异常");
return Models.ProcessResult.Error($"通信状态消息处理异常: {ex.Message}");
}
}
/// <summary>
/// 处理Alert报警消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <param name="originalJson">原始JSON字符串</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessAlertMessageAsync(JToken contentToken, string originalJson)
{
try
{
// 输入验证
if (contentToken == null)
{
_logger.LogWarning("Alert message content is null");
return Models.ProcessResult.Error("Alert message content is null");
}
// 反序列化告警数据
List<AlertData> alertDatas;
try
{
alertDatas = contentToken.ToObject<List<AlertData>>();
if (alertDatas == null || alertDatas.Count == 0)
{
_logger.LogWarning("Alert message contains no valid alert data");
return Models.ProcessResult.Success(contentToken, "ALERT");
}
}
catch (JsonException jsonEx)
{
_logger.LogError(jsonEx, "Failed to deserialize alert data from content token");
return Models.ProcessResult.Error($"Invalid alert data format: {jsonEx.Message}");
}
// 处理每个告警数据 - 使用并发处理提高性能
var alarmTasks = alertDatas
.Where(alertData => alertData != null && !string.IsNullOrEmpty(alertData.AlertType))
.Select(async alertData =>
{
try
{
string json = JsonConvert.SerializeObject(alertData);
await HandleAlarmMessageAsync(json);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to process individual alert data: {AlertId}", alertData?.AlertID);
return false;
}
});
var alarmResults = await Task.WhenAll(alarmTasks);
var successCount = alarmResults.Count(r => r);
var failureCount = alarmResults.Length - successCount;
if (failureCount > 0)
{
_logger.LogWarning("Alert processing completed with {SuccessCount} successes and {FailureCount} failures",
successCount, failureCount);
}
// 处理故障报告类型的告警
//await ProcessFaultReportsAsync(alertDatas);
//报警上传
await _webApiRequest.UploadAlertMessageAsync(alertDatas);
//报警推送到孪生体
await _thingService.UpdateAlarmDatas(alertDatas);
// WebSocket实时推送 - 异步执行,不阻塞主流程
_ = Task.Run(async () =>
{
try
{
await _webSocketPushService.PushAlertDataAsync(contentToken);
}
catch (Exception pushEx)
{
_logger.LogWarning(pushEx, "告警数据WebSocket推送失败但不影响主要处理流程");
}
});
return Models.ProcessResult.Success(contentToken, "ALERT");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing Alert message");
return Models.ProcessResult.Error($"Alert processing error: {ex.Message}");
}
}
/// <summary>
/// 处理故障报告类型的告警
/// </summary>
/// <param name="alertDatas">告警数据列表</param>
/// <returns>处理任务</returns>
private async Task ProcessFaultReportsAsync(List<AlertData> alertDatas)
{
try
{
var faultReports = alertDatas
.Where(t => !string.IsNullOrEmpty(t?.AlertType) && t.AlertType == "故障报告")
.ToList();
if (faultReports.Count > 0)
{
var jtoken = JToken.FromObject(faultReports);
HandleRecvMsg(jtoken, "faultRpt");
}
else
{
//_logger.LogInformation("No fault reports found in alert data");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing fault reports");
// 不抛出异常,避免影响主流程
}
}
/// <summary>
/// 处理Version版本消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessVersionMessageAsync(JToken contentToken)
{
try
{
HandleRecvMsg(contentToken, "VERSION");
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
var processedCount = 0;
var errorCount = 0;
var validVersionDataList = new List<IsmsDeviceItem>();
foreach (var item in contentArray)
{
try
{
var versionData = item.ToObject<IsmsDeviceItem>();
validVersionDataList.Add(versionData);
}
catch (Exception itemEx)
{
_logger.LogError(itemEx, "处理单个版本信息失败: {Item}", item?.ToString());
errorCount++;
}
}
_logger.LogInformation("版本消息处理完成 - 成功: {ProcessedCount}, 错误: {ErrorCount}",
processedCount, errorCount);
}
else
{
_logger.LogWarning("Version message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "VERSION");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing Version message");
return Models.ProcessResult.Error($"Version processing error: {ex.Message}");
}
}
/// <summary>
/// 处理Error错误消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <param name="originalJson">原始JSON字符串</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessErrorMessageAsync(JToken contentToken, string originalJson)
{
try
{
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
foreach (var item in contentArray)
{
var errorData = item.ToString();
HandleRecvMsg(item, "ERROR", true);
_logger.LogError("处理单个错误信息: {errorData}", errorData);
}
//_logger.LogInformation("错误消息处理完成 - 总数: {ProcessedCount}, 严重错误: {CriticalCount}",
// processedCount, criticalErrorCount);
}
return Models.ProcessResult.Success(contentToken, "ERROR");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing Error message");
return Models.ProcessResult.Error($"Error processing error: {ex.Message}");
}
}
/// <summary>
/// 映射内部消息类型到查询类型
/// </summary>
/// <param name="internalType">内部消息类型</param>
/// <returns>查询类型</returns>
private string MapInternalTypeToQueryType(string internalType)
{
return internalType?.ToUpper() switch
{
"FAULTRPT" => "faultRpt",
"VERSION" => "version",
"WAVECFG" => "waveCfg",
"WAVEDATA" => "waveDat",
"DZ" => "dz",
"ERROR" => "error",
_ => internalType?.ToLower() ?? string.Empty
};
}
private void HandleRecvMsg(JToken token, string type, bool isError = false)
{
// 检查是否有外部查询正在进行,如果有则信号查询完成
if (_queryCoordinationService.IsExternalQueryInProgress)
{
var status = _queryCoordinationService.GetStatus();
if (!string.IsNullOrEmpty(status.CurrentQueryId))
{
if (isError)
{
_logger.LogInformation("检测到错误消息,完成外部查询: {QueryId}", status.CurrentQueryId);
_queryCoordinationService.CompleteExternalQuery(status.CurrentQueryId, token.ToString());
}
else
{
// 映射内部类型到查询类型进行比较
var mappedType = type.ToLower();
var currentQueryType = _queryCoordinationService.CurrentQueryType?.ToLower();
_logger.LogInformation("消息类型匹配检查 - 接收类型: {ReceivedType}, 映射类型: {MappedType}, 期望类型: {ExpectedType}",
type, mappedType, currentQueryType);
if (mappedType == currentQueryType)
{
_logger.LogInformation("检测到匹配消息类型 {MessageType},完成外部查询: {QueryId}",
mappedType, status.CurrentQueryId);
_queryCoordinationService.CompleteExternalQuery(status.CurrentQueryId, token.ToString());
}
else
{
_logger.LogInformation("消息类型不匹配 - 接收: {ReceivedType}({MappedType}), 期望: {ExpectedType}",
type, mappedType, currentQueryType);
}
}
}
else
{
_logger.LogWarning("外部查询正在进行但查询ID为空");
}
}
else
{
//_logger.LogInformation("没有外部查询正在进行,忽略消息类型: {MessageType}", type);
}
}
/// <summary>
/// 处理HeartBeat心跳消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessHeartBeatMessageAsync(JToken contentToken)
{
try
{
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
foreach (var item in contentArray)
{
var heartBeatData = item.ToString();
}
}
else
{
_logger.LogWarning("HeartBeat message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "HEARTBEAT");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing HeartBeat message");
return Models.ProcessResult.Error($"HeartBeat processing error: {ex.Message}");
}
}
/// <summary>
/// 处理WaveCfg波形配置消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessWaveCfgMessageAsync(JToken contentToken)
{
try
{
_logger.LogInformation("Processing WaveCfg (wave configuration) message");
HandleRecvMsg(contentToken, "WAVECFG");
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
var processedCount = 0;
var errorCount = 0;
var validWaveCfgDataList = new List<WaveCfgData>();
foreach (var item in contentArray)
{
try
{
var waveCfgData = item.ToObject<WaveCfgData>();
if (waveCfgData != null && waveCfgData.IsValid())
{
_logger.LogInformation("波形配置: {WaveCfgData}", waveCfgData.ToString());
validWaveCfgDataList.Add(waveCfgData);
processedCount++;
}
else
{
_logger.LogWarning("查询中请稍后使用ftp获取: {Item}", item.ToString());
errorCount++;
}
}
catch (Exception itemEx)
{
_logger.LogError(itemEx, "处理单个波形配置失败: {Item}", item?.ToString());
errorCount++;
}
}
_logger.LogInformation("波形配置消息处理完成 - 成功: {ProcessedCount}, 错误: {ErrorCount}",
processedCount, errorCount);
}
else
{
_logger.LogWarning("WaveCfg message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "WAVECFG");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing WaveCfg message");
return Models.ProcessResult.Error($"WaveCfg processing error: {ex.Message}");
}
}
/// <summary>
/// 处理WaveData波形数据消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessWaveDataMessageAsync(JToken contentToken)
{
try
{
HandleRecvMsg(contentToken, "WAVEDATA");
_logger.LogInformation("Processing WaveData (wave data) message");
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
var processedCount = 0;
var errorCount = 0;
var totalDataSize = 0;
var validWaveDataList = new List<WaveDataInfo>();
foreach (var item in contentArray)
{
try
{
var waveDataInfo = item.ToObject<WaveDataInfo>();
validWaveDataList.Add(waveDataInfo);
}
catch (Exception itemEx)
{
_logger.LogError(itemEx, "处理单个波形数据失败: {Item}", item?.ToString());
errorCount++;
}
}
_logger.LogInformation("波形数据消息处理完成 - 成功: {ProcessedCount}, 错误: {ErrorCount}, 总数据量: {TotalSize}字节",
processedCount, errorCount, totalDataSize);
}
else
{
_logger.LogWarning("WaveData message content is not a valid array or is empty");
}
return Models.ProcessResult.Success(contentToken, "WAVEDATA");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing WaveData message");
return Models.ProcessResult.Error($"WaveData processing error: {ex.Message}");
}
}
/// <summary>
/// 处理AllData总召结果消息
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessAllDataMessageAsync(JToken contentToken)
{
try
{
_logger.LogInformation("Processing AllData (general interrogation result) message");
//总召返回字符串,内容为总召状态
if (contentToken is JArray contentArray && contentArray.Count > 0)
{
foreach (var item in contentArray)
{
_logger.LogInformation("总召结果: {Item}", item.ToString());
}
}
return Models.ProcessResult.Success(contentToken, "AllData");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing AllData message");
return Models.ProcessResult.Error($"AllData processing error: {ex.Message}");
}
}
/// <summary>
/// 处理网关通信数据消息,数据每小时发一次
/// </summary>
/// <param name="contentToken">消息内容</param>
/// <returns>处理结果</returns>
private async Task<Models.ProcessResult> ProcessGwErrorRatioMessageAsync(JToken contentToken)
{
return await _gwErrorRatioService.TranselateData(contentToken);
}
#endregion
/// <summary>
/// 处理报警消息
/// </summary>
/// <param name="json">报警JSON数据</param>
/// <returns>处理任务</returns>
public async Task HandleAlarmMessageAsync(string json)
{
if (string.IsNullOrWhiteSpace(json))
{
_logger.LogWarning("Attempted to process null or empty alarm message");
return;
}
try
{
// 异步上传报警消息
var uploadResult = await _alarmService.UploadAlarmMessageAsync(json);
if (uploadResult)
{
//_logger.LogDebug("Alarm message uploaded successfully");
}
else
{
//_logger.LogWarning("Alarm message upload returned false - may be queued for retry");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error handling alarm message: {Json}", json);
// 不重新抛出异常,避免影响上层调用
}
}
/// <summary>
/// 处理命令响应
/// </summary>
/// <param name="content">响应内容</param>
/// <param name="isAlarmData">是否为报警数据</param>
/// <returns>处理任务</returns>
public async Task HandleCommandResponseAsync(string content, bool isAlarmData)
{
try
{
// 报警数据是主动推送的,不需要处理命令响应
if (isAlarmData)
{
return;
}
var currentCommand = CommandStateMachine.CurrentCommand;
if (currentCommand == null)
{
return;
}
_logger.LogWarning("Detected error response: {Content}", content);
// 检查是否有外部查询正在进行,如果有则信号查询完成
if (_queryCoordinationService.IsExternalQueryInProgress)
{
var status = _queryCoordinationService.GetStatus();
if (!string.IsNullOrEmpty(status.CurrentQueryId))
{
_logger.LogInformation("检测到错误响应,完成外部查询: {QueryId}", status.CurrentQueryId);
_queryCoordinationService.CompleteExternalQuery(status.CurrentQueryId, content);
}
}
// 错误响应也视为命令完成,解除命令锁定
if (CommandStateMachine.CompleteCommand())
{
_logger.LogInformation("Command '{CommandName}' completed with error response: {Response}",
currentCommand.CommandName, content);
}
else
{
_logger.LogWarning("Failed to complete command '{CommandName}' with error response: {Response}",
currentCommand.CommandName, content);
}
await Task.CompletedTask;
return;
await Task.CompletedTask;
}
catch (Exception ex)
{
_logger.LogError(ex, "Error handling command response: {Content}", content);
}
}
public async Task<ProcessResult> ProcessDataAsync(ReadOnlyMemory<byte> data)
{
int contentLength = 0;
string content = "";
string errorMsg = "解析失败";
JToken? jcontent = null;
string type = "Error";
if (_messageParser.TryParseMessage(data.ToArray(),out contentLength, out content, out errorMsg, out jcontent, out type))
{
await ProcessMessageByTypeAsync(type, jcontent, content);
return ProcessResult.Success(jcontent, type);
}
return ProcessResult.Error(errorMsg);
}
/// <summary>
/// 预处理DZ数据项处理Value字段可能包含非数字值的情况
/// </summary>
/// <param name="item">原始JSON数据项</param>
/// <returns>处理后的JSON数据项</returns>
private JToken PreprocessDZDataItem(JToken item)
{
try
{
if (item is JObject jObject && jObject["Value"] != null)
{
var valueToken = jObject["Value"];
var valueString = valueToken?.ToString();
// 检查Value是否为非数字值如"退出"等中文字符)
if (!string.IsNullOrEmpty(valueString) && !decimal.TryParse(valueString, out _))
{
_logger.LogWarning("DZ数据Value字段包含非数字值: {Value}", valueString);
// 将非数字值替换为0
jObject["Value"] = valueString;
}
}
return item;
}
catch (Exception ex)
{
_logger.LogError(ex, "预处理DZ数据项时发生错误");
return item; // 返回原始数据,让后续处理决定如何处理
}
}
}
}