using GPW.CORE.Data; using GPW.CORE.Data.DbModels; using Microsoft.AspNetCore.Identity.UI.Services; using Newtonsoft.Json; using NLog; using StackExchange.Redis; using System.Diagnostics; namespace GPW.CORE.Api.Data { public class ApiDataService : IDisposable { #region Public Fields /// /// Classe Accesso metodi DB /// public static CORE.Data.Controllers.GPWController dbController = null!; #endregion Public Fields #region Public Constructors /// /// Init classe /// /// /// /// /// public ApiDataService(IConfiguration configuration, ILogger logger, IEmailSender emailSender, IConnectionMultiplexer redisConn) { _logger = logger; _configuration = configuration; _emailSender = emailSender; // setup compoenti REDIS var redConnString = _configuration.GetConnectionString("Redis"); if (redConnString == null) { _logger.LogError("REDIS ConnString empty!"); } else { this.redisConn = ConnectionMultiplexer.Connect(redConnString); this.redisDb = this.redisConn.GetDatabase(); } // Conf DB var connStrDB = _configuration.GetConnectionString("GPW.DB"); if (string.IsNullOrEmpty(connStrDB)) { _logger.LogError("ConnString empty!"); } else { dbController = new CORE.Data.Controllers.GPWController(configuration); _logger.LogInformation("DbController OK"); } } #endregion Public Constructors #region Public Methods /// /// Recupera l'elenco fasi (ATTIVE) /// /// public async Task> AnagFasiActiv() { List? dbResult = new List(); string cacheKey = $"{rKeyFasiAct}"; trackCache(cacheKey); string rawData = await getRSV(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.AnagFasiAll(true); rawData = JsonConvert.SerializeObject(dbResult, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); await setRSV(cacheKey, rawData, shortTTL); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AnagFasiActiv: {ts.TotalMilliseconds} ms"); } if (dbResult == null) { dbResult = new List(); } return await Task.FromResult(dbResult); } /// /// Recupera l'elenco progetti (ATTIVI) /// /// public async Task> AnagProjActiv() { List? dbResult = new List(); string cacheKey = $"{rKeyProjAct}"; trackCache(cacheKey); string rawData = await getRSV(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject>(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.AnagProjAll(true); rawData = JsonConvert.SerializeObject(dbResult, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); await setRSV(cacheKey, rawData, shortTTL); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per AnagProjActiv: {ts.TotalMilliseconds} ms"); } if (dbResult == null) { dbResult = new List(); } return await Task.FromResult(dbResult); } /// /// Vista dati per FASE (tipicamente master...) con totalizzaizone ore budget/real e stato fase /// /// /// public async Task CalcOreFase(int idxFase, bool doLog) { CalcOreFasiModel? dbResult = new CalcOreFasiModel(); string cacheKey = $"{rKeyCalcOreFase}:{idxFase}"; trackCache(cacheKey); string rawData = await getRSV(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject(rawData); } else { Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.CalcOreFase(idxFase); rawData = JsonConvert.SerializeObject(dbResult, Formatting.None, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); await setRSV(cacheKey, rawData, shortTTL); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; if (doLog) { Log.Trace($"Effettuata lettura da DB per CalcOreFase: {ts.TotalMilliseconds} ms"); } } if (dbResult == null) { dbResult = new CalcOreFasiModel(); } return await Task.FromResult(dbResult); } public async Task> ChecksGetByDip(int idxDip) { DateTime dtFine = DateTime.Today.AddDays(1); List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetChecksVC19Filt(idxDip, dtFine.AddMonths(-1), dtFine); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ChecksGetByDip: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task> ChecksGetLast(int numRecord) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.GetChecksVC19(numRecord); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per ChecksGetLast: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera record anomalie dipendenti /// /// /// /// /// /// public async Task> DipAndAnomGetAll(DateTime inizio, DateTime fine, bool notOkApp, bool notOkTim, bool notOkLav) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.DipAndAnomGetAll(inizio, fine, notOkApp, notOkTim, notOkLav); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per DipAndAnomGetAll: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public async Task> DipendentiGetAll() { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.DipendentiGetAll(); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per DipendentiGetAll: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } public void Dispose() { // Clear database controller dbController.Dispose(); } /// /// Imposta stato di una fase /// /// ID /// /// Stato attivo true/false (se è amster -_> aggiorna sottofasi x trigger su DB /// /// public async Task FasiSetActive(int idxFase, bool isActive) { return await dbController.FasiSetActive(idxFase, isActive); } public async Task InsertCheck(DCCDecode updItem, string clientIp) { bool done = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); done = dbController.InsertCheck(updItem, clientIp); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata operazione InsertCheck: {ts.TotalMilliseconds} ms"); return await Task.FromResult(done); } public async Task InsertManual(int idxDip, string clientIp) { bool done = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); done = dbController.InsertManual(idxDip, clientIp); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata operazione InsertManual: {ts.TotalMilliseconds} ms"); return await Task.FromResult(done); } /// /// invalida tutta la cache in caso di update /// /// public async Task InvalidateAllCache() { foreach (var item in cachedDataList) { await redisDb.StringSetAsync(item, "", TimeSpan.FromMilliseconds(5)); } cachedDataList = new List(); } /// /// Recupera eventi dato criteri filtro /// /// /// /// /// public async Task> RegEventiGetFilt(DateTime inizio, DateTime fine, string evento) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.RegEventiGetFilt(inizio, fine, evento); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per RegEventiGetFilt: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Insert/Update di un record in Registro Eventi /// /// /// public async Task RegEventiUpdate(RegistroEventiModel currItem) { bool done = false; Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); done = dbController.RegEventiUpdate(currItem); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata operazione RegEventiUpdate: {ts.TotalMilliseconds} ms"); return await Task.FromResult(done); } /// /// Recupera record anomalie dipendenti /// /// singolo idx oppure 0 = tutti /// /// /// /// /// /// /// public async Task> TeRaExplGetAll(int idxDipendente, DateTime dataFrom, DateTime dataTo, bool inatt, bool showWE, int maxErrMin, int maxErrPlus) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.TeRaExplGetAll(idxDipendente, dataFrom, dataTo, inatt, showWE, maxErrMin, maxErrPlus); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TeRaExplGetAll: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera record anomalie dipendenti /// /// singolo idx oppure 0 = tutti /// /// /// /// /// /// public async Task> TimbExplGetAnomalie(int idxDipendente, DateTime inizio, DateTime fine, bool notOkApp, bool notOkTim, bool notOkLav) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.TimbExplGetAnomalie(idxDipendente, inizio, fine, notOkApp, notOkTim, notOkLav); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TimbExplGetAnomalie: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera record anomalie dipendenti /// /// singolo idx oppure 0 = tutti /// /// /// public async Task> TimbExplGetContinuato(int idxDipendente, DateTime inizio, DateTime fine) { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.TimbExplGetContinuato(idxDipendente, inizio, fine); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TimbExplGetContinuato: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } /// /// Recupera elenco anomalie x timbrature future /// /// public async Task> TimbratureAnomalieFuture() { List dbResult = new List(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); dbResult = dbController.TimbratureAnomalieFuture(); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB per TimbratureAnomalieFuture: {ts.TotalMilliseconds} ms"); return await Task.FromResult(dbResult); } #endregion Public Methods #region Protected Fields protected const string rKeyCalcOreFase = "Check:OreFasi"; protected const string rKeyFasiAct = "Check:FasiAct"; protected const string rKeyProjAct = "Check:ProjAct"; /// /// TTL da 1 min x cache Redis /// protected const int shortTTL = 60 * 5; #endregion Protected Fields #region Protected Methods /// /// Recupero chiave da redis /// /// /// protected async Task getRSV(string rKey) { string answ = ""; var rawData = await redisDb.StringGetAsync(rKey); if (rawData.HasValue) { answ = $"{rawData}"; } return answ; } /// /// 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 private static IConfiguration _configuration = null!; private static ILogger _logger = null!; private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private readonly IEmailSender _emailSender; //private readonly IDistributedCache distributedCache; //private readonly IRedisCacheClient _redisCacheClient; /// /// Elenco obj in cache /// private List cachedDataList = new List(); /// /// Oggetto per connessione a REDIS /// private ConnectionMultiplexer redisConn = null!; /// /// Oggetto DB redis da impiegare x chiamate R/W /// private IDatabase redisDb = null!; #endregion Private Fields } }