using EVCB_OCPP.Domain; using EVCB_OCPP.Domain.Models.MainDb; using EVCB_OCPP.Packet.Features; using EVCB_OCPP.Packet.Messages; using EVCB_OCPP.WSServer.Message; using EVCB_OCPP.WSServer.Service.WsService; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Quartz; namespace EVCB_OCPP.WSServer.Jobs; [DisallowConcurrentExecution] public class ServerMessageJob : IJob { public ServerMessageJob( ProtalServer protalServer, IDbContextFactory maindbContextFactory, ILogger logger) { this.protalServer = protalServer; this.maindbContextFactory = maindbContextFactory; this.logger = logger; } private readonly ProtalServer protalServer; private readonly IDbContextFactory maindbContextFactory; private readonly ILogger logger; public async Task Execute(IJobExecutionContext context) { //logger.LogDebug("{0} Started", nameof(ServerMessageJob)); try { await ExecuteTrigger(); } catch (Exception ex) { logger.LogError("ServerMessageTrigger Ex:{0}", ex.ToString()); } } private async Task ExecuteTrigger() { protalServer.RemoveConfirmMessage(); BasicMessageHandler msgAnalyser = new BasicMessageHandler(); var dateTimeNow = DateTime.UtcNow; DateTime startDt = dateTimeNow.AddSeconds(-30); DateTime dt = new DateTime(1991, 1, 1); DateTime currentTime = dateTimeNow; List commandList; var clientDic = protalServer.GetClientDic(); using (var db = await maindbContextFactory.CreateDbContextAsync()) { commandList = await db.ServerMessages.Where(c => c.ReceivedOn == dt && c.UpdatedOn == dt && c.CreatedOn >= startDt && c.CreatedOn <= currentTime).AsNoTracking().ToListAsync(); } //處理主機傳送的有指令 var cmdMachineList = commandList.Select(c => c.ChargeBoxId).Distinct().ToList(); if (commandList.Count > 0) { // Console.WriteLine(string.Format("Now:{0} commandList Count:{1} ", DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"), commandList.Count)); } var resendList = protalServer.GetResendMessage(); foreach (var resendItem in resendList) { WsClientData session; if (clientDic.TryGetValue(resendItem.ChargePointSerialNumber, out session)) { if (dateTimeNow.Subtract(resendItem.SentOn).TotalSeconds > 1) { resendItem.SentTimes--; resendItem.SentOn = dateTimeNow; protalServer.SendMsg(session, resendItem.SentMessage, string.Format("{0} {1}", resendItem.SentAction, "Request"), ""); } } } foreach (var charger_SN in cmdMachineList) { WsClientData session; string uuid = string.Empty; if (!clientDic.TryGetValue(charger_SN, out session)) { continue; } //logger.LogDebug(string.Format("charger_SN:{0} startDt:{1} CreatedOn:{2}", charger_SN, startDt.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm:ss"))); if (session.IsCheckIn && !session.ISOCPP20) { string rawRequest = string.Empty; var cmdList = commandList.Where(c => c.ChargeBoxId == charger_SN).ToList(); var profiles = protalServer.Profiles; foreach (var item in cmdList) { IRequest request = null; Actions action = Actions.None; Enum.TryParse(item.OutAction, out action); Type _RequestType = null; for (int i = 0; i < profiles.Count; i++) { var feature = profiles[i].GetFeaturebyAction(item.OutAction); if (feature != null) { _RequestType = feature.GetRequestType(); break; } } if (_RequestType != null && item.CreatedBy != "Destroyer") { request = JsonConvert.DeserializeObject(item.OutRequest, _RequestType) as IRequest; uuid = session.queue.store(request); rawRequest = BasicMessageHandler.GenerateRequest(uuid, item.OutAction, request); protalServer.SendMsg(session, rawRequest, string.Format("{0} {1}", action, "Request"), ""); } if (item.CreatedBy == "Destroyer") { if (_RequestType != null) { request = Activator.CreateInstance(_RequestType) as IRequest; uuid = session.queue.store(request); rawRequest = BasicMessageHandler.GenerateDestroyRequest(uuid, item.OutAction, item.OutRequest); protalServer.SendMsg(session, rawRequest, string.Format("{0} {1}", action, "Request"), ""); } else { rawRequest = BasicMessageHandler.GenerateDestroyRequest(Guid.NewGuid().ToString(), item.OutAction, item.OutRequest); protalServer.SendMsg(session, rawRequest, string.Format("{0} {1}", action, "Request"), ""); } } protalServer.AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest); dateTimeNow = DateTime.UtcNow; #region 更新資料表單一欄位 var _UpdatedItem = new ServerMessage() { Id = item.Id, UpdatedOn = dateTimeNow }; //db.Configuration.AutoDetectChangesEnabled = false;//自動呼叫DetectChanges()比對所有的entry集合的每一個屬性Properties的新舊值 //db.Configuration.ValidateOnSaveEnabled = false;// 因為Entity有些欄位必填,若不避開會有Validate錯誤 // var _UpdatedItem = db.ServerMessage.Where(x => x.Id == item.Id).FirstOrDefault(); using (var db = await maindbContextFactory.CreateDbContextAsync()) { db.ServerMessages.Attach(_UpdatedItem); _UpdatedItem.UpdatedOn = dateTimeNow; db.Entry(_UpdatedItem).Property(x => x.UpdatedOn).IsModified = true;// 可以直接使用這方式強制某欄位要更新,只是查詢集合耗效能而己 await db.SaveChangesAsync(); db.ChangeTracker.Clear(); } #endregion await Task.Delay(100); } } } } }