using Microsoft.Extensions.Logging; using Org.BouncyCastle.Utilities; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using YunDa.Server.ISMSTcp.Domain; using YunDa.Server.ISMSTcp.Interfaces; namespace YunDa.Server.ISMSTcp.Services { public class ZzDataPoint { public DateTime TimeStamp { get; set; } public double Value { get; } public string ValueStr { get; } public ZzDataPoint(DateTime time, double value, string valueStr) { TimeStamp = time; Value = value; ValueStr = valueStr; } } public class ZzData { public TimeSpan Retention { get; set; } public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public int? DispatcherAddress { get; set; } = null; ///////////////////////////////////////////////////////////////////////////////////// public double Value { get; set; } public string ValueStr { get; set; } = string.Empty; public DateTime TimeStamp { get; set; } ///////////////////////////////////////////////////////////////////////////////////// private readonly ConcurrentQueue<(DateTime time, ZzDataPoint point)> _queue = new ConcurrentQueue<(DateTime time, ZzDataPoint point)>(); public ZzData(int minutes, string id, string name, int dispatcherAddress) { Retention = TimeSpan.FromMinutes(minutes); Id = id; Name = name; DispatcherAddress = dispatcherAddress; } public void AddData(ZzDataPoint point) { DateTime now = DateTime.Now; point.TimeStamp = now; //2025-11-18 用当前时间(临时修改) _queue.Enqueue((now, point)); TimeStamp = point.TimeStamp; Value = point.Value; ValueStr = point.ValueStr; CleanupOldData(); } private void CleanupOldData() { DateTime limit = DateTime.Now - Retention; while (_queue.TryPeek(out var dp) && dp.time < limit) { _queue.TryDequeue(out _); } } public List GetData(DateTime start, DateTime end) { return _queue.Where(dp => dp.point.TimeStamp >= start && dp.point.TimeStamp <= end) .Select(x => x.point) .ToList(); } } public class ZzDataRequestModel { public List Id { get; set; } public int Times { get; set; } public int TimeWindowType { get; set; } } public class ZzDataResultModel { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public int? DispatcherAddress { get; set; } = null; public double Value { get; set; } public string ValueStr { get; set; } = string.Empty; public DateTime TimeStamp { get; set; } = DateTime.MinValue; public List Data { get; set; } = new List(); public ZzDataResultModel() { } public ZzDataResultModel(ZzData data) { Id = data.Id; Name = data.Name; Value = data.Value; ValueStr = data.ValueStr; TimeStamp = data.TimeStamp; DispatcherAddress = data.DispatcherAddress; } } public class ZzDataHistoryModel { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; } public class ZzDataCacheContainer { private readonly ConcurrentDictionary _datas = new ConcurrentDictionary(); private readonly int _cleanupMinutes = 5; public ZzDataCacheContainer(int cleanupMinutes) { _cleanupMinutes = cleanupMinutes; } public void Write(string id, double val, DateTime time, string name) { var data = _datas.GetOrAdd(id, _ => new ZzData(_cleanupMinutes, id, name, 0)); data.AddData(new ZzDataPoint(time, val, "")); } public void Write(string id, double val, DateTime time, string name, string valStr) { var data = _datas.GetOrAdd(id, _ => new ZzData(_cleanupMinutes, id, name, 0)); data.AddData(new ZzDataPoint(time, val, valStr)); } public void Write(string id, double val, DateTime time, string name, string valStr, int dispatcherAddress) { //if (id == "YCB001101001") //{ // int kk = 0; //} var data = _datas.GetOrAdd(id, _ => new ZzData(_cleanupMinutes, id, name, dispatcherAddress)); data.AddData(new ZzDataPoint(time, val, valStr)); } public Dictionary Read(List ids, DateTime start, DateTime end) { var result = new Dictionary(); foreach (var id in ids) { //if (id == "YCB001101001") //{ // int kk = 0; //} if (_datas.TryGetValue(id, out var channel)) { ZzDataResultModel data = new ZzDataResultModel(channel); data.Data = channel.GetData(start, end); if(data.Data.Count == 0 && data.TimeStamp != DateTime.MinValue) { ZzDataPoint zzDataPoint = new ZzDataPoint(DateTime.Now, data.Value, data.ValueStr); data.Data.Add(zzDataPoint); } result[id] = data; } } return result; } public async Task> Read(List ids, int seconds, int timeWindowType, CancellationToken cancellationToken, DateTime now = default) { try { if(now == default) now = DateTime.Now; //寻找匹配的值 Dictionary matched1 = new Dictionary(); Dictionary matched2 = new Dictionary(); if (timeWindowType == 0 || timeWindowType == 2) { matched1 = Read(ids, now.AddSeconds(-seconds), now); } if (timeWindowType == 1 || timeWindowType == 2) { int span = seconds*1000 - (int)(DateTime.Now - now).TotalMilliseconds; if(span > 0) await Task.Delay(span, cancellationToken); matched2 = Read(ids, now, DateTime.Now); } foreach (var kv in matched2) { if (!matched1.TryAdd(kv.Key, kv.Value)) { matched1[kv.Key].Data.AddRange(kv.Value.Data); } } return matched1.Values.ToList(); } catch (Exception ex) { return new List(); } } } public class ZzDataCacheContainerInit { private readonly ILogger _logger; private readonly WebApiRequest _webApiRequest; private readonly ZzTcpService _zTcpService = null; public ZzDataCacheContainerInit(ILogger logger, WebApiRequest webApiRequest, ZzTcpService zTcpService) { _logger = logger; _webApiRequest = webApiRequest; _zTcpService = zTcpService; } public void InitTcpService(ITcpClient tcpClient) { _zTcpService.Init(tcpClient); } //初始化虚点信息 public async Task InitVariantBaseinfo(ZzDataCacheContainer cache) { //从数据库获取 var list = await _webApiRequest.GetVariantBaseinfoAsync(); if (list != null) { foreach (var item in list) { cache.Write(item.Id, 2, DateTime.Now, item.Name, "不定"); } } //发送命令从综自获取 if(_zTcpService != null) { string cmd = "CallVAByStat|B001"; for (int i = 0; i < 3; i++) { var sendResult = await _zTcpService.SendTcpMessageAsync(cmd, CancellationToken.None); if (sendResult.Success) { break; } await Task.Delay(1000); } } } //初始化网关信息 public async Task InitGateWayBaseInfo(ZzDataCacheContainer cache) { var list = await _webApiRequest.GetGateWayBaseInfoAsync(); if (list != null) { foreach (var item in list) { cache.Write(item.Id, 0, DateTime.Now, item.Name, "0.00 %"); } } } } }