SOMS/src/YunDa.Server/YunDa.Server.ISMSTcp/Services/TelesignalisationHandle.cs
2025-07-31 18:51:24 +08:00

269 lines
11 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 System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using YunDa.SOMS.DataTransferObject.GeneralInformation.EquipmentLiveDataDto;
using YunDa.SOMS.Redis.Repositories;
using YunDa.Server.ISMSTcp.Models;
namespace YunDa.Server.ISMSTcp.Services
{
/// <summary>
/// 遥信数据处理服务
/// </summary>
public class TelesignalisationHandle
{
private readonly ILogger<TelesignalisationHandle> _logger;
private readonly IRedisRepository<TelesignalisationModel, string> _telesignalisationModelListRedis;
private readonly string _telesignalisationModelListRediskey = "telesignalisationModelList";
// 映射字典YX_ID -> haskey
private readonly ConcurrentDictionary<string, string> _yxIdToHashKeyMapping = new ConcurrentDictionary<string, string>();
// 初始化状态
private volatile bool _isInitialized = false;
private readonly object _initLock = new object();
/// <summary>
/// 构造函数
/// </summary>
/// <param name="logger">日志服务</param>
/// <param name="telesignalisationModelListRedis">遥信数据Redis仓储</param>
public TelesignalisationHandle(
ILogger<TelesignalisationHandle> logger,
IRedisRepository<TelesignalisationModel, string> telesignalisationModelListRedis)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_telesignalisationModelListRedis = telesignalisationModelListRedis ?? throw new ArgumentNullException(nameof(telesignalisationModelListRedis));
}
/// <summary>
/// 初始化遥信数据映射
/// </summary>
/// <param name="maxRetries">最大重试次数</param>
/// <param name="retryDelayMs">重试间隔(毫秒)</param>
/// <returns>初始化任务</returns>
public async Task<bool> InitAsync(int maxRetries = 3, int retryDelayMs = 2000)
{
if (_isInitialized)
{
_logger.LogInformation("遥信数据映射已经初始化完成");
return true;
}
lock (_initLock)
{
if (_isInitialized)
{
return true;
}
_logger.LogInformation("开始初始化遥信数据映射...");
}
for (int attempt = 1; attempt <= maxRetries; attempt++)
{
try
{
_logger.LogInformation("第 {Attempt}/{MaxRetries} 次尝试查询遥信数据", attempt, maxRetries);
// 查询所有遥信数据,使用固定的数据源类别 "Zongzi" (0)
string redisKey = $"{_telesignalisationModelListRediskey}_Zongzi";
var telesignalisationModels = await _telesignalisationModelListRedis.HashSetGetAllAsync(redisKey);
if (telesignalisationModels == null || telesignalisationModels.Count == 0)
{
_logger.LogWarning("第 {Attempt} 次查询遥信数据为空Redis键: {RedisKey}", attempt, redisKey);
if (attempt < maxRetries)
{
_logger.LogInformation("等待 {DelayMs} 毫秒后重试...", retryDelayMs);
await Task.Delay(retryDelayMs);
continue;
}
else
{
_logger.LogError("所有重试都失败,无法获取遥信数据");
return false;
}
}
// 创建映射字典
int mappingCount = 0;
foreach (var model in telesignalisationModels)
{
if (!string.IsNullOrEmpty(model.ismsbaseYXId))
{
// 构造haskey格式"{dev_addr}_{dev_sector}_{dev_inf}_0"
// 这里使用模型中的地址信息
string haskey = $"{model.InfoDeviceAddress}_{model.InfoCPUSector}_{model.InfoAddress}_0";
if (_yxIdToHashKeyMapping.TryAdd(model.ismsbaseYXId, haskey))
{
mappingCount++;
_logger.LogDebug("添加映射: YX_ID={YxId} -> haskey={HasKey}", model.ismsbaseYXId, haskey);
}
else
{
_logger.LogWarning("重复的YX_ID: {YxId},跳过映射", model.ismsbaseYXId);
}
}
else
{
_logger.LogDebug("遥信模型 {ModelName} 的 ismsbaseYXId 为空,跳过", model.Name);
}
}
lock (_initLock)
{
_isInitialized = true;
}
_logger.LogInformation("遥信数据映射初始化成功!总计 {TotalModels} 个模型,创建 {MappingCount} 个映射",
telesignalisationModels.Count, mappingCount);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "第 {Attempt} 次初始化遥信数据映射时发生错误", attempt);
if (attempt < maxRetries)
{
_logger.LogInformation("等待 {DelayMs} 毫秒后重试...", retryDelayMs);
await Task.Delay(retryDelayMs);
}
else
{
_logger.LogError("所有重试都失败,初始化遥信数据映射失败");
return false;
}
}
}
return false;
}
/// <summary>
/// 处理遥信数据
/// </summary>
/// <param name="yxData">遥信数据JSON令牌</param>
/// <returns>处理任务</returns>
public async Task ProcessYXDataAsync(JToken yxData)
{
try
{
_logger.LogInformation("开始处理遥信数据: {YXData}", yxData?.ToString());
if (yxData == null)
{
_logger.LogWarning("遥信数据为空,跳过处理");
return;
}
if (!_isInitialized)
{
_logger.LogWarning("遥信数据映射尚未初始化,跳过处理");
return;
}
// 解析YXData数组
if (yxData is JArray yxArray)
{
_logger.LogInformation("处理遥信数据数组,包含 {Count} 个项目", yxArray.Count);
foreach (var item in yxArray)
{
await ProcessSingleYXDataAsync(item);
}
}
else if (yxData is JObject yxObject)
{
await ProcessSingleYXDataAsync(yxObject);
}
else
{
_logger.LogWarning("不支持的遥信数据格式: {DataType}", yxData.Type);
}
_logger.LogInformation("遥信数据处理完成");
}
catch (Exception ex)
{
_logger.LogError(ex, "处理遥信数据时发生错误: {YXData}", yxData?.ToString());
throw;
}
}
/// <summary>
/// 处理单个遥信数据项
/// </summary>
/// <param name="yxItem">单个遥信数据项</param>
/// <returns>处理任务</returns>
private async Task ProcessSingleYXDataAsync(JToken yxItem)
{
try
{
// 解析YXData结构
var yxDataModel = yxItem.ToObject<YXData>();
if (yxDataModel == null)
{
_logger.LogWarning("无法解析遥信数据项: {Item}", yxItem?.ToString());
return;
}
_logger.LogDebug("处理遥信数据: YX_ID={YxId}, V={Value}, T={Time}",
yxDataModel.YX_ID, yxDataModel.V, yxDataModel.T);
// 使用映射字典查找对应的haskey
if (!_yxIdToHashKeyMapping.TryGetValue(yxDataModel.YX_ID, out string haskey))
{
_logger.LogWarning("未找到YX_ID {YxId} 对应的映射", yxDataModel.YX_ID);
return;
}
// 构建Redis键
string redisKey = $"{_telesignalisationModelListRediskey}_Zongzi";
// 从Redis获取现有数据
var telesignalisationModel = await _telesignalisationModelListRedis.HashSetGetOneAsync(redisKey, haskey);
if (telesignalisationModel == null)
{
_logger.LogWarning("Redis中未找到遥信数据: RedisKey={RedisKey}, HasKey={HasKey}", redisKey, haskey);
return;
}
// 解析时间
DateTime resultTime = DateTime.Now;
if (!string.IsNullOrEmpty(yxDataModel.T))
{
if (DateTime.TryParse(yxDataModel.T, out DateTime parsedTime))
{
resultTime = parsedTime;
}
else
{
_logger.LogWarning("无法解析时间格式: {TimeStr},使用当前时间", yxDataModel.T);
}
}
// 更新数据
telesignalisationModel.ResultTime = resultTime;
telesignalisationModel.ResultValue = yxDataModel.V;
// 保存到Redis
await _telesignalisationModelListRedis.HashSetUpdateOneAsync(redisKey, haskey, telesignalisationModel);
_logger.LogDebug("成功更新遥信数据: YX_ID={YxId}, HasKey={HasKey}, 值={Value}",
yxDataModel.YX_ID, haskey, yxDataModel.V);
}
catch (Exception ex)
{
_logger.LogError(ex, "处理单个遥信数据项时发生错误: {Item}", yxItem?.ToString());
}
}
}
}