using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Caching.Memory; using MP.MONO.Core.DTO; using MP.MONO.Data; using MP.MONO.Data.Controllers; using Newtonsoft.Json; using NLog; using StackExchange.Redis; using System.Diagnostics; using System.Text; using StackExchange.Redis; namespace MP.MONO.UI.Data { public class CurrentDataService : IDisposable { #region Private Fields private static IConfiguration _configuration; private static ILogger _logger; private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private readonly IDistributedCache distributedCache; /// /// Oggetto per connessione a REDIS /// private ConnectionMultiplexer redisConn = null!; //ISubscriber sub = redis.GetSubscriber(); /// /// Oggetto DB redis da impiegare x chiamate R/W /// private IDatabase redisDb = null!; /// /// Durata assoluta massima della cache IN SECONDI /// private int chAbsExp = 60 * 5; /// /// Durata della cache IN SECONDI in modalità inattiva (non acceduta) prima di venire rimossa /// NON estende oltre il tempo massimo di validità della cache (chAbsExp) /// private int chSliExp = 60 * 1; #endregion Private Fields #region Public Fields /// /// Controller dati da DB /// public static MpDbController dbController; /// /// Controller dati simulati /// public static SimController simGen; #endregion Public Fields public MessagePipe alarmPipe { get; set; } = null!; public MessagePipe parametersPipe { get; set; } = null!; public MessagePipe statusPipe { get; set; } = null!; #region Public Constructors public CurrentDataService(IConfiguration configuration, ILogger logger, IDistributedCache distributedCache, IConnectionMultiplexer redisConn) { _logger = logger; _configuration = configuration; // setup compoenti REDIS this.redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis")); this.redisDb = this.redisConn.GetDatabase(); // setup canali pub/sub alarmPipe = new MessagePipe(redisConn, "allarms"); parametersPipe = new MessagePipe(redisConn, "parameters"); statusPipe = new MessagePipe(redisConn, "status"); // conf cache this.distributedCache = distributedCache; // conf DB string connStr = _configuration.GetConnectionString("MP.MONO.Data"); if (string.IsNullOrEmpty(connStr)) { _logger.LogError("ConnString empty!"); } else { dbController = new MpDbController(configuration); _logger.LogInformation("DbController OK"); } simGen = new SimController(); } #endregion Public Constructors #region Protected Properties #if false protected Dictionary? ParametersList { get; set; } = new Dictionary(); #endif #endregion Protected Properties #region Private Methods /// /// Hash Redis contenente i dati MP di una specifico TYPE (es StatusMacchina, StateMachineIngressi, ...) /// /// /// private static string mHash(string dataType) { return $"MAPO-MONO:{dataType}"; } private DistributedCacheEntryOptions cacheOpt(bool fastCache) { var numSecAbsExp = fastCache ? chAbsExp : chAbsExp * 10; var numSecSliExp = fastCache ? chSliExp : chSliExp * 10; return new DistributedCacheEntryOptions().SetAbsoluteExpiration(DateTime.Now.AddSeconds(numSecAbsExp)).SetSlidingExpiration(TimeSpan.FromSeconds(numSecSliExp)); } #endregion Private Methods #region Public Methods public void Dispose() { // Clear database controller dbController.Dispose(); } #if false public async Task> GetCurrentParameters() { ParametersList = new Dictionary(); string cacheKey = mHash("Machine:Parameters:Current"); string rawData = await redisDb.StringGetAsync(cacheKey); if (!string.IsNullOrEmpty(rawData)) { ParametersList = JsonConvert.DeserializeObject>(rawData); } else { ParametersList = simGen.GetCurrentParameters(); rawData = JsonConvert.SerializeObject(ParametersList); await redisDb.StringSetAsync(cacheKey, rawData); } return ParametersList; } #endif public async Task> MachineDisplay() { List? dbResult = new List(); string cacheKey = mHash("Machine:Parameters:Current"); string rawData = await redisDb.StringGetAsync(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject>(rawData); } #if false else { dbResult = simGen.MachineGetParameters(); rawData = JsonConvert.SerializeObject(dbResult); await redisDb.StringSetAsync(cacheKey, rawData); } #endif if (dbResult == null) { dbResult = new List(); } #if false 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 = dbController.MachineGetDisplay(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); // tolgo salvataggio x sim meglio //await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per MachineDisplay: {ts.TotalMilliseconds} ms"); } if (dbResult == null) { dbResult = new List(); } #endif return await Task.FromResult(dbResult); } public async Task MachineProd() { ProductionDTO? dbResult = new ProductionDTO(); string cacheKey = mHash("DATA:Machine:Prod"); 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 = dbController.MachineGetProd(); rawData = JsonConvert.SerializeObject(dbResult); redisDataList = Encoding.UTF8.GetBytes(rawData); // tolgo salvataggio x sim meglio //await distributedCache.SetAsync(cacheKey, redisDataList, cacheOpt(true)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"Effettuata lettura da DB + caching per MachineProd: {ts.TotalMilliseconds} ms"); } if (dbResult == null) { dbResult = new ProductionDTO(); } return await Task.FromResult(dbResult); } public async Task MachineStatus() { MachineDTO? dbResult = new MachineDTO(); string cacheKey = mHash("Machine:Status:Current"); string rawData = await redisDb.StringGetAsync(cacheKey); if (!string.IsNullOrEmpty(rawData)) { dbResult = JsonConvert.DeserializeObject(rawData); } #if false else { dbResult = simGen.MachineGetStatus(); rawData = JsonConvert.SerializeObject(dbResult); redisDb.StringSetAsync(cacheKey, rawData); } #endif if (dbResult == null) { dbResult = new MachineDTO(); } return await Task.FromResult(dbResult); } #endregion Public Methods } }