EquipmentController.cs 5.46 KB
using HHECS.BllModel;
using HHECS.DAQServer.Dto.Equipment;
using HHECS.DAQServer.Models;
using HHECS.DAQServer.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using System.Text;
using System.Text.Json;

namespace HHECS.DAQServer.Controllers
{
    /// <summary>
    /// 设备数据
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class EquipmentController : ControllerBase
    {
        private readonly IFreeSql _freeSql;
        private readonly DataCacheService _dataCacheService;
        private readonly IDistributedCache _cache;

        public EquipmentController(IFreeSql freeSql, DataCacheService dataCacheService, IDistributedCache cache)
        {
            _freeSql = freeSql;
            _dataCacheService = dataCacheService;
            _cache = cache;
        }

        /// <summary>
        /// 推送设备实时数据
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<BllResult> SendEquipmentData(IEnumerable<EquipmentDataDto> data)
        {
            try
            {
                if (!data.Any())
                {
                    return BllResultFactory.Error($"数据不能为空!");
                }

                //小于此时间,认为是无效数据
                var minStartTime = DateTime.Parse("2024-6-10");

                var records = data.Select(x => new EquipmentDataRecord
                {
                    EquipmentCode = x.EquipmentSN,
                    Tags = JsonSerializer.Serialize(x.Reported),
                    IsHandle = false,
                    Version = x.Version,
                    CreateTime = TimestampConvertToLocalDateTime(x.Timestamp),
                    Timestamp = x.Timestamp,
                }).Where(x => x.CreateTime != default && x.CreateTime >= minStartTime).ToList();

                //缓存配置
                var options = new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(10));

                //缓存设备实时数据
                foreach (var record in data.GroupBy(x => x.EquipmentSN))
                {
                    //获取最新时间戳的数据
                    var lastItem = record.OrderByDescending(x => x.Timestamp).First();

                    //获取当前缓存数据
                    var cacheDataBytes = await _cache.GetAsync(record.Key);
                    if (cacheDataBytes != null)
                    {
                        var cacheData = JsonSerializer.Deserialize<EquipmentDataDto>(Encoding.Default.GetString(cacheDataBytes));
                        if (cacheData.Timestamp >= lastItem.Timestamp)
                        {
                            continue;
                        }
                    }

                    var encodedCurrentData = JsonSerializer.SerializeToUtf8Bytes(lastItem);
                    await _cache.SetAsync(record.Key, encodedCurrentData, options);
                }

                const int maxCount = 1000 * 5;

                //缓存队列超过设定值,暂时不记录到队列,降低数据丢失的风险
                if (_dataCacheService.EquipmentDataRecordQueue.Count >= maxCount)
                {
                    return BllResultFactory.Error($"数据队列缓存超过设定值({maxCount}),待当前队列处理完成后才能继续");
                }

                //加入缓存队列,存入数据库
                foreach (var item in records)
                {
                    _dataCacheService.EquipmentDataRecordQueue.Enqueue(item);
                }

                return BllResultFactory.Success();
            }
            catch (Exception ex)
            {
                return BllResultFactory.Error(ex.Message);
            }
        }

        /// <summary>
        /// 更新设备在线状态
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<BllResult> UpdateClientStatus(ClientStatusDto data)
        {
            try
            {
                var clientStatusRepository = _freeSql.GetRepository<ClientStatus>();
                var client = await clientStatusRepository.Where(x => x.ClientKeys == data.ClientId).FirstAsync();
                if (client == null)
                {
                    return BllResultFactory.Error($"客户端标识:{data.ClientId}不存在,请查验后再试!");
                }
                clientStatusRepository.Attach(client);
                client.LastSeenDate = DateTime.Now;
                await clientStatusRepository.UpdateAsync(client);
                return BllResultFactory.Success();
            }
            catch (Exception ex)
            {
                return BllResultFactory.Error(ex.Message);
            }
        }

        /// <summary>
        /// 时间戳转本地时间
        /// </summary>
        /// <param name="timestamp">时间戳</param>
        /// <returns></returns>
        private DateTime TimestampConvertToLocalDateTime(long timestamp)
        {
            var timestampLength = Math.Abs(timestamp).ToString().Length;

            DateTime time = default;

            //时间戳为秒
            if (timestampLength == 10)
            {
                time = DateTimeOffset.FromUnixTimeSeconds(timestamp).LocalDateTime;
            }
            //时间戳为毫秒
            else if (timestampLength == 13)
            {
                time = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).LocalDateTime;
            }

            //其他情况,无效数据
            return time;
        }
    }
}