278 lines
11 KiB
C#
Raw Normal View History

2024-12-19 16:07:07 +08:00
using System;
using System.Linq;
2025-03-27 08:38:19 +08:00
using System.Runtime.CompilerServices;
2024-12-19 16:07:07 +08:00
using System.Threading.Tasks;
2025-03-27 08:38:19 +08:00
using DeviceDetectorNET.Parser.Device;
using DotNetCore.CAP;
2024-12-19 16:07:07 +08:00
using JiShe.CollectBus.Ammeters;
using JiShe.CollectBus.Common.Enums;
using JiShe.CollectBus.Common.Extensions;
2025-04-15 18:58:38 +08:00
using JiShe.CollectBus.Common.Helpers;
2024-12-19 16:07:07 +08:00
using JiShe.CollectBus.Enums;
using JiShe.CollectBus.Interceptors;
2025-03-14 14:28:04 +08:00
using JiShe.CollectBus.IotSystems.Devices;
using JiShe.CollectBus.IotSystems.MessageReceiveds;
2025-04-15 18:58:38 +08:00
using JiShe.CollectBus.Kafka.Producer;
2024-12-19 16:07:07 +08:00
using JiShe.CollectBus.Protocol.Contracts;
using MassTransit;
using Microsoft.Extensions.Logging;
using TouchSocket.Core;
using TouchSocket.Sockets;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using static FreeSql.Internal.GlobalFilter;
2024-12-19 16:07:07 +08:00
namespace JiShe.CollectBus.Plugins
{
2025-03-27 08:38:19 +08:00
public partial class TcpMonitor : PluginBase, ITransientDependency, ITcpReceivedPlugin, ITcpConnectingPlugin, ITcpConnectedPlugin, ITcpClosedPlugin
2024-12-19 16:07:07 +08:00
{
private readonly ICapPublisher _producerBus;
2025-04-15 18:58:38 +08:00
private readonly IProducerService _producerService;
2024-12-19 16:07:07 +08:00
private readonly ILogger<TcpMonitor> _logger;
private readonly IRepository<Device, Guid> _deviceRepository;
private readonly IDistributedCache<AmmeterInfo> _ammeterInfoCache;
/// <summary>
///
/// </summary>
2025-04-15 18:58:38 +08:00
/// <param name="producerService"></param>
2024-12-19 16:07:07 +08:00
/// <param name="logger"></param>
/// <param name="deviceRepository"></param>
/// <param name="ammeterInfoCache"></param>
public TcpMonitor(ICapPublisher producerBus, IProducerService producerService,
2025-03-27 08:38:19 +08:00
ILogger<TcpMonitor> logger,
IRepository<Device, Guid> deviceRepository,
2024-12-19 16:07:07 +08:00
IDistributedCache<AmmeterInfo> ammeterInfoCache)
{
_producerBus = producerBus;
2025-04-15 18:58:38 +08:00
_producerService = producerService;
2024-12-19 16:07:07 +08:00
_logger = logger;
_deviceRepository = deviceRepository;
_ammeterInfoCache = ammeterInfoCache;
}
2025-03-27 08:38:19 +08:00
public async Task OnTcpReceived(ITcpSession client, ReceivedDataEventArgs e)
2024-12-19 16:07:07 +08:00
{
var messageHexString = Convert.ToHexString(e.ByteBlock.Span);
var hexStringList = messageHexString.StringToPairs();
var aFn = (int?)hexStringList.GetAnalyzeValue(CommandChunkEnum.AFN);
var fn = (int?)hexStringList.GetAnalyzeValue(CommandChunkEnum.FN);
var aTuple = (Tuple<string, int>)hexStringList.GetAnalyzeValue(CommandChunkEnum.A);
if (aFn.HasValue && fn.HasValue && aTuple != null && !string.IsNullOrWhiteSpace(aTuple.Item1))
2024-12-19 16:07:07 +08:00
{
2025-03-27 08:38:19 +08:00
var tcpSessionClient = (ITcpSessionClient)client;
2024-12-19 16:07:07 +08:00
if ((AFN)aFn == AFN.)
{
switch (fn)
{
case 1:
2025-03-27 08:38:19 +08:00
await OnTcpLoginReceived(tcpSessionClient, messageHexString, aTuple.Item1);
2024-12-19 16:07:07 +08:00
break;
case 3:
2025-03-27 08:38:19 +08:00
//心跳帧有两种情况:
//1. 集中器先有登录帧,再有心跳帧
//2. 集中器没有登录帧,只有心跳帧
await OnTcpHeartbeatReceived(tcpSessionClient, messageHexString, aTuple.Item1);
2024-12-19 16:07:07 +08:00
break;
default:
_logger.LogError($"指令初步解析失败,指令内容:{messageHexString}");
break;
}
}
else
{
await OnTcpNormalReceived(tcpSessionClient, messageHexString, aTuple.Item1,aFn.ToString()!.PadLeft(2,'0'));
2024-12-19 16:07:07 +08:00
}
}
else
{
_logger.LogError($"指令初步解析失败,指令内容:{messageHexString}");
}
await e.InvokeNext();
}
2025-03-27 08:38:19 +08:00
//[GeneratorPlugin(typeof(ITcpConnectingPlugin))]
public async Task OnTcpConnecting(ITcpSession client, ConnectingEventArgs e)
2024-12-19 16:07:07 +08:00
{
2025-03-27 08:38:19 +08:00
var tcpSessionClient = (ITcpSessionClient)client;
_logger.LogInformation($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}正在连接中...");
2024-12-19 16:07:07 +08:00
await e.InvokeNext();
}
2025-03-27 08:38:19 +08:00
//[GeneratorPlugin(typeof(ITcpConnectedPlugin))]
public async Task OnTcpConnected(ITcpSession client, ConnectedEventArgs e)
2024-12-19 16:07:07 +08:00
{
2025-03-27 08:38:19 +08:00
var tcpSessionClient = (ITcpSessionClient)client;
_logger.LogInformation($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}已连接");
2024-12-19 16:07:07 +08:00
await e.InvokeNext();
}
2025-03-27 08:38:19 +08:00
//[GeneratorPlugin(typeof(ITcpClosedPlugin))]//ITcpSessionClient
public async Task OnTcpClosed(ITcpSession client, ClosedEventArgs e)
2024-12-19 16:07:07 +08:00
{
2025-03-27 08:38:19 +08:00
var tcpSessionClient = (ITcpSessionClient)client;
var entity = await _deviceRepository.FindAsync(a => a.ClientId == tcpSessionClient.Id);
2024-12-19 16:07:07 +08:00
if (entity != null)
{
entity.UpdateByOnClosed();
await _deviceRepository.UpdateAsync(entity);
}
else
{
2025-03-27 08:38:19 +08:00
_logger.LogWarning($"[TCP] ID:{tcpSessionClient.Id} IP:{client.GetIPPort()}已关闭连接,但采集程序检索失败");
2024-12-19 16:07:07 +08:00
}
await e.InvokeNext();
}
/// <summary>
/// 登录帧处理
/// </summary>
/// <param name="client"></param>
/// <param name="messageHexString"></param>
/// <param name="deviceNo">集中器编号</param>
/// <returns></returns>
2025-03-12 17:10:00 +08:00
private async Task OnTcpLoginReceived(ITcpSessionClient client, string messageHexString, string deviceNo)
2024-12-19 16:07:07 +08:00
{
2025-03-27 08:38:19 +08:00
string oldClientId = $"{client.Id}";
await client.ResetIdAsync(deviceNo);
var deviceInfoList= await _deviceRepository.GetListAsync(a => a.Number == deviceNo);
if (deviceInfoList != null && deviceInfoList.Count > 1)
{
//todo 推送集中器编号重复预警
_logger.LogError($"集中器编号:{deviceNo},存在多个集中器,请检查集中器编号是否重复");
return;
}
var entity = deviceInfoList?.FirstOrDefault(a => a.Number == deviceNo);
2025-03-27 08:38:19 +08:00
if (entity == null)
{
await _deviceRepository.InsertAsync(new Device(deviceNo, oldClientId, DateTime.Now, DateTime.Now, DeviceStatus.Online));
}
else
{
entity.UpdateByLoginAndHeartbeat(oldClientId);
await _deviceRepository.UpdateAsync(entity);
}
2024-12-19 16:07:07 +08:00
var messageReceivedLoginEvent = new MessageReceivedLogin
{
2025-03-27 08:38:19 +08:00
ClientId = deviceNo,
2024-12-19 16:07:07 +08:00
ClientIp = client.IP,
ClientPort = client.Port,
MessageHexString = messageHexString,
DeviceNo = deviceNo,
MessageId = NewId.NextGuid().ToString()
};
//await _producerBus.PublishAsync(ProtocolConst.SubscriberLoginReceivedEventName, messageReceivedLoginEvent);
2025-04-16 18:26:25 +08:00
await _producerService.ProduceAsync(ProtocolConst.SubscriberLoginReceivedEventName, messageReceivedLoginEvent);
2025-04-01 22:50:34 +08:00
2025-04-07 21:50:50 +08:00
//await _producerBus.Publish( messageReceivedLoginEvent);
2025-03-27 08:38:19 +08:00
}
private async Task OnTcpHeartbeatReceived(ITcpSessionClient client, string messageHexString, string deviceNo)
{
string clientId = deviceNo;
string oldClientId = $"{client.Id}";
var deviceInfoList = await _deviceRepository.GetListAsync(a => a.Number == deviceNo);
if (deviceInfoList != null && deviceInfoList.Count > 1)
{
//todo 推送集中器编号重复预警
_logger.LogError($"集中器编号:{deviceNo},存在多个集中器,请检查集中器编号是否重复");
return;
}
var entity = deviceInfoList?.FirstOrDefault(a => a.Number == deviceNo);
2025-03-27 08:38:19 +08:00
if (entity == null) //没有登录帧的设备,只有心跳帧
2024-12-19 16:07:07 +08:00
{
2025-03-27 08:38:19 +08:00
await client.ResetIdAsync(clientId);
await _deviceRepository.InsertAsync(new Device(deviceNo, oldClientId, DateTime.Now, DateTime.Now, DeviceStatus.Online));
2024-12-19 16:07:07 +08:00
}
else
{
2025-03-27 08:38:19 +08:00
if (clientId != oldClientId)
{
entity.UpdateByLoginAndHeartbeat(oldClientId);
}
else
{
entity.UpdateByLoginAndHeartbeat();
}
2024-12-19 16:07:07 +08:00
await _deviceRepository.UpdateAsync(entity);
}
var messageReceivedHeartbeatEvent = new MessageReceivedHeartbeat
{
2025-03-27 08:38:19 +08:00
ClientId = clientId,
2024-12-19 16:07:07 +08:00
ClientIp = client.IP,
ClientPort = client.Port,
MessageHexString = messageHexString,
DeviceNo = deviceNo,
MessageId = NewId.NextGuid().ToString()
};
//await _producerBus.PublishAsync(ProtocolConst.SubscriberHeartbeatReceivedEventName, messageReceivedHeartbeatEvent);
2025-04-16 18:26:25 +08:00
await _producerService.ProduceAsync(ProtocolConst.SubscriberHeartbeatReceivedEventName, messageReceivedHeartbeatEvent);
2025-04-07 21:50:50 +08:00
//await _producerBus.Publish(messageReceivedHeartbeatEvent);
2024-12-19 16:07:07 +08:00
}
/// <summary>
/// 正常帧处理将不同的AFN进行分发
/// </summary>
/// <param name="client"></param>
/// <param name="messageHexString"></param>
/// <param name="deviceNo"></param>
/// <param name="aFn"></param>
/// <returns></returns>
private async Task OnTcpNormalReceived(ITcpSessionClient client, string messageHexString, string deviceNo,string aFn)
2024-12-19 16:07:07 +08:00
{
2025-04-07 21:50:50 +08:00
//await _producerBus.Publish(new MessageReceived
2025-04-01 22:50:34 +08:00
//{
// ClientId = client.Id,
// ClientIp = client.IP,
// ClientPort = client.Port,
// MessageHexString = messageHexString,
// DeviceNo = deviceNo,
// MessageId = NewId.NextGuid().ToString()
//});
2025-04-07 21:50:50 +08:00
2025-04-10 17:06:53 +08:00
//string topicName = string.Format(ProtocolConst.AFNTopicNameFormat, aFn);
2025-04-10 23:31:43 +08:00
//todo 如何确定时标?目前集中器的采集频率,都是固定,数据上报的时候,根据当前时间,往后推测出应当采集的时间点作为时标。但是如果由于网络问题,数据一直没上报的情况改怎么计算?
//await _producerBus.PublishAsync(ProtocolConst.SubscriberReceivedEventName, new MessageReceived
//{
// ClientId = client.Id,
// ClientIp = client.IP,
// ClientPort = client.Port,
// MessageHexString = messageHexString,
// DeviceNo = deviceNo,
// MessageId = NewId.NextGuid().ToString()
//});
2025-04-15 18:58:38 +08:00
await _producerService.ProduceAsync(ProtocolConst.SubscriberReceivedEventName, new MessageReceived
2025-04-07 21:50:50 +08:00
{
ClientId = client.Id,
ClientIp = client.IP,
ClientPort = client.Port,
MessageHexString = messageHexString,
DeviceNo = deviceNo,
MessageId = NewId.NextGuid().ToString()
2025-04-16 18:26:25 +08:00
});
2024-12-19 16:07:07 +08:00
}
}
}