using Core; using Core.DTO; using LiMan.DB.DBModels; using LiMan.DB.DTO; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using NLog; using Org.BouncyCastle.Asn1.Pkcs; using StackExchange.Redis; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Runtime; using System.Text; using System.Threading.Tasks; using static Core.Enum; namespace LiMan.DB.Services { /// /// Classe common x gestione servizi sui dati (DB + REDIS) x UI ed API /// public class CommonDataServices : IDisposable { #region Public Constructors /// /// Costruttore principale /// /// /// /// /// /// public CommonDataServices(IConfiguration configuration, IConnectionMultiplexer redisConnMult, IEmailSender emailSender) { _configuration = configuration; // Conf cache redisConn = redisConnMult; redisDb = this.redisConn.GetDatabase(); // json serializer... FIX errore loop circolare https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/ JSSettings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }; // conf messagepipe: setup canali pub/sub EnrollMessPipe = new MessagePipe(redisConn, Const.ENRL_MSG_PIPE); UpdActMessPipe = new MessagePipe(redisConn, Const.TASK_MSG_PIPE); TaskMessPipe = new MessagePipe(redisConn, Const.UPDT_MSG_PIPE); _emailSender = emailSender; // conf DB string connStrDB = _configuration.GetConnectionString("LiMan.DB"); if (string.IsNullOrEmpty(connStrDB)) { Log.Error("Empty ConnString for LiMan.DB!"); } else { dbController = new LiMan.DB.Controllers.DbController(configuration); Log.Info("DbController for LiMan.DB OK"); } } #endregion Public Constructors #region Public Properties /// /// Wrapper x invio/ricezione messaggi sul canale dedicato agli eventi enroll /// public MessagePipe EnrollMessPipe { get; set; } = null!; /// /// Wrapper x invio/ricezione messaggi sul canale dedicato a generico update info dai vari EgwACC /// public MessagePipe UpdActMessPipe { get; set; } = null!; /// /// Wrapper x invio/ricezione messaggi sul canale dedicato agli eventi Task /// public MessagePipe TaskMessPipe { get; set; } = null!; #endregion Public Properties #region Public Methods /// /// Elenco licenze dato cliente /// /// Codice Installaizone /Cliente /// Codice Applicazione /// Indica se nascondere i dati sensibili /// public async Task> AppDtoSearch(string CodInst, string CodApp, bool HideData) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetApplicativiFilt(true, CodApp, CodInst, HideData); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ApplicativiByCliente: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task ApplicHasChild(string CodApp) { string source = "DB"; bool dbResult = false; try { string currKey = $"{Const.rKeyConfig}:Next:Applicazioni:HasChild"; Stopwatch sw = new Stopwatch(); sw.Start(); string rawData = redisHashKeyGet(currKey, CodApp); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; dbResult = JsonConvert.DeserializeObject(rawData); } else { dbResult = dbController.ApplicazioniHasChild(CodApp); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); redisHashKeySet(currKey, CodApp, rawData, UltraLongCache.Minutes); } sw.Stop(); Log.Debug($"ApplicHasChild | {source} in: {sw.Elapsed.TotalMilliseconds:N2} ms"); } catch (Exception exc) { Log.Error($"Error during ApplicHasChild:{Environment.NewLine}{exc}"); } await Task.Delay(0); return dbResult; } /// /// Elimina il record indicato (se non ci sono record correlati...) /// /// /// public async Task ApplicNextDelete(ApplicativoModel currItem) { bool done = false; try { // controllo NON ci siano record figli... bool hasCHild = dbController.ApplicazioniHasChild(currItem.CodApp); if (!hasCHild) { done = dbController.ApplicazioniNextDelete(currItem); await FlushRedisCache(); } } catch (Exception exc) { Log.Error($"Eccezione in ApplicNextDelete:{Environment.NewLine}{exc}"); } return done; } public async Task> ApplicNextGetAll(bool forceDb) { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Next:Applicazioni:List"; Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData) && !forceDb) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.GetApplicazioni(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); Log.Debug($"ApplicNextGetAll | {source} in: {sw.Elapsed.TotalMilliseconds:N2} ms"); } catch (Exception exc) { Log.Error($"Error during ApplicNextGetAll:{Environment.NewLine}{exc}"); } return dbResult; } public async Task ApplicNextUpdate(ApplicativoModel currItem) { bool done = false; try { done = dbController.ApplicazioniNextUpdate(currItem); await FlushRedisCache(); } catch (Exception exc) { Log.Error($"Eccezione in ApplicNextUpdate:{Environment.NewLine}{exc}"); } return done; } /// /// Elimina record attivazione /// /// /// public async Task AttivazioneDelete(int idxSubLic) { bool fatto = dbController.AttivazioniDelete(idxSubLic); await Task.Delay(1); return fatto; } /// /// Elenco licenze dato cliente /// /// Licenza MASTER /// Codice Impiego licenza /// Indica se nascondere i dati sensibili /// public async Task AttivazioneSearch(string Chiave, string CodImpiego, bool HideData) { AttivazioneDTO dbResult = new AttivazioneDTO(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetAttivazione(Chiave, CodImpiego, HideData); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniSearch: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Effettua sblocco di una licenza impostando data veto a oggi /// /// /// public async Task AttivazioneUnlock(int idxSubLic) { bool fatto = dbController.AttivazioniUnlock(idxSubLic); await Task.Delay(1); return fatto; } /// /// Elenco Attivaizoni da ID Licenza master /// /// Idx Licenza Master /// Indica se nascondere i dati sensibili /// public async Task> AttivazioniByLic(int idxLic, bool hideData) { List dbResult = new List(); string cacheKey = $"{rKeyAttivByLic}:{hideData}:{idxLic}"; trackCache(cacheKey); string rawData = await getRSV(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetAttivazioniByLic(idxLic, hideData); rawData = JsonConvert.SerializeObject(dbResult); await setRSV(cacheKey, rawData, redCacheTtlStd); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniByLic: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } /// /// Elenco Attivaizoni da valore Licenza master /// /// Licenza Master /// Indica se nascondere i dati sensibili /// public async Task> AttivazioniByMasterKey(string MasterKey, bool HideData) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); LicenzaModel licenza = await LicenzaByMasterKey(MasterKey); if (licenza != null) { dbResult = await AttivazioniByLic(licenza.IdxLic, HideData); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniByMasterKey: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Elimina un Attivaizone /// /// Licenza Master /// Elenco delle attivazioni da eliminare /// public async Task AttivazioniDelete(string MasterKey, Dictionary ParamDict) { bool answ = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); LicenzaModel licenza = await LicenzaByMasterKey(MasterKey); if (licenza != null) { answ = dbController.AttivazioniDelete(ParamDict, MasterKey); await FlushRedisCache(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniDelete: {ts.TotalMilliseconds} ms"); return await Task.FromResult(answ); } /// /// Lista attivazioni dati cod identificativi CodImp e AppKey /// /// /// /// public async Task> AttivazioniGetAppImp(string AppKey, string CodImp) { Stopwatch stopWatch = new Stopwatch(); List dbResult = new List(); stopWatch.Start(); dbResult = dbController.AttivazioniGetAppImp(AppKey, CodImp); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniGetAppImp: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera attivazioni data licenza /// /// /// public async Task> AttivazioniGetByLic(int IdxLic) { Stopwatch sw = new Stopwatch(); List dbResult = new List(); sw.Start(); dbResult = dbController.AttivazioniGetByLic(IdxLic); sw.Stop(); Log.Trace($"Effettuata lettura da DB per AttivazioniGetByLic: {sw.Elapsed.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Elimina attivaizoni con veto scaduto /// /// Licenza Master /// public async Task AttivazioniResetAvail(string MasterKey) { bool answ = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); LicenzaModel licenza = await LicenzaByMasterKey(MasterKey); if (licenza != null) { answ = dbController.AttivazioniResetAvail(MasterKey); await FlushRedisCache(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AttivazioniResetAvail: {ts.TotalMilliseconds} ms"); return await Task.FromResult(answ); } /// /// Effettua registrazione (se possibile) delle licenze indicate dall'elenco codici di /// impiego indicati /// /// Codice Licenza Master /// Elenco codici impiego (key) + valori in formato dizionari /// Numero giorni x scadenza veto modifica /// Tipo di licenza da registrare /// /// public async Task AttivazioniTryAdd(string MasterKey, Dictionary ParamDict, int DayVeto, TipoLicenza TipoLic) { bool taskDone = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); taskDone = dbController.AttivazioniTryAdd(MasterKey, ParamDict, DayVeto, TipoLic); await FlushRedisCache(); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata scrittura + rilettura da DB per AttivazioniTryAdd: {ts.TotalMilliseconds} ms"); return await Task.FromResult(taskDone); } /// /// Effettua update (se possibile) delle licenze indicate dall'elenco codici di impiego indicati /// /// Codice Licenza Master /// Elenco codici impiego (key) + valori in formato dizionari /// /// public async Task AttivazioniTryRefresh(string MasterKey, Dictionary ParamDict) { bool taskDone = false; Stopwatch sw = new Stopwatch(); sw.Start(); taskDone = dbController.AttivazioniTryRefresh(MasterKey, ParamDict); await FlushRedisCache(); sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata scrittura + rilettura da DB per AttivazioniTryRefresh: {ts.TotalMilliseconds} ms"); return await Task.FromResult(taskDone); } /// /// Recupera elenco Claim dato UserID /// /// /// public async Task> AuthClaimByUserID(int userID) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:Claims:UID:{userID}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.AuthClaimByUserID(userID); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, LongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthClaimByUserID | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthClaimByUserID:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Recupera elenco Claim dato UserName /// /// /// public async Task> AuthClaimByUserName(string userName) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:Claims:UName:{userName}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.AuthClaimByUserName(userName); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthClaimByUserName | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthClaimByUserName:{Environment.NewLine}{exc}"); } //return await Task.FromResult(dbResult); return dbResult; } /// /// Rimozione del Claim (Role Utente) /// /// /// public async Task AuthClaimRemove(AuthClaimModel newRec) { bool fatto = dbController.AuthClaimRemove(newRec); await FlushRedisCache(); return fatto; } /// /// Upsesrt del Claim di auth utente /// /// /// public async Task AuthClaimUpsert(AuthClaimModel newRec) { bool fatto = dbController.AuthClaimUpsert(newRec); await FlushRedisCache(); return fatto; } /// /// Rimozione dei roles x utente /// /// /// public async Task AuthRoleResetUser(int UserId) { bool fatto = dbController.AuthRoleResetUser(UserId); await FlushRedisCache(); return fatto; } /// /// Recupera elenco Roles (completo) /// /// public async Task> AuthRolesGetAll() { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:Roles"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.AuthRolesGetAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthRolesGetAll | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthRolesGetAll:{Environment.NewLine}{exc}"); } //return await Task.FromResult(dbResult); return dbResult; } /// /// Upsert del ROLE /// /// /// public async Task AuthRoleUpsert(AuthRoleModel newRec) { bool fatto = dbController.AuthRoleUpsert(newRec); await FlushRedisCache(); return fatto; } /// /// Recupera elenco Utenti (tutti) /// /// public async Task> AuthUserAll() { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:UsersList"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.AuthUserAll(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthUserAll | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthUserAll:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Recupera elenco Utenti UserName (idealmente 1...) /// /// /// public async Task> AuthUserGetFilt(string userName) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Auth:User:{userName}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.AuthUserGetFilt(userName); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"AuthUserGetFilt | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during AuthUserGetFilt:{Environment.NewLine}{exc}"); } //return await Task.FromResult(dbResult); return dbResult; } /// /// Upsert AuthUser /// /// /// public async Task AuthUserUpsert(AuthUserModel newRec) { bool fatto = dbController.AuthUserUpsert(newRec); await FlushRedisCache(); return fatto; } public virtual void Dispose() { // Clear database controller dbController.Dispose(); } /// /// Elimino una richiesta enroll (anche se già approvata...) /// /// ID record public async Task EnrollReqDelete(int idReq) { bool fatto = false; // inserimento! Stopwatch sw = new Stopwatch(); sw.Start(); fatto = dbController.EnrollReqDelete(idReq); // svuota eventuale cache redis... await FlushRedisCachePattern("Enroll"); await FlushRedisCachePattern("InstVerSta"); sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata EnrollReqDelete: {ts.TotalMilliseconds} ms"); // invio string in messagepipe x forzare refresh... EnrollMessPipe.sendMessage("NewEnrollReq"); return fatto; } /// /// Elenco richeiste enroll attive al momento /// /// public async Task> EnrollReqGetActive() { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Enroll:ActiveList"; Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.EnrollReqGetActive(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, LongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Debug($"EnrollReqGetActive | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during EnrollReqGetActive:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Recupera una richiesta dato suo ID x verificare approvazione e dati associati... /// /// ID record public async Task EnrollReqGetById(int idReq) { string source = "DB"; EnrollRequestModel dbResult = new EnrollRequestModel() { IdReq = idReq }; try { string currKey = $"{Const.rKeyConfig}:Enroll:ById:{idReq}"; Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject(rawData); if (tempResult == null) { dbResult = new EnrollRequestModel() { IdReq = idReq }; } else { dbResult = tempResult; } } else { dbResult = dbController.EnrollReqGetById(idReq); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, FastCache); } if (dbResult == null) { dbResult = new EnrollRequestModel() { IdReq = idReq }; } sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Debug($"EnrollReqGetById | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during EnrollReqGetById:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Elenco richeiste enroll attive al momento /// /// public async Task> EnrollReqGetFilt(bool onlyActive, DateTime dtFrom, DateTime dtTo) { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Enroll:ActiveList"; if (!onlyActive) { currKey = $"{Const.rKeyConfig}:Enroll:Sel:{dtFrom:yyMMdd}_{dtTo:yyMMdd}"; } Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { if (onlyActive) { dbResult = dbController.EnrollReqGetActive(); } else { dbResult = dbController.EnrollReqGetFilt(dtFrom, dtTo); } rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Debug($"EnrollReqGetActive | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during EnrollReqGetActive:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Elimino eventuali richieste non approvate e scadute /// public async Task EnrollReqPurgeInvalid() { var reqPurged = dbController.EnrollReqPurgeInvalid(); // svuota eventuale cache redis... await FlushRedisCachePattern("Enroll"); await FlushRedisCachePattern("InstVerSta"); // invio string in messagepipe x forzare refresh... EnrollMessPipe.sendMessage("NewEnrollReq"); return reqPurged; } /// /// Upsert record richiesta enroll /// /// /// public async Task EnrollReqUpsert(EnrollRequestModel newRec) { int recId = 0; // inserimento! Stopwatch sw = new Stopwatch(); sw.Start(); recId = dbController.EnrollReqUpsert(newRec); await FlushRedisCachePattern("Enroll"); await FlushRedisCachePattern("InstVerSta"); var dbResult = await EnrollReqGetById(recId); // svuota eventuale cache redis... sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata EnrollReqUpsert: {ts.TotalMilliseconds} ms"); // invio string in messagepipe x forzare refresh... EnrollMessPipe.sendMessage("NewEnrollReq"); // restituisce risultato return dbResult; } /// /// Elenco file registrati dato ticket id /// /// Identificativo del ticket /// public async Task> FileGetFilt(int idxTicket) { List dbResult = new List(); Stopwatch sw = new Stopwatch(); sw.Start(); dbResult = dbController.FileGetFilt(idxTicket); sw.Stop(); Log.Trace($"Effettuata lettura da DB per FileGetFilt: {sw.Elapsed.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Esegue flush cache dati enroll x successiva rilettura /// /// /// public async Task FlushEnrollCache() { bool fatto = await FlushRedisCachePattern("Enroll"); return fatto; } /// /// Refresh globale cache redis /// /// public async Task FlushRedisCache() { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); await Task.Delay(1); RedisValue pattern = new RedisValue($"{Const.rKeyConfig}:*"); bool answ = await ExecFlushRedisPattern(pattern); UserClaimsLUT = new Dictionary(); stopWatch.Stop(); Log.Debug($"FlushRedisCache in {stopWatch.Elapsed.TotalMilliseconds} ms"); return answ; } /// /// Refresh cache Redis dato redPattern /// /// Pattern da eliminare /// public async Task FlushRedisCachePattern(string pattern) { Stopwatch sw = new Stopwatch(); sw.Start(); await Task.Delay(1); RedisValue redPattern = new RedisValue($"{Const.rKeyConfig}:{pattern}*"); bool answ = await ExecFlushRedisPattern(redPattern); sw.Stop(); Log.Debug($"FlushRedisCachePattern in {sw.Elapsed.TotalMilliseconds} ms"); return answ; } public async Task> InstallazioniNextGetAll() { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Next:Installazioni:List"; Stopwatch sw = new Stopwatch(); sw.Start(); string rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.GetInstallazioni(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); Log.Debug($"InstallazioniNextGetAll | {source} in: {sw.Elapsed.TotalMilliseconds:N2} ms"); } catch (Exception exc) { Log.Error($"Error during InstallazioniNextGetAll:{Environment.NewLine}{exc}"); } return dbResult; #if false List dbResult = new List(); string cacheKey = mHash("Next:Installazioni"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.GetInstallazioni(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per InstallazioniNextGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); #endif } public async Task InstallazioniNextUpdate(InstallazioneModel currItem) { bool done = false; try { done = dbController.UpsertInstallazione(currItem); await FlushRedisCache(); } catch (Exception exc) { Log.Error($"Eccezione in InstallazioniNextUpdate:{Environment.NewLine}{exc}"); } return await Task.FromResult(done); } /// /// Effettua pulizia record registrazione InstalledRelease eliminando quelli non presenti in elenco /// /// CodImpiego /// Chiave App /// Elenco app gestite (=da tenere) /// Num rec eliminati public int InstallRelClean(string CodImp, string AppKey, List ListCodApp) { return dbController.InstallRelClean(CodImp, AppKey, ListCodApp); } /// /// Effettua eliminazione record registrazione InstalledRelease dato idx SubLic /// /// Idx sub licenza /// Num rec eliminati public int InstallRelDelBySubLic(int idxSubLic) { return dbController.InstallRelDelBySubLic(idxSubLic); } /// /// Effettua salvataggio della situazione delle installazioni attive (se non c'è veto per registrazione appena effettuata...) /// /// Forza salvataggio comunque /// public async Task InstallRelHistSnapshot(bool doForce) { bool fatto = false; DateTime adesso = DateTime.Now; if (adesso > VetoInstRelHistSnap || doForce) { // veto x 4h (+/- rand 30 min) VetoInstRelHistSnap = adesso.AddHours(4).AddMinutes(rnd.Next(-30, 30)); // calcolo periodo come x interfaccia... DateTime DtFine = DateTime.Today.AddHours(DateTime.Now.Hour + 1); DateTime DtInizio = DateTime.Today.AddMonths(-1); // svuoto cache info... await ResetInstallStatus(); // recupero info DTO var rawData = await InstallStatusGetInfo(DtInizio, DtFine, "", ""); fatto = dbController.InstallRelHistSnapshot(rawData.InstallStatus); } return fatto; } /// /// Registro su DB il record della licenza attuale relativo alla richiesta di verifica licenza ricevuta /// /// record da inserire/aggiornare public bool InstallRelUpsert(InstalledReleasesModel upRec) { bool fatto = dbController.InstallRelUpsert(upRec); // se ok fa verifica sublicenze... if (fatto) { dbController.CheckCleanOldSubLic(upRec); } return fatto; } /// /// Reset cache info installazioni x forzare reload /// /// public async Task ResetInstallStatus() { bool fatto = false; Stopwatch sw = new Stopwatch(); sw.Start(); string source = "REDIS"; fatto = await FlushRedisCachePattern($"InstVerSta"); sw.Stop(); Log.Debug($"ResetInstallStatus | {source} cleanup in: {sw.Elapsed.TotalMilliseconds} ms"); return fatto; } /// /// Recupera info statistiche installazione dato periodo riferimento, da cache o da db /// /// /// /// Filtro Cliente (CodInstall) /// Filtro TipoApp public async Task InstallStatusGetInfo(DateTime dtStart, DateTime dtEnd, string CodInst, string TipoApp) { string source = "DB"; InstallStatusDTO dbResult = new InstallStatusDTO(); try { string filtCli = string.IsNullOrEmpty(CodInst) ? "ALL-INSTALL" : $"{CodInst}"; string filtTipo = string.IsNullOrEmpty(TipoApp) ? "ALL-TIPO" : $"{TipoApp}"; string currKey = $"{Const.rKeyConfig}:InstVerSta:{filtTipo}:{filtCli}:{dtStart:yyyyMMdd-HHmm}:{dtEnd:yyyyMMdd-HHmm}"; Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject(rawData); if (tempResult == null) { dbResult = new InstallStatusDTO(); } else { dbResult = tempResult; } } else { dbResult = dbController.InstallStatusGetInfo(dtStart, dtEnd, CodInst, TipoApp); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new InstallStatusDTO(); } sw.Stop(); Log.Debug($"InstallStatusGetInfo | {source} in: {sw.Elapsed.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during InstallStatusGetInfo:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Elenco licenze dato ID /// /// ID licenza (DB) /// public async Task LicenzaById(int licId) { LicenzaModel dbResult = new LicenzaModel(); string cacheKey = $"{rKeyLicById}:{licId}"; trackCache(cacheKey); string rawData = await getRSV(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.LicenzaById(licId); if (dbResult != null) { rawData = JsonConvert.SerializeObject(dbResult); await setRSV(cacheKey, rawData, hourTTL); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzaById: {ts.TotalMilliseconds} ms"); } return dbResult; } /// /// Record licenza data masterKey /// /// Chiave Licenza x ricerca /// public async Task LicenzaByMasterKey(string chiave) { LicenzaModel dbResult = new LicenzaModel(); string cacheKey = $"{rKeyLicByMKey}:{chiave}"; trackCache(cacheKey); string rawData = await getRSV(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.LicenzaByKey(chiave); if (dbResult != null) { rawData = JsonConvert.SerializeObject(dbResult); await setRSV(cacheKey, rawData, hourTTL); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzaByMasterKey: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); } /// /// Recupera licenza dato IDX /// /// /// public LicenzaModel LicenzaNextGetByIdx(int IdxLic) { Stopwatch sw = new Stopwatch(); LicenzaModel dbResult = new LicenzaModel(); sw.Start(); dbResult = dbController.GetLicenza(IdxLic); sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzeNextGetByIdx: {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Effettua refresh del Payload della licenza dato info + enigma generato dal client /// /// /// public async Task LicenzaRefreshPayload(LicenseCoord appInfo) { // chiamo metodo x ricalcolare Payload dato enigma bool done = await dbController.LicenseUpdatePayload(appInfo.CodInst, appInfo.CodApp, appInfo.MasterKey, appInfo.Enigma); await FlushRedisCache(); // ora recupero i dati var licList = await LicenzeSearch(appInfo.CodInst, appInfo.CodApp, appInfo.MasterKey, false); return licList.FirstOrDefault(); } /// /// Elenco licenze dato cliente /// /// /// public async Task> LicenzeByCliente(string cliente) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetLicenzeFilt(true, "", cliente); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzeByCliente: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Elenco licenze x data scadenza /// /// Data minima di scadenza /// Data massima di scadenza /// public async Task> LicenzeExpiring(DateTime minDate, DateTime maxDate) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetApplicativiExpiring(minDate, maxDate).ToList(); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per LicenzeExpiring: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task> LicenzeNextGetAll() { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Next:Licenze:List"; Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.GetLicenze(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); Log.Debug($"LicenzeNextGetAll | {source} in: {sw.Elapsed.TotalMilliseconds:N2} ms"); } catch (Exception exc) { Log.Error($"Error during LicenzeNextGetAll:{Environment.NewLine}{exc}"); } return dbResult; #if false List dbResult = new List(); string cacheKey = mHash("Next:Licenze"); string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbControllerNext.GetLicenze(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per LicenzeNextGetAll: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); #endif } /// /// Recupera licenze SENZA cache /// /// /// public async Task> LicenzeNextGetFilt(SelectNext CurrFilter) { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:Next:LicenzeFilt:APP_{CurrFilter.ApplicazioneSel}:INS_{CurrFilter.InstallazioneSel}:OA_{CurrFilter.OnlyActive}"; Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.GetLicenzeFilt(CurrFilter.OnlyActive, CurrFilter.ApplicazioneSel, CurrFilter.InstallazioneSel); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); Log.Debug($"LicenzeNextGetFilt | {source} in: {sw.Elapsed.TotalMilliseconds:N2} ms"); } catch (Exception exc) { Log.Error($"Error during LicenzeNextGetAll:{Environment.NewLine}{exc}"); } return dbResult; } public async Task LicenzeNextUpdate(LicenzaModel currItem) { bool done = false; // chiamo Log licenza + update insieme try { done = dbController.UpsertLicenza(currItem); await FlushRedisCache(); } catch (Exception exc) { Log.Error($"Eccezione in ApplicazioniUpdate:{Environment.NewLine}{exc}"); } return await Task.FromResult(done); } /// /// Elenco licenze dato cliente /// /// Codice Installaizone /Cliente /// Codice Applicazione /// Chiave Licenza da validare /// Indica se nascondere i dati sensibili /// public async Task> LicenzeSearch(string CodInst, string CodApp, string Chiave, bool HideData) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetApplicativiFilt(true, CodApp, CodInst, HideData).Where(x => x.Chiave == Chiave).ToList(); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ApplicativiByCliente: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task ReleaseDelete(ReleaseModel rec2del) { bool fatto = dbController.ReleaseDelete(rec2del); await FlushRedisCache(); return fatto; } /// /// Elenco Release dato Applicativo /// /// Codice Applicazione /// public async Task> ReleaseGetByApp(string CodApp) { string source = "DB"; List? dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:App:AllRel:{CodApp}"; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { dbResult = dbController.ReleaseGetByApp(CodApp); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, LongCache); // per evitare loopback uso deserialize... var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult != null) { dbResult = tempResult; } } if (dbResult == null) { dbResult = new List(); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Debug($"ReleaseGetByApp | {source} in: {ts.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Error during ReleaseGetByApp:{Environment.NewLine}{exc}"); } return dbResult; } /// /// Elenco Release dato Applicativo + versione minima /// /// Codice Applicazione /// Versione minima richiesta /// public async Task> ReleaseGetByAppVers(string CodApp, string VersMin) { await Task.Delay(1); List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.ReleaseGetByAppVers(CodApp, VersMin); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ReleaseGetByAppVers | {CodApp} | vers >= {VersMin} | {ts.TotalMilliseconds} ms"); return dbResult; } /// /// Ultima Release dato Applicativo VALIDA (= rilasciata) /// /// Codice Applicazione /// public async Task ReleaseLastGetByApp(string CodApp) { string answ = ""; RedisKey currKey = $"{Const.rKeyConfig}:App:CurrRel"; var rawVal = await redisDb.HashGetAsync(currKey, CodApp); if (rawVal.HasValue) { answ = $"{rawVal}"; } else { var rawList = await ReleaseGetByApp(CodApp); if (rawList != null) { var lastRel = rawList .Where(x => x.IsReleased) .OrderByDescending(x => x.VersVal) .ThenByDescending(x => x.ReleaseDate) .FirstOrDefault() ?? new ReleaseModel() { CodApp = CodApp }; answ = lastRel.VersNum; // salvo su redis tab... await redisDb.HashSetAsync(currKey, CodApp, answ); } } return answ; } /// /// Upsert record Release applicazione /// /// /// public async Task ReleaseUpsert(ReleaseModel currItem) { bool done = false; Stopwatch sw = new Stopwatch(); sw.Start(); try { done = await dbController.ReleaseUpsert(currItem); await FlushRedisCache(); Log.Trace($"Effettuato upsert su DB per ReleaseUpsert | {currItem.CodApp} | {currItem.VersNum} | {sw.Elapsed.TotalMilliseconds} ms"); } catch (Exception exc) { Log.Error($"Eccezione in ReleaseUpsert:{Environment.NewLine}{exc}"); } return done; } public async Task SendEmail(string destEmail, string oggetto, string corpo) { bool answ = false; try { await _emailSender.SendEmailAsync(destEmail, oggetto, corpo); answ = true; } catch { } return answ; } /// /// Statistiche del LOG chiamate all'API dato filtro /// /// Data minima /// DataMax /// Valore cercato, se "" è tutti /// public async Task> StatsLogCallGetFilt(DateTime DateFrom, DateTime DateTo, string SearchVal = "") { string source = "DB"; List dbResult = new List(); try { string currKey = $"{Const.rKeyConfig}:StatslogCall:{DateFrom:yyyyMMdd}:{DateTo:yyyyMMdd}"; if (!string.IsNullOrEmpty(SearchVal)) { currKey += $":{SearchVal}"; } Stopwatch sw = new Stopwatch(); sw.Start(); string? rawData = await redisDb.StringGetAsync(currKey); if (!string.IsNullOrEmpty(rawData)) { source = "REDIS"; var tempResult = JsonConvert.DeserializeObject>(rawData); if (tempResult == null) { dbResult = new List(); } else { dbResult = tempResult; } } else { var rawResult = dbController.StatsLogCallGetFilt(DateFrom, DateTo, SearchVal); dbResult = rawResult .OrderByDescending(x => x.YearRef) .ThenByDescending(x => x.TotCall) .ToList(); rawData = JsonConvert.SerializeObject(dbResult, JSSettings); await redisDb.StringSetAsync(currKey, rawData, UltraLongCache); } if (dbResult == null) { dbResult = new List(); } sw.Stop(); Log.Debug($"StatsLogCallGetFilt | {source} in: {sw.Elapsed.TotalMilliseconds:N2} ms"); } catch (Exception exc) { Log.Error($"Error during StatsLogCallGetFilt:{Environment.NewLine}{exc}"); } return dbResult; #if false List dbResult = new List(); string cacheKey = mHash($"StatslogCall:{DateFrom:yyyyMMdd}:{DateTo:yyyyMMdd}"); if (!string.IsNullOrEmpty(SearchVal)) { cacheKey += $":{SearchVal}"; } string rawData; var redisDataList = await distributedCache.GetAsync(cacheKey); if (redisDataList != null) { rawData = Encoding.UTF8.GetString(redisDataList); dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); var rawResult = dbControllerNext.StatsLogCallGetFilt(DateFrom, DateTo, SearchVal); dbResult = rawResult .OrderByDescending(x => x.YearRef) .ThenByDescending(x => x.TotCall) .ToList(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per StatsLogCallGetFilt: {ts.TotalMilliseconds} ms"); } return await Task.FromResult(dbResult); #endif } /// /// Restituisce i task associati ad un dato EgwACC in stato DONE /// /// /// public Dictionary TaskDoneGet(string CodImp) { RedisKey currKey = (RedisKey)$"{rKeyTaskDone}:{CodImp}"; Dictionary answ = redisHashDictGet(currKey); return answ; } /// /// Restituisce elenco dei task richiesti da hashtable /// /// public Dictionary TaskListDoneGet() { RedisKey currKey = (RedisKey)$"{rKeyTaskDone}List"; Dictionary answ = redisHashDictGet(currKey); return answ; } /// /// Restituisce elenco dei task richiesti da hashtable /// /// public Dictionary TaskListReqGet() { RedisKey currKey = (RedisKey)$"{rKeyTaskReq}List"; Dictionary answ = redisHashDictGet(currKey); return answ; } /// /// Restituisce elenco dei task richiesti da hashtable /// /// public Dictionary TaskListRunGet() { RedisKey currKey = (RedisKey)$"{rKeyTaskRun}List"; Dictionary answ = redisHashDictGet(currKey); return answ; } /// /// Aggiunta di un task x un dato EgwACC (senza scadenza) /// /// UID impianto /// Task richiesto /// Valore/opzione task /// public bool TaskReqAdd(string CodImp, EgwAccTask TaskType, string TaskVal) { bool answ = redisHashKeySet((RedisKey)$"{rKeyTaskReq}:{CodImp}", $"{TaskType}", TaskVal); // aggiungo al dizionario x ricerca... redisHashKeySet((RedisKey)$"{rKeyTaskReq}List", CodImp, $"{DateTime.Now}"); return answ; } /// /// Aggiunta di un task x una lista di dato EgwACC (senza scadenza) /// /// Lista di UID impianto /// Task richiesto /// Valore/opzione task /// public bool TaskReqAdd(List ListCodImp, EgwAccTask TaskType, string TaskVal) { int done = 0; foreach (var CodImp in ListCodImp) { bool added = TaskReqAdd(CodImp, TaskType, TaskVal); done += added ? 1 : 0; } return done > 0; } /// /// Restituisce i task associati ad un dato EgwACC in stato RICHIESTI /// /// /// public Dictionary TaskReqGet(string CodImp) { RedisKey currKey = (RedisKey)$"{rKeyTaskReq}:{CodImp}"; Dictionary answ = redisHashDictGet(currKey); return answ; } /// /// Resetta i task di un dato EgwACC /// /// /// public bool TaskReqReset(string CodImp) { bool okReq = redisHashDictDelete((RedisKey)$"{rKeyTaskReq}:{CodImp}"); bool okRun = redisHashDictDelete((RedisKey)$"{rKeyTaskRun}:{CodImp}"); redisHashKeyDelete((RedisKey)$"{rKeyTaskReq}List", CodImp); redisHashKeyDelete((RedisKey)$"{rKeyTaskRun}List", CodImp); redisHashKeyDelete((RedisKey)$"{rKeyTaskDone}List", CodImp); return okReq && okRun; } /// /// Restituisce i task associati ad un dato EgwACC in stato RUNNING /// /// /// public Dictionary TaskRunGet(string CodImp) { RedisKey currKey = (RedisKey)$"{rKeyTaskRun}:{CodImp}"; Dictionary answ = redisHashDictGet(currKey); return answ; } /// /// Recupera elenco Tickets filtrato /// /// /// public async Task> TicketsGetAll() { Stopwatch sw = new Stopwatch(); List dbResult = new List(); sw.Start(); dbResult = dbController.TicketGetAll(false, 1000); sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata lettura da DB per TicketsGetAll: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Ricerca ticket filtrati /// /// /// /// /// public async Task> TicketsGetFilt(bool onlyOpen, string CodApp, string CodInst) { Stopwatch sw = new Stopwatch(); List dbResult = new List(); sw.Start(); dbResult = dbController.TicketGetFilt(onlyOpen, CodApp, CodInst); sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata lettura da DB per TicketsGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera elenco Tickets filtrato /// /// /// public async Task> TicketsGetFilt(SelectNext CurrFilter) { Stopwatch sw = new Stopwatch(); List dbResult = new List(); sw.Start(); dbResult = dbController.TicketGetFiltAllLic(CurrFilter.OnlyActive, Core.Enum.TipologiaTicket.ND, CurrFilter.ApplicazioneSel, CurrFilter.InstallazioneSel, 1000); sw.Stop(); TimeSpan ts = sw.Elapsed; Log.Trace($"Effettuata lettura da DB per TicketsGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Aggiornamentos tato ticket /// /// /// /// public async Task TicketUpdateState(int IdxTicket, StatoRichiesta NewStatus) { bool fatto = false; // inserimento! Stopwatch sw = new Stopwatch(); sw.Start(); fatto = dbController.TicketUpdateState(IdxTicket, NewStatus); sw.Stop(); Log.Trace($"Effettuata update con TicketUpdateState: {sw.Elapsed.TotalMilliseconds} ms"); // restituisce elenco return await Task.FromResult(fatto); } /// /// Verifica di un role utente dall'elenco claims... /// /// /// /// public bool UserHasClaim(string userName, string role) { bool answ = false; string keyLUT = $"{userName}_{role}"; if (UserClaimsLUT.ContainsKey(keyLUT)) { answ = UserClaimsLUT[keyLUT]; } else { var pUpd = Task.Run(async () => { var userClaims = await AuthClaimByUserName(userName); if (userClaims != null && userClaims.Count > 0) { answ = userClaims.Where(x => x.RoleNav.Ruolo == role).Any(); } }); pUpd.Wait(); UserClaimsLUT.Add(keyLUT, answ); } return answ; } #endregion Public Methods #region Protected Fields /// /// TTL da 1 h x cache Redis /// protected const int hourTTL = 60 * 60; /// /// TTL da 1 min x cache Redis /// protected const int redCacheTtlFast = 60 * 1; /// /// TTL da 5 min x cache Redis /// protected const int redCacheTtlStd = 60 * 5; /// /// Chiave redis x attivazioni da IdxLic /// protected const string rKeyAttivByLic = "LiMan.UI:Licenze:AttByIdxLic"; /// /// Chiave base dati Redis gestiti API /// protected const string rKeyBaseApi = "LiMan:API"; /// /// Chiave base dati Redis gestiti UI/API /// protected const string rKeyBaseComm = "LiMan:ALL"; /// /// Chiave base dati Redis gestiti UI /// protected const string rKeyBaseUi = "LiMan:UI"; /// /// Chiave degli elenchi dei devices con EgwACC in esecuzione /// protected const string rKeyEACCDetail = $"{rKeyBaseComm}:EAccDetail"; /// /// Chiave degli elenchi dei devices con EgwACC in esecuzione /// protected const string rKeyEACCList = $"{rKeyBaseComm}:EAccList"; /// /// Chiave redis x licenze da ID /// protected const string rKeyLicById = "LiMan.UI:Licenze:ById"; /// /// Chiave redis x licenze da MasterKey /// protected const string rKeyLicByMKey = "LiMan.UI:Licenze:ListByKey"; /// /// Chiave redis x statistiche in acquisizione /// protected const string rKeySampleStats = "LiMan.UI:SampleStats:Curr"; /// /// Chiave redis x statistiche in acquisizione /// protected const string rKeySampleVars = "LiMan.UI:SampleStats:Vars"; /// /// Chiave redis x statistiche chiamate /// protected const string rKeyStatslogCall = "LiMan.UI:StatsLogCall"; /// /// Chiave degli elenchi dei Task eseguiti /// protected const string rKeyTaskDone = $"{rKeyBaseComm}:TaskDone"; /// /// Chiave degli elenchi dei Task req/pending /// protected const string rKeyTaskReq = $"{rKeyBaseComm}:TaskReq"; /// /// Chiave degli elenchi dei Task in esecuzione /// protected const string rKeyTaskRun = $"{rKeyBaseComm}:TaskRun"; /// /// Chiave degli elenchi delle ultime DataOra di comunicazione degli updater /// protected const string rKeyUpdLastAct = $"{rKeyBaseComm}:LastActions"; protected static IConfiguration _configuration; protected static Controllers.DbController dbController; protected static JsonSerializerSettings? JSSettings; protected static Logger Log = LogManager.GetCurrentClassLogger(); /// /// Oggetto per invio email /// protected readonly IEmailSender _emailSender; /// /// Durata cache lunga IN SECONDI /// protected int cacheTtlLong = 60 * 5; /// /// Durata cache breve IN SECONDI /// protected int cacheTtlShort = 60 * 1; /// /// Oggetto per connessione a REDIS /// protected IConnectionMultiplexer redisConn = null!; /// /// Oggetto DB redis da impiegare x chiamate R/W /// protected IDatabase redisDb = null!; protected Random rnd = new Random(); #endregion Protected Fields #region Protected Properties /// /// Durata cache breve (1 min circa + perturbazione percentuale +/-10%) /// protected TimeSpan FastCache { get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000); } /// /// Durata cache lunga (+ perturbazione percentuale +/-10%) /// protected TimeSpan LongCache { get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000); } /// /// Durata cache MOLTO breve (10 sec circa + perturbazione percentuale +/-10%) /// protected TimeSpan UltraFastCache { get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000); } /// /// Durata cache MOLTO lunga (+ perturbazione percentuale +/-10%) /// protected TimeSpan UltraLongCache { get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000); } #endregion Protected Properties #region Protected Methods /// /// Esegue flush memoria redis dato pat2Flush /// /// /// protected async Task ExecFlushRedisPattern(RedisValue pat2Flush) { bool answ = false; var masterEndpoint = redisConn.GetEndPoints() .Where(ep => redisConn.GetServer(ep).IsConnected && !redisConn.GetServer(ep).IsReplica) .FirstOrDefault(); // sepattern è "*" elimino intero DB... if (masterEndpoint != null && (pat2Flush.Equals(new RedisValue("*")) || pat2Flush == RedisValue.Null)) { redisConn.GetServer(masterEndpoint).FlushDatabase(database: redisDb.Database); } else { var server = redisConn.GetServer(masterEndpoint); var keys = server.Keys(database: redisDb.Database, pattern: pat2Flush, pageSize: 1000); var deleteTasks = new List(); foreach (var key in keys) { deleteTasks.Add(redisDb.KeyDeleteAsync(key)); if (deleteTasks.Count >= 1000) { await Task.WhenAll(deleteTasks); deleteTasks.Clear(); } } if (deleteTasks.Count > 0) { await Task.WhenAll(deleteTasks); } } answ = true; #if false var listEndpoints = redisConn.GetEndPoints(); foreach (var endPoint in listEndpoints) { //var server = redisConnAdmin.GetServer(listEndpoints[0]); var server = redisConn.GetServer(endPoint); if (server != null) { var keyList = server.Keys(redisDb.Database, pattern); foreach (var item in keyList) { await redisDb.KeyDeleteAsync(item); } answ = true; } } #endif return answ; } /// /// Recupero chiave da redis /// /// /// protected async Task getRSV(string rKey) { string answ = await redisDb.StringGetAsync(rKey); return answ; } /// /// Recupera contatore x la chiave redis indicata... /// /// protected async Task redCount(string rKey) { int currCount = 0; string rawVal = await getRSV(rKey); if (!string.IsNullOrEmpty(rawVal)) { int.TryParse(rawVal, out currCount); } return currCount; } /// /// Resetta contatore x la chiave redis indicata... /// /// protected async Task redCountClear(string rKey) { bool answ = false; int currCount = 0; answ = await setRSV(rKey, currCount, 2 * hourTTL); return answ; } /// /// Incrementa contatore x la chiave redis indicata... /// /// protected async Task redCountIncr(string rKey) { bool answ = false; int currCount = 0; string rawVal = await getRSV(rKey); if (!string.IsNullOrEmpty(rawVal)) { int.TryParse(rawVal, out currCount); } currCount++; answ = await setRSV(rKey, currCount, 2 * hourTTL); return answ; } /// /// Eliminazione di un HashSet Redis /// /// Chiave del dizionario protected bool redisHashDictDelete(RedisKey dictKey) { bool fatto = false; try { // rimuovo scrivendo un set vuoto con expiry a 1 sec HashEntry[] data2ins = new HashEntry[1]; data2ins[0] = new HashEntry("removed", $"{DateTime.Now}"); // salvo! redisDb.HashSet(dictKey, data2ins); redisDb.KeyExpire(dictKey, DateTime.Now.AddMilliseconds(1)); fatto = true; } catch (Exception exc) { Log.Error($"Eccezione in redisHashDictDelete | dictKey: {dictKey}{Environment.NewLine}{exc}"); } return fatto; } /// /// Recupero HashSet redis come Dictionary /// /// Chiave del dizionario /// Dizionario valori salvato protected Dictionary redisHashDictGet(RedisKey dictKey) { Dictionary answ = new Dictionary(); if (redisDb.KeyExists(dictKey)) { try { answ = redisDb .HashGetAll(dictKey) .ToDictionary(x => $"{x.Name}", x => $"{x.Value}"); } catch (Exception exc) { Log.Info($"Errore redisHashDictGet | dictKey: {dictKey}{Environment.NewLine}{exc}"); } } return answ; } /// /// Salvataggio Dictionary come HashSet Redis, con expiry NON gestito (0 = mai) /// /// Chiave del dizionario /// Valore Dizionario da salvare protected bool redisHashDictSet(RedisKey dictKey, Dictionary dict) { // ove non indicato expiry è 0 = MAI return redisHashDictSet(dictKey, dict, 0); } /// /// Salvataggio Dictionary come HashSet Redis /// /// Chiave del dizionario /// Valore Dizionario da salvare /// Expiry in minuti del valore, se 0 = mai protected bool redisHashDictSet(RedisKey dictKey, Dictionary dict, double expireMin) { bool fatto = false; try { HashEntry[] data2ins = new HashEntry[dict.Count]; int i = 0; foreach (KeyValuePair kvp in dict) { data2ins[i] = new HashEntry(kvp.Key, kvp.Value); i++; } // salvo! redisDb.HashSet(dictKey, data2ins); // se richiesto imposto Expiry if (expireMin > 0) { redisDb.KeyExpire(dictKey, DateTime.Now.AddMinutes(expireMin)); } fatto = true; } catch (Exception exc) { Log.Error($"Eccezione in redisHashDictSet | dictKey: {dictKey}{Environment.NewLine}{exc}"); } return fatto; } /// /// Eliminazione di un singolo valore da un HashSet Redis /// /// Chiave del dizionario /// Chiave del valore da eliminare (singolo record) protected bool redisHashKeyDelete(RedisKey dictKey, string recKey) { bool fatto = false; try { redisDb.HashDelete(dictKey, (RedisValue)recKey); fatto = true; } catch (Exception exc) { Log.Error($"Eccezione in redisHashKeyDelete | dictKey: {dictKey}{Environment.NewLine}{exc}"); } return fatto; } /// /// recupero un singolo valore in HashSet Redis /// /// Chiave del dizionario /// Chiave valore da recuperare protected string redisHashKeyGet(RedisKey dictKey, string recKey) { string answ = redisDb.HashGet(dictKey, (RedisValue)recKey); return answ; } /// /// Salvataggio variazione in (incremento/decremento) di un singolo valore in HashSet Redis, con expiry NON gestito (0 = mai) /// /// Chiave del dizionario /// Chiave valore da salvare /// Valore di incremento/decremento da salvare protected bool redisHashKeyIncDecBy(RedisKey dictKey, string recKey, long incrVal) { // ove non indicato expiry è 0 = MAI return redisHashKeyIncDecBy(dictKey, recKey, incrVal, 0); } /// /// Salvataggio INCREMENTO di un singolo valore in HashSet Redis /// /// Chiave del dizionario /// Chiave valore da salvare /// Incremento/decremento da salvare /// Expiry in minuti del valore, se 0 = mai protected bool redisHashKeyIncDecBy(RedisKey dictKey, string recKey, long incrVal, double expireMin) { bool fatto = false; try { // salvo! if (incrVal > 0) { redisDb.HashIncrement(dictKey, (RedisValue)recKey, incrVal); } else { redisDb.HashDecrement(dictKey, (RedisValue)recKey, Math.Abs(incrVal)); } // se richiesto imposto Expiry if (expireMin > 0) { redisDb.KeyExpire(dictKey, DateTime.Now.AddMinutes(expireMin)); } fatto = true; } catch (Exception exc) { Log.Error($"Eccezione in redisHashKeyIncDecBy | dictKey: {dictKey}{Environment.NewLine}{exc}"); } return fatto; } /// /// Salvataggio di un singolo valore in HashSet Redis, con expiry NON gestito (0 = mai) /// /// Chiave del dizionario /// Chiave valore da salvare /// Valore da salvare protected bool redisHashKeySet(RedisKey dictKey, string recKey, string recVal) { // ove non indicato expiry è 0 = MAI return redisHashKeySet(dictKey, recKey, recVal, 0); } /// /// Salvataggio di un singolo valore in HashSet Redis /// /// Chiave del dizionario /// Chiave valore da salvare /// Valore da salvare /// Expiry in minuti del valore, se 0 = mai protected bool redisHashKeySet(RedisKey dictKey, string recKey, string recVal, double expireMin) { bool fatto = false; try { HashEntry[] data2ins = new HashEntry[1] { new HashEntry(recKey, recVal) }; // salvo! redisDb.HashSet(dictKey, data2ins); // se richiesto imposto Expiry if (expireMin > 0) { redisDb.KeyExpire(dictKey, DateTime.Now.AddMinutes(expireMin)); } fatto = true; } catch (Exception exc) { Log.Error($"Eccezione in redisHashKeySet | dictKey: {dictKey}{Environment.NewLine}{exc}"); } return fatto; } /// /// Salvataggio chiave in redis /// /// /// /// /// protected async Task setRSV(string rKey, string rVal, int ttlSec) { bool fatto = false; await redisDb.StringSetAsync(rKey, rVal, TimeSpan.FromSeconds(ttlSec)); fatto = true; return fatto; } /// /// Salvataggio chiave in redis /// /// /// /// /// protected async Task setRSV(string rKey, int rValInt, int ttlSec) { bool fatto = false; await redisDb.StringSetAsync(rKey, $"{rValInt}", TimeSpan.FromSeconds(ttlSec)); fatto = true; return fatto; } /// /// Registra in cache chiave se non fosse già in elenco /// /// protected void trackCache(string newKey) { if (!cachedDataList.Contains(newKey)) { cachedDataList.Add(newKey); } } #endregion Protected Methods #region Private Fields /// /// Elenco obj in cache /// private List cachedDataList = new List(); private Dictionary UserClaimsLUT = new Dictionary(); /// /// data-ora veto registrazione di una nuova registrazione di snapshot installazioni attive al giorno corrente /// private DateTime VetoInstRelHistSnap = DateTime.Today; #endregion Private Fields } }