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