diff --git a/WebDoorCreator.API/Controllers/QueueController.cs b/WebDoorCreator.API/Controllers/QueueController.cs index 3d52462..5359197 100644 --- a/WebDoorCreator.API/Controllers/QueueController.cs +++ b/WebDoorCreator.API/Controllers/QueueController.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Mvc; using NLog; +using WebDoorCreator.Data.DTO; using WebDoorCreator.Data.Services; namespace WebDoorCreator.API.Controllers @@ -20,8 +21,7 @@ namespace WebDoorCreator.API.Controllers #endregion Public Constructors - #region Public Methods - +#if false /// /// Lunghezza coda in attesa /// @@ -43,63 +43,39 @@ namespace WebDoorCreator.API.Controllers long numQueue = await QDataServ.NumRequestProcessing(); return numQueue; } +#endif + + #region Public Methods /// - /// Invio elenco messaggi elaborazioni (se ho errori --> messaggi oppure libero) + /// Lunghezza coda in fase di processing /// - /// /// - [HttpPost("PostProcessingMessage")] - public async Task PostProcessingMessage(Dictionary ProcMessageList) + [HttpGet("ActLenght")] + public async Task> ActLenght() { - bool answ = false; - await Task.Delay(1); + Dictionary answ = new Dictionary(); + var actPend = await QDataServ.NumRequestPending(); + answ.Add("pending", actPend); + + var actProc = await QDataServ.NumRequestProcessing(); + answ.Add("processing", actProc); return answ; } /// /// Invio elenco risultati elaborazioni (modalità boolean di esecuzione corretta) /// - /// + /// Risultati elaborazioni in formato CalcResultDTO /// - [HttpPost("PostProcessingResult")] - public async Task PostProcessingResult(Dictionary ProcResultList) + [HttpPost("SaveProcessingResult")] + public async Task SaveProcessingResult(List calcResults) { - bool answ = false; - //VC19Check answ = new VC19Check() - //{ - // Result = "KO" - //}; - //var result = await _DataService.InsertCheck(DecodedData, "10.74.82.255"); - //if (result) - //{ - // answ = new VC19Check - // { - // DTRecord = DateTime.Now, - // CheckRecorded = true, - // TimbrRecorder = true, - // Result = $"OK, Check Recorded for {DecodedData.nam.fn} {DecodedData.nam.gn} {DecodedData.dob:yyyy.MM.dd}" - // }; - //} - //else - //{ } - await Task.Delay(1); - return answ; - } - - /// - /// Invio elenco risultati elaborazioni come elenco di SVG - /// - /// - /// - [HttpPost("PostProcessingSvg")] - public async Task PostProcessingSvg(Dictionary ProcSvgList) - { - bool answ = false; - await Task.Delay(1); + bool answ = await QDataServ.SaveProcessingResult(calcResults); return answ; } +#if false /// /// Elenco richieste in stato pending /// @@ -111,24 +87,6 @@ namespace WebDoorCreator.API.Controllers return actQueue; } - - /// - /// Elenco richieste raggruppate x stato - /// - /// - [HttpGet("ShowQueue")] - public async Task>> ShowQueue() - { - Dictionary> answ = new Dictionary>(); - var actPend = await QDataServ.RequestPending(); - answ.Add("pending", actPend); - - var actProc = await QDataServ.RequestProcessing(); - answ.Add("processing", actProc); - return answ; - } - - /// /// Elenco richeiste in stato processing /// @@ -139,6 +97,23 @@ namespace WebDoorCreator.API.Controllers var actQueue = await QDataServ.RequestProcessing(); return actQueue; } +#endif + + /// + /// Elenco richieste raggruppate x stato + /// + /// + [HttpGet("StatusList")] + public async Task>> StatusList() + { + Dictionary> answ = new Dictionary>(); + var actPend = await QDataServ.RequestPending(); + answ.Add("pending", actPend); + + var actProc = await QDataServ.RequestProcessing(); + answ.Add("processing", actProc); + return answ; + } /// /// Chiede un numero massimo di items dalla coda NB: diff --git a/WebDoorCreator.Data/DTO/CalcResultDTO.cs b/WebDoorCreator.Data/DTO/CalcResultDTO.cs new file mode 100644 index 0000000..6679dc8 --- /dev/null +++ b/WebDoorCreator.Data/DTO/CalcResultDTO.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace WebDoorCreator.Data.DTO +{ + /// + /// Oggetto contenitore esiti calcolo + /// + public class CalcResultDTO + { + /// + /// UID (DoorId.Version) + /// + public string DoorIdVers { get; set; } = ""; + /// + /// Validated = true / error found = false + /// + public bool Validated { get; set; } = true; + /// + /// Error message (optional) + /// + public string ErrorMsg { get; set; } = ""; + /// + /// SVG generated + /// + public string SvgGen { get; set; } = ""; + /// + /// Articat path (ex 3d zip/pack) + /// + public string artifactPath { get; set; } = ""; + } +} diff --git a/WebDoorCreator.Data/Services/QueueDataService.cs b/WebDoorCreator.Data/Services/QueueDataService.cs index 374c623..88916f6 100644 --- a/WebDoorCreator.Data/Services/QueueDataService.cs +++ b/WebDoorCreator.Data/Services/QueueDataService.cs @@ -2,11 +2,10 @@ using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using NLog; -using Org.BouncyCastle.Asn1.Pkcs; using StackExchange.Redis; using System.Diagnostics; using WebDoorCreator.Core; -using WebDoorCreator.Data; +using WebDoorCreator.Data.DTO; namespace WebDoorCreator.Data.Services { @@ -64,82 +63,6 @@ namespace WebDoorCreator.Data.Services redisConn.Dispose(); } - /// - /// Invio richiesta di calcolo per la porta indicata, dato il suo DDF - /// - /// - /// Contenuto completo del DDF - /// indice/versione del calcolo DDF - public async Task SendCalcReq(int DoorId, string FullDDF) - { - int currVers = 1; - string sDoorId = $"{DoorId}"; - string sCurrVers = ""; - Stopwatch stopWatch = new Stopwatch(); - stopWatch.Start(); - - // per prima cosa controllo se ho GIA' in coda qualcosa come richeiste - long numPending = await NumRequestPending(); - - // se coda non vuota: cerco la DoorId corrente, se c'è sovrascrivo versione altrimenti - if (numPending != 0) - { - var currPending = await RequestPending(); - if (currPending != null) - { - if (currPending.ContainsKey(sDoorId)) - { - sCurrVers = currPending[sDoorId]; - int.TryParse(sCurrVers, out currVers); - currVers++; - } - } - } - sCurrVers = $"{currVers}"; - // inserisco in coda - numPending = await RequestProcessingUpsert(sDoorId, sCurrVers); - - // salvo nell'archivio REDIS delle porte il DDF corrente (key=doorId.versNumb), potrebbe - // venire buono anche x eventuale UNDO... - RedisKey currDdfKey = new RedisKey($"{Constants.CALC_REQ_DDF_CACHE}:{sDoorId}:{sCurrVers}"); - await redisDb.StringSetAsync(currDdfKey, FullDDF, DayLongCache); - - // invio sul canale dei messaggi il numero di items in coda attuali x chiedere esecuzione... - numPending = await NumRequestPending(); - bool answ = CalcReqPipe.saveAndSendMessage(Constants.LAST_CALC_REQ_KEY, $"{numPending}"); - - - stopWatch.Stop(); - TimeSpan ts = stopWatch.Elapsed; - Log.Debug($"SendCalcReq | DoorId: {DoorId} enqueued in: {ts.TotalMilliseconds} ms"); - - - // FIXME TODO!!!! levare quando ci sarà il vero sw in esecuzione... - - - // simulazione ritorno dati... - string fileName = Path.Combine("temp", $"Logo{idxSim:00}.svg"); - if (File.Exists(fileName)) - { - // update indici - idxSim++; - idxSim = idxSim % 4; - // leggo file - string svgCont = File.ReadAllText(fileName); - // salvo in area REDIS - RedisKey currSvgKey = new RedisKey($"{Constants.CALC_REQ_SVG_CACHE}:{sDoorId}:{sCurrVers}"); - await redisDb.StringSetAsync(currSvgKey, svgCont, DayLongCache); - - } - // simulo attesa segnalazione messaggio porta calcolata - await Task.Delay(300); - string retMess = $"{sDoorId}:{sCurrVers}"; - // invio il FINTO messaggio di ritorno... - CalcDonePipe.saveAndSendMessage(Constants.LAST_CALC_DONE_KEY, retMess); - - return currVers; - } - /// /// Restitusice l'SVG della porta in oggetto /// @@ -198,6 +121,46 @@ namespace WebDoorCreator.Data.Services return numReq; } + /// + /// Remove for single hash record + /// + /// Chiave redis della Hashlist + /// Chiave nella HashList + /// Esito rimozione + public async Task RedHashRemove(RedisKey currKey, string chiave) + { + bool fatto = false; + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + fatto = await redisDb.HashDeleteAsync(currKey, chiave); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Trace($"RedHashRemove | {currKey} | in: {ts.TotalMilliseconds} ms"); + return fatto; + } + + /// + /// Remove for single hash record + /// + /// Dictionary of DoorId, saveVersNumb + public async Task RequestDoneRemove(string doorId) + { + RedisKey currKey = new RedisKey(Constants.CALC_REQ_DONE); + bool fatto = await RedHashRemove(currKey, doorId); + return fatto; + } + + /// + /// Upsert for single hash record + /// + /// Dictionary of DoorId, saveVersNumb + public async Task RequestDoneUpsert(string doorId, string vers) + { + RedisKey currKey = new RedisKey(Constants.CALC_REQ_DONE); + long numReq = await RedHashUpsert(currKey, doorId, vers); + return numReq; + } + /// /// Get Queue request pending /// @@ -226,6 +189,27 @@ namespace WebDoorCreator.Data.Services return dictResult; } + /// + /// Remove for single hash record + /// + /// Dictionary of DoorId, saveVersNumb + public async Task RequestPendingRemove(string doorId) + { + RedisKey currKey = new RedisKey(Constants.CALC_REQ_PEND); + bool fatto = await RedHashRemove(currKey, doorId); + return fatto; + } + + /// + /// Upsert for single hash record + /// + /// Dictionary of DoorId, saveVersNumb + public async Task RequestPendingUpsert(string doorId, string vers) + { + RedisKey currKey = new RedisKey(Constants.CALC_REQ_PEND); + long numReq = await RedHashUpsert(currKey, doorId, vers); + return numReq; + } /// /// Get Queue request processing @@ -254,23 +238,99 @@ namespace WebDoorCreator.Data.Services Log.Debug($"RequestProcessing | {source} in: {ts.TotalMilliseconds} ms"); return dictResult; } + + /// + /// Remove for single hash record + /// + /// Dictionary of DoorId, saveVersNumb + public async Task RequestProcessingRemove(string doorId) + { + RedisKey currKey = new RedisKey(Constants.CALC_REQ_PROC); + bool fatto = await RedHashRemove(currKey, doorId); + return fatto; + } + /// /// Upsert for single hash record /// /// Dictionary of DoorId, saveVersNumb public async Task RequestProcessingUpsert(string doorId, string vers) { - long numReq = 0; - // cerco da cache - RedisKey currKey = new RedisKey(Constants.CALC_REQ_PEND); + RedisKey currKey = new RedisKey(Constants.CALC_REQ_PROC); + long numReq = await RedHashUpsert(currKey, doorId, vers); + return numReq; + } + + /// + /// Invio richiesta di calcolo per la porta indicata, dato il suo DDF + /// + /// + /// Contenuto completo del DDF + /// indice/versione del calcolo DDF + public async Task SendCalcReq(int DoorId, string FullDDF) + { + int currVers = 1; + string sDoorId = $"{DoorId}"; + string sCurrVers = ""; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); - await redisDb.HashSetAsync(currKey, doorId, vers); - numReq = await redisDb.HashLengthAsync(currKey); + + // per prima cosa controllo se ho GIA' in coda qualcosa come richeiste + long numPending = await NumRequestPending(); + + // se coda non vuota: cerco la DoorId corrente, se c'è sovrascrivo versione altrimenti + if (numPending != 0) + { + var currPending = await RequestPending(); + if (currPending != null) + { + if (currPending.ContainsKey(sDoorId)) + { + sCurrVers = currPending[sDoorId]; + int.TryParse(sCurrVers, out currVers); + currVers++; + } + } + } + sCurrVers = $"{currVers}"; + // inserisco in coda + numPending = await RequestPendingUpsert(sDoorId, sCurrVers); + + // salvo nell'archivio REDIS delle porte il DDF corrente (key=doorId.versNumb), potrebbe + // venire buono anche x eventuale UNDO... + RedisKey currDdfKey = new RedisKey($"{Constants.CALC_REQ_DDF_CACHE}:{sDoorId}:{sCurrVers}"); + await redisDb.StringSetAsync(currDdfKey, FullDDF, DayLongCache); + + // invio sul canale dei messaggi il numero di items in coda attuali x chiedere esecuzione... + numPending = await NumRequestPending(); + bool answ = CalcReqPipe.saveAndSendMessage(Constants.LAST_CALC_REQ_KEY, $"{numPending}"); + stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; - Log.Debug($"RequestProcessingUpsert | in: {ts.TotalMilliseconds} ms"); - return numReq; + Log.Debug($"SendCalcReq | DoorId: {DoorId} enqueued in: {ts.TotalMilliseconds} ms"); + + // FIXME TODO!!!! levare quando ci sarà il vero sw in esecuzione... + + // simulazione ritorno dati... + string fileName = Path.Combine("temp", $"Logo{idxSim:00}.svg"); + if (File.Exists(fileName)) + { + // update indici + idxSim++; + idxSim = idxSim % 4; + // leggo file + string svgCont = File.ReadAllText(fileName); + // salvo in area REDIS + RedisKey currSvgKey = new RedisKey($"{Constants.CALC_REQ_SVG_CACHE}:{sDoorId}:{sCurrVers}"); + await redisDb.StringSetAsync(currSvgKey, svgCont, DayLongCache); + } + // simulo attesa segnalazione messaggio porta calcolata + await Task.Delay(300); + string retMess = $"{sDoorId}:{sCurrVers}"; + // invio il FINTO messaggio di ritorno... + CalcDonePipe.saveAndSendMessage(Constants.LAST_CALC_DONE_KEY, retMess); + + return currVers; } /// @@ -279,7 +339,7 @@ namespace WebDoorCreator.Data.Services /// Dictionary of DoorId, saveVersNumb public async Task> TakeProcessingItems(int numItems) { - string source = "REDIS"; + int maxTake = 10; long numReq = 0; Dictionary dictResult = new Dictionary(); // cerco da cache @@ -290,20 +350,41 @@ namespace WebDoorCreator.Data.Services if (numReq > 0) { var rawData = await redisDb.HashGetAllAsync(currKey); + // sposto fino a concorrenza... foreach (var item in rawData) { + maxTake--; dictResult.Add($"{item.Name}", $"{item.Value}"); + // sposto tra le 2 code + await RequestProcessingUpsert(item.Name, item.Value); + await RequestPendingRemove(item.Name); + if (maxTake <= 0) + { + break; + } } } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; - Log.Debug($"TakeProcessingItems | {source} in: {ts.TotalMilliseconds} ms"); + Log.Debug($"TakeProcessingItems | REDIS in: {ts.TotalMilliseconds} ms"); return dictResult; } + /// + /// Invio elenco risultati elaborazioni (modalità boolean di esecuzione corretta) + /// + /// Risultati elaborazioni in formato CalcResultDTO + /// + public async Task SaveProcessingResult(List calcResults) + { + bool answ = false; + await Task.Delay(1); + return answ; + } + #endregion Public Methods - #region Protected Fields + #region Protected Fields protected const string rKeyCalcOreFase = "Check:OreFasi"; @@ -340,6 +421,26 @@ namespace WebDoorCreator.Data.Services return answ; } + /// + /// Effettua upsert in HasList redis + /// + /// Chiave redis della Hashlist + /// Chiave nella HashList + /// Valore da salvare + /// Num record nella HashList + protected async Task RedHashUpsert(RedisKey currKey, string chiave, string valore) + { + long numReq = 0; + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); + await redisDb.HashSetAsync(currKey, chiave, valore); + numReq = await redisDb.HashLengthAsync(currKey); + stopWatch.Stop(); + TimeSpan ts = stopWatch.Elapsed; + Log.Trace($"RedHashUpsert | {currKey} | in: {ts.TotalMilliseconds} ms"); + return numReq; + } + /// /// Salvataggio chiave in redis /// @@ -423,6 +524,14 @@ namespace WebDoorCreator.Data.Services #region Private Properties + /// + /// Durata cache di 24h + /// + private TimeSpan DayLongCache + { + get => TimeSpan.FromHours(24); + } + /// /// Durata cache lunga (+ perturbazione percentuale +/-10%) /// @@ -447,14 +556,6 @@ namespace WebDoorCreator.Data.Services get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000); } - /// - /// Durata cache di 24h - /// - private TimeSpan DayLongCache - { - get => TimeSpan.FromHours(24); - } - #endregion Private Properties #region Private Methods diff --git a/WebDoorCreator.UI/temp/Conf.yaml b/WebDoorCreator.UI/temp/Conf.yaml index 861a811..1a0ecf8 100644 --- a/WebDoorCreator.UI/temp/Conf.yaml +++ b/WebDoorCreator.UI/temp/Conf.yaml @@ -3,7 +3,7 @@ #Door1 code: 0015943 -date: 2023-04-19T13:38:20.6194164+02:00 +date: 2023-04-19T14:05:03.5064525+02:00 material: wood measures: millimiters order: