using EVCB_OCPP.Domain; using EVCB_OCPP.Domain.Models.MainDb; using EVCB_OCPP.Packet.Features; using EVCB_OCPP.Packet.Messages; using EVCB_OCPP.Packet.Messages.Core; using EVCB_OCPP.WSServer.Message; using EVCB_OCPP.WSServer.Service; using EVCB_OCPP.WSServer.Service.WsService; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.VisualBasic; using Newtonsoft.Json; using Quartz; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EVCB_OCPP.WSServer.Jobs; [DisallowConcurrentExecution] public class ServerMessageJob : IJob { public ServerMessageJob( ProtalServer protalServer, ConfirmWaitingMessageSerevice confirmWaitingMessageSerevice, //VendorIdUpdateService vendorIdReplaceService, IConfiguration configuration, IDbContextFactory maindbContextFactory, ILogger logger) { this.protalServer = protalServer; this.confirmWaitingMessageSerevice = confirmWaitingMessageSerevice; //this.vendorIdUpdateService = vendorIdReplaceService; this.maindbContextFactory = maindbContextFactory; this.logger = logger; } private readonly ProtalServer protalServer; private readonly ConfirmWaitingMessageSerevice confirmWaitingMessageSerevice; //private readonly VendorIdUpdateService vendorIdUpdateService; 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 Task ExecuteTrigger() { var clientDic = protalServer.GetClientDic(); confirmWaitingMessageSerevice.RemoveExpiredConfirmMessage(); ResendServerMessage(clientDic); return SendNewServerMessage(clientDic); } private async Task SendNewServerMessage(Dictionary clientDic) { BasicMessageHandler msgAnalyser = new BasicMessageHandler(); DateTime dateTimeNow = DateTime.UtcNow; DateTime startDt = dateTimeNow.AddSeconds(-30); DateTime dt = new DateTime(1991, 1, 1); DateTime currentTime = dateTimeNow; List commandList; List waitTasks = new List(); using (var db = await maindbContextFactory.CreateDbContextAsync()) { commandList = await db.ServerMessage.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)); } Dictionary> toSendWsClientDataMsgPair = commandList .GroupBy(x => x.ChargeBoxId) .Where(x => clientDic.ContainsKey(x.Key)) .ToDictionary(x => clientDic[x.Key], x => x.ToList()); await Parallel.ForEachAsync(toSendWsClientDataMsgPair, async (sendPair, token) => //{ }); //foreach (var charger_SN in cmdMachineList) { WsClientData session = sendPair.Key; string charger_SN = session.ChargeBoxId; string uuid = string.Empty; //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.ISOCPP20) { //continue; return; } string rawRequest = string.Empty; List cmdList = sendPair.Value; 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; if (action == Actions.DataTransfer) { ReplaceVID(session, action, request); } 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"), ""); } } var tmpTask = confirmWaitingMessageSerevice.Add(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest); waitTasks.Add(tmpTask); //protalServer.AddConfirmMessage(charger_SN, item.Id, item.SerialNo, item.OutAction, uuid, item.CreatedBy, rawRequest); await Task.Delay(100); } } ); await Task.WhenAll(waitTasks); } private void ResendServerMessage(Dictionary clientDic) { DateTime dateTimeNow = DateTime.UtcNow; List resendList = confirmWaitingMessageSerevice.GetPendingMessages(); foreach (var resendItem in resendList) { WsClientData session; if (clientDic.TryGetValue(resendItem.ChargePointSerialNumber, out session)) { if (dateTimeNow.Subtract(resendItem.SentOn).TotalSeconds > 1) { confirmWaitingMessageSerevice.SignalMessageSended(resendItem); protalServer.SendMsg(session, resendItem.SentMessage, string.Format("{0} {1}", resendItem.SentAction, "Request"), ""); } } } } private void ReplaceVID(WsClientData session, Actions action, IRequest request) { if (action != Actions.DataTransfer || request is not DataTransferRequest dataTransferRequest) { return; } string vid = session.ChargePointVendor; if (string.IsNullOrEmpty(vid)) { return; } dataTransferRequest.vendorId = vid; } }