using Jint; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json.Linq; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Http; using System.Net.Http.Json; using System.Numerics; using System.Text; using System.Threading; using System.Threading.Tasks; using YunDa.Server.ISMSTcp.Domain; using YunDa.Server.ISMSTcp.Interfaces; using YunDa.Server.ISMSTcp.Models; using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection; namespace YunDa.Server.ISMSTcp.Services { public class WebApiSettings { public int Port { get; set; } } public class SecondaryCircuitInspectionPlanStateModel { //执行时间 public DateTime ExecuteTime { get; set; } = DateTime.MinValue; public SecondaryCircuitInspectionPlanOutput Plan { get; set; } public SecondaryCircuitInspectionPlanStateModel() { Plan = new SecondaryCircuitInspectionPlanOutput(); } } //二次回路巡检计划 public class SecondaryCircuitInspectionPlanService { private readonly ILogger _logger; private readonly IApiEndpoints _apiEndpoints; private readonly WebApiRequest _webApiRequest; private readonly WebApiSettings _webApiSettings; private bool _updatedPlanOk = false; private Queue _planList; private readonly object _planLock = new object(); private int _planCheckDay = 0; public SecondaryCircuitInspectionPlanService( ILogger logger, IApiEndpoints apiEndpoints, WebApiRequest webApiRequest, IOptions webApiOptions ) { _apiEndpoints = apiEndpoints ?? throw new ArgumentNullException(nameof(apiEndpoints)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _webApiRequest = webApiRequest ?? throw new ArgumentNullException(nameof(webApiRequest)); _webApiSettings = webApiOptions.Value; _planList = new Queue(); StartAsync(); } private async Task StartAsync() { //更新计划 _ = Task.Run(async () => { while (true) {//每30秒更新一下配置 await UpdatePlans(); await Task.Delay(30000); } }); //执行计划 _ = Task.Run(async () => { while (true) {//每个小时,更新一下全体孪生状态 if (_updatedPlanOk) { await CheckPlan(); await Task.Delay(10 * 1000); } else { await Task.Delay(10000); } } }); await Task.CompletedTask; } //更新计划 private async Task UpdatePlans() { try { var list = await _webApiRequest.GetSecondaryCircuitInspectionPlanListAsync(); if (list != null) { lock (_planLock) { var oldPlan = _planList.ToArray(); _planList.Clear(); List planlist = new List(); foreach (var item in list) { planlist.Add(new SecondaryCircuitInspectionPlanStateModel() { Plan = item }); } foreach (var item in planlist) { var plan = oldPlan.FirstOrDefault(x => x.Plan.Name == item.Plan.Name && x.Plan.ScheduledTimeString == item.Plan.ScheduledTimeString); if (plan != null) { item.ExecuteTime = plan.ExecuteTime; } _planList.Enqueue(item); } //获取到绑定信息,可以更新全部状态了 if (planlist.Count > 0) _updatedPlanOk = true; } } } catch (Exception ex) { _updatedPlanOk = false; } await Task.CompletedTask; } //检测计划,判断计划是否该执行 private async Task CheckPlan() { bool ret = false; if (_planList == null) return ret; try { SecondaryCircuitInspectionPlanStateModel[] planList; lock (_planLock) { planList = _planList.ToArray(); } DateTime now = DateTime.Now; int week = DateTime.Now.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)DateTime.Now.DayOfWeek; if (now.Day != _planCheckDay) {//翻天,清空已执行标记 lock (_planLock) { foreach (var item in _planList) item.ExecuteTime = DateTime.MinValue; } } _planCheckDay = now.Day; foreach (var item in planList) { if (item.ExecuteTime == DateTime.MinValue && item.Plan.IsActive) {//当天未执行 if (now.Hour == item.Plan.ScheduledHour && now.Minute == item.Plan.ScheduledMinute) { if (item.Plan.ScheduledWeekDaysList.IndexOf(week) != -1) { if (await ExecutePlan(item.Plan)) {//执行成功 lock (_planLock) { item.ExecuteTime = DateTime.Now; } ret = true; } } } } } } catch (Exception ex) { _logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CheckPlan:发生错误"); } return ret; } //执行计划 private async Task ExecutePlan(SecondaryCircuitInspectionPlanOutput plan) { try { bool ret = true; var engine = new Jint.Engine(); foreach (var item in plan.InspectionItems) { if(!string.IsNullOrWhiteSpace(item.CalculationExpression)) { engine.Execute(item.CalculationExpression); var result = engine.Invoke("calculate", new List()).AsNumber(); } } return ret; } catch (Exception ex) { _logger.LogError(ex, "SecondaryCircuitInspectionPlanService - ExecutePlan:发生错误"); } return false; } //获取遥测数据 public async Task> CallYCByDataIdAsync(CallYCByDataIdRequest request, CancellationToken cancellationToken = default) { try { using var httpClient = new HttpClient(); string url = $"http://127.0.0.1:{_webApiSettings.Port}/api/CallYCByDataId"; var response = await httpClient.PostAsJsonAsync(url, request); response.EnsureSuccessStatusCode(); var result = await response.Content.ReadAsStringAsync(); JObject obj = JObject.Parse(result); if (obj.ContainsKey("data")) { JArray jArray = obj.Value("data"); if (jArray != null) { List list = jArray.ToObject>(); return list; } } } catch(Exception ex) { _logger.LogError(ex, "SecondaryCircuitInspectionPlanService - CallYCByDataIdAsync:发生错误"); } return null; } } }