Riorganizzaizone API

This commit is contained in:
Samuele Locatelli
2023-04-19 14:55:46 +02:00
parent 7b61d49767
commit a0f30600b4
4 changed files with 269 additions and 158 deletions
@@ -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
/// <summary>
/// Lunghezza coda in attesa
/// </summary>
@@ -43,63 +43,39 @@ namespace WebDoorCreator.API.Controllers
long numQueue = await QDataServ.NumRequestProcessing();
return numQueue;
}
#endif
#region Public Methods
/// <summary>
/// Invio elenco messaggi elaborazioni (se ho errori --&gt; messaggi oppure libero)
/// Lunghezza coda in fase di processing
/// </summary>
/// <param name="ProcMessageList"></param>
/// <returns></returns>
[HttpPost("PostProcessingMessage")]
public async Task<bool> PostProcessingMessage(Dictionary<string, string> ProcMessageList)
[HttpGet("ActLenght")]
public async Task<Dictionary<string, long>> ActLenght()
{
bool answ = false;
await Task.Delay(1);
Dictionary<string, long> answ = new Dictionary<string, long>();
var actPend = await QDataServ.NumRequestPending();
answ.Add("pending", actPend);
var actProc = await QDataServ.NumRequestProcessing();
answ.Add("processing", actProc);
return answ;
}
/// <summary>
/// Invio elenco risultati elaborazioni (modalità boolean di esecuzione corretta)
/// </summary>
/// <param name="ProcResultList"></param>
/// <param name="calcResults">Risultati elaborazioni in formato CalcResultDTO</param>
/// <returns></returns>
[HttpPost("PostProcessingResult")]
public async Task<bool> PostProcessingResult(Dictionary<string, bool> ProcResultList)
[HttpPost("SaveProcessingResult")]
public async Task<bool> SaveProcessingResult(List<CalcResultDTO> 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;
}
/// <summary>
/// Invio elenco risultati elaborazioni come elenco di SVG
/// </summary>
/// <param name="ProcSvgList"></param>
/// <returns></returns>
[HttpPost("PostProcessingSvg")]
public async Task<bool> PostProcessingSvg(Dictionary<string, string> ProcSvgList)
{
bool answ = false;
await Task.Delay(1);
bool answ = await QDataServ.SaveProcessingResult(calcResults);
return answ;
}
#if false
/// <summary>
/// Elenco richieste in stato pending
/// </summary>
@@ -111,24 +87,6 @@ namespace WebDoorCreator.API.Controllers
return actQueue;
}
/// <summary>
/// Elenco richieste raggruppate x stato
/// </summary>
/// <returns></returns>
[HttpGet("ShowQueue")]
public async Task<Dictionary<string,Dictionary<string, string>>> ShowQueue()
{
Dictionary<string, Dictionary<string, string>> answ = new Dictionary<string, Dictionary<string, string>>();
var actPend = await QDataServ.RequestPending();
answ.Add("pending", actPend);
var actProc = await QDataServ.RequestProcessing();
answ.Add("processing", actProc);
return answ;
}
/// <summary>
/// Elenco richeiste in stato processing
/// </summary>
@@ -139,6 +97,23 @@ namespace WebDoorCreator.API.Controllers
var actQueue = await QDataServ.RequestProcessing();
return actQueue;
}
#endif
/// <summary>
/// Elenco richieste raggruppate x stato
/// </summary>
/// <returns></returns>
[HttpGet("StatusList")]
public async Task<Dictionary<string, Dictionary<string, string>>> StatusList()
{
Dictionary<string, Dictionary<string, string>> answ = new Dictionary<string, Dictionary<string, string>>();
var actPend = await QDataServ.RequestPending();
answ.Add("pending", actPend);
var actProc = await QDataServ.RequestProcessing();
answ.Add("processing", actProc);
return answ;
}
/// <summary>
/// Chiede un numero massimo di items dalla coda NB:
+35
View File
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WebDoorCreator.Data.DTO
{
/// <summary>
/// Oggetto contenitore esiti calcolo
/// </summary>
public class CalcResultDTO
{
/// <summary>
/// UID (DoorId.Version)
/// </summary>
public string DoorIdVers { get; set; } = "";
/// <summary>
/// Validated = true / error found = false
/// </summary>
public bool Validated { get; set; } = true;
/// <summary>
/// Error message (optional)
/// </summary>
public string ErrorMsg { get; set; } = "";
/// <summary>
/// SVG generated
/// </summary>
public string SvgGen { get; set; } = "";
/// <summary>
/// Articat path (ex 3d zip/pack)
/// </summary>
public string artifactPath { get; set; } = "";
}
}
+197 -96
View File
@@ -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();
}
/// <summary>
/// Invio richiesta di calcolo per la porta indicata, dato il suo DDF
/// </summary>
/// <param name="DoorId"></param>
/// <param name="FullDDF">Contenuto completo del DDF</param>
/// <returns>indice/versione del calcolo DDF</returns>
public async Task<int> 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;
}
/// <summary>
/// Restitusice l'SVG della porta in oggetto
/// </summary>
@@ -198,6 +121,46 @@ namespace WebDoorCreator.Data.Services
return numReq;
}
/// <summary>
/// Remove for single hash record
/// </summary>
/// <param name="currKey">Chiave redis della Hashlist</param>
/// <param name="chiave">Chiave nella HashList</param>
/// <returns>Esito rimozione</returns>
public async Task<bool> 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;
}
/// <summary>
/// Remove for single hash record
/// </summary>
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<bool> RequestDoneRemove(string doorId)
{
RedisKey currKey = new RedisKey(Constants.CALC_REQ_DONE);
bool fatto = await RedHashRemove(currKey, doorId);
return fatto;
}
/// <summary>
/// Upsert for single hash record
/// </summary>
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<long> RequestDoneUpsert(string doorId, string vers)
{
RedisKey currKey = new RedisKey(Constants.CALC_REQ_DONE);
long numReq = await RedHashUpsert(currKey, doorId, vers);
return numReq;
}
/// <summary>
/// Get Queue request pending
/// </summary>
@@ -226,6 +189,27 @@ namespace WebDoorCreator.Data.Services
return dictResult;
}
/// <summary>
/// Remove for single hash record
/// </summary>
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<bool> RequestPendingRemove(string doorId)
{
RedisKey currKey = new RedisKey(Constants.CALC_REQ_PEND);
bool fatto = await RedHashRemove(currKey, doorId);
return fatto;
}
/// <summary>
/// Upsert for single hash record
/// </summary>
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<long> RequestPendingUpsert(string doorId, string vers)
{
RedisKey currKey = new RedisKey(Constants.CALC_REQ_PEND);
long numReq = await RedHashUpsert(currKey, doorId, vers);
return numReq;
}
/// <summary>
/// Get Queue request processing
@@ -254,23 +238,99 @@ namespace WebDoorCreator.Data.Services
Log.Debug($"RequestProcessing | {source} in: {ts.TotalMilliseconds} ms");
return dictResult;
}
/// <summary>
/// Remove for single hash record
/// </summary>
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<bool> RequestProcessingRemove(string doorId)
{
RedisKey currKey = new RedisKey(Constants.CALC_REQ_PROC);
bool fatto = await RedHashRemove(currKey, doorId);
return fatto;
}
/// <summary>
/// Upsert for single hash record
/// </summary>
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<long> 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;
}
/// <summary>
/// Invio richiesta di calcolo per la porta indicata, dato il suo DDF
/// </summary>
/// <param name="DoorId"></param>
/// <param name="FullDDF">Contenuto completo del DDF</param>
/// <returns>indice/versione del calcolo DDF</returns>
public async Task<int> 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;
}
/// <summary>
@@ -279,7 +339,7 @@ namespace WebDoorCreator.Data.Services
/// <returns>Dictionary of DoorId, saveVersNumb</returns>
public async Task<Dictionary<string, string>> TakeProcessingItems(int numItems)
{
string source = "REDIS";
int maxTake = 10;
long numReq = 0;
Dictionary<string, string> dictResult = new Dictionary<string, string>();
// 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;
}
/// <summary>
/// Invio elenco risultati elaborazioni (modalità boolean di esecuzione corretta)
/// </summary>
/// <param name="calcResults">Risultati elaborazioni in formato CalcResultDTO</param>
/// <returns></returns>
public async Task<bool> SaveProcessingResult(List<CalcResultDTO> 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;
}
/// <summary>
/// Effettua upsert in HasList redis
/// </summary>
/// <param name="currKey">Chiave redis della Hashlist</param>
/// <param name="chiave">Chiave nella HashList</param>
/// <param name="valore">Valore da salvare</param>
/// <returns>Num record nella HashList</returns>
protected async Task<long> 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;
}
/// <summary>
/// Salvataggio chiave in redis
/// </summary>
@@ -423,6 +524,14 @@ namespace WebDoorCreator.Data.Services
#region Private Properties
/// <summary>
/// Durata cache di 24h
/// </summary>
private TimeSpan DayLongCache
{
get => TimeSpan.FromHours(24);
}
/// <summary>
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
/// </summary>
@@ -447,14 +556,6 @@ namespace WebDoorCreator.Data.Services
get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000);
}
/// <summary>
/// Durata cache di 24h
/// </summary>
private TimeSpan DayLongCache
{
get => TimeSpan.FromHours(24);
}
#endregion Private Properties
#region Private Methods
+1 -1
View File
@@ -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: