using MP.Data.Conf; using MP.Data.DatabaseModels; using MP.WASM.Mon.Server.Controllers; using Newtonsoft.Json; using NLog; using StackExchange.Redis; using System.Diagnostics; using System.Text; namespace MP.WASM.Mon.Server.Data { public class MpDataService : IDisposable { #region Public Constructors public MpDataService(IConfiguration configuration, ILogger logger, IConnectionMultiplexer redConn, MessageService MServ) { _logger = logger; _configuration = configuration; _MServ = MServ; // setup compoenti REDIS //this.redisConn = redConn; this.redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis")); this.redisDb = this.redisConn.GetDatabase(); // conf DB string connStr = _configuration.GetConnectionString("Mp.Mon"); if (string.IsNullOrEmpty(connStr)) { _logger.LogError("ConnString empty!"); } else { dbController = new MP.Data.Controllers.MpMonController(configuration); StringBuilder sb = new StringBuilder(); sb.AppendLine($"MpDataService: DbController OK"); _logger.LogInformation(sb.ToString()); } // setup parametri opzionali setupConf(); // setup conf IOB da dizionario tryLoadIobTags(); } #endregion Public Constructors #region Public Properties public static MP.Data.Controllers.MpMonController dbController { get; set; } = null!; /// /// Dizionario dei tag configurati per IOB /// public Dictionary> currTagConf { get; set; } = new Dictionary>(); #endregion Public Properties #region Public Methods public Task> ConfigGetAll() { return Task.FromResult(dbController.ConfigGetAll().ToList()); } public void Dispose() { // Clear database controller dbController.Dispose(); _logger.LogInformation("MpDataService disposed!"); } /// /// Elenco setup dei tag conf correnti /// /// public Task>> getAllTags() { return Task.FromResult(currTagConf); } /// /// restituisce il valore da REDIS associato al tag richeisto /// /// Chiave in cui cercare il valore /// public string getTagConf(string redKey) { string outVal = ""; // cerco in REDIS la conf x l'IOB var rawData = redisDb.StringGet(redKey); if (!string.IsNullOrEmpty(rawData)) { outVal = $"{rawData}"; } return outVal; } public Task> MacchineGetAll() { return Task.FromResult(dbController.MacchineGetAll()); } public async Task> MseGetAll() { List result = new List(); // se lettura in corso... attendo 10..50ms... if (DateTime.Now.Subtract(MessageService.lastRead).TotalMilliseconds < 100) { Random rnd = new Random(); await Task.Delay(rnd.Next(10, 50)); } Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); // cerco in redis... var rawData = await redisDb.StringGetAsync(redisMseKey); if (!string.IsNullOrEmpty(rawData)) { result = JsonConvert.DeserializeObject>(rawData); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"REDIS Read: {ts.TotalMilliseconds:N2}ms"); } else { result = await Task.FromResult(dbController.MseGetAll()); // serializzp e salvo... rawData = JsonConvert.SerializeObject(result); await redisDb.StringSetAsync(redisMseKey, rawData, TimeSpan.FromSeconds(fastRefreshSec)); stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; Log.Trace($"DB Read: {ts.TotalMilliseconds:N2}ms"); } if (result == null) { result = new List(); } MessageService.lastRead = DateTime.Now; return result; } #endregion Public Methods #region Protected Methods /// /// Recupera il valore e se trovato aggiorna /// /// Valore da cercare /// String in cui salvare il valore se trovato /// protected bool getConfVal(string chiave, ref string varObj) { bool answ = false; if (CurrConfig != null && CurrConfig.Count > 0) { // sistemo i parametri opzionali... ConfigModel? risultato = CurrConfig.FirstOrDefault(x => x.Chiave == chiave); if (risultato != null) { varObj = risultato.Valore; answ = !string.IsNullOrEmpty(risultato.Valore); } } return answ; } /// /// Recupera il valore e se trovato aggiorna /// /// Valore da cercare /// Int in cui salvare il valore se trovato /// protected bool getConfValInt(string chiave, ref int varObj) { bool answ = false; if (CurrConfig != null && CurrConfig.Count > 0) { // sistemo i parametri opzionali... ConfigModel? risultato = CurrConfig.FirstOrDefault(x => x.Chiave == chiave); if (risultato != null) { answ = int.TryParse(risultato.Valore, out varObj); } } return answ; } #endregion Protected Methods #region Private Fields private static IConfiguration _configuration = null!; private static ILogger _logger = null!; private static NLog.Logger Log = LogManager.GetCurrentClassLogger(); private List? CurrConfig = null; private int fastRefreshSec = 2; private static MessageService _MServ = null!; /// /// Oggetto per connessione a REDIS /// private ConnectionMultiplexer redisConn = null!; /// /// Oggetto DB redis da impiegare x chiamate R/W /// private IDatabase redisDb = null!; private string redisMseKey = "MP:MON:Cache:MSE"; #endregion Private Fields #region Private Methods private void setupConf() { CurrConfig = dbController.ConfigGetAll(); if (CurrConfig != null && CurrConfig.Count > 0) { // sistemo i parametri opzionali... getConfValInt("MSE_cacheDuration", ref fastRefreshSec); Log.Info($"Effettuato setup parametri | MSE_cacheDuration: {fastRefreshSec}"); } } /// /// Prova a caricare da file la conf degli IOB se presente /// private void tryLoadIobTags() { Dictionary> currConf = new Dictionary>(); string strExeFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(strExeFilePath)) { string? strWorkPath = Path.GetDirectoryName(strExeFilePath); if (!string.IsNullOrEmpty(strWorkPath)) { string filePath = $"{strWorkPath}/Conf/iobTagsConf.json"; if (File.Exists(filePath)) { string rawData = File.ReadAllText(filePath); if (!string.IsNullOrEmpty(rawData)) { var fileConfData = JsonConvert.DeserializeObject(rawData); if (fileConfData != null) { // effettuo esplosione conf SE contenesse il valore "***" = tutti // gli IOB if (fileConfData.IobSetup.ContainsKey("***")) { // recupero elenco macchine... var elencoMacc = dbController.MacchineGetAll(); // x ogni macchina creo le righe standard da conf... var baseConf = fileConfData.IobSetup.Where(x => x.Key == "***").FirstOrDefault(); foreach (var item in elencoMacc) { if (!string.IsNullOrEmpty(item.IdxMacchina)) { // converto i valori x la macchina corrente... clono in // nuovo oggetto var specVal = baseConf.Value.Select(i => i.Clone()).ToList(); // sostituisco segnaposto foreach (var singleVal in specVal) { singleVal.TagLocation = singleVal.TagLocation.Replace("***", item.IdxMacchina); } // ora aggiungo eventuali valori in override... if (fileConfData.IobSetup.ContainsKey(item.IdxMacchina)) { var otConf = fileConfData.IobSetup.Where(x => x.Key == item.IdxMacchina).FirstOrDefault(); //verifico x ogni valore other... foreach (var otTag in otConf.Value) { var ovrTag = specVal.Where(x => x.ColNum == otTag.ColNum && x.RowNum == otTag.RowNum).FirstOrDefault(); // se contiene --> sovrascrivo if (ovrTag != null) { //ovrTag = otTag.Clone(); specVal.Remove(ovrTag); specVal.Add(otTag.Clone()); } // se non contiene --> aggiungo else { specVal.Add(otTag); } } } currConf.Add(item.IdxMacchina, specVal); } } } // altrimenti copio ed ho finito else { currConf = fileConfData.IobSetup; } } } } if (currConf != null) { currTagConf = currConf; } } } } #endregion Private Methods } }