Files
mapo-core/MP.IOC/Data/MpDataService.cs
2026-05-11 09:13:30 +02:00

5006 lines
206 KiB
C#

using Microsoft.EntityFrameworkCore;
using MP.Core.Conf;
using MP.Core.DTO;
using MP.Core.Objects;
using MP.Data;
using MP.Data.Controllers;
using MP.Data.DbModels;
using MP.Data.DbModels.Anag;
using MP.Data.MgModels;
using MP.Data.Services.IOC;
using MP.Data.Services.Mtc;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using static MP.Core.Objects.Enums;
namespace MP.IOC.Data
{
public class MpDataService : IDisposable
{
#region Public Constructors
public MpDataService(
IConfiguration configuration,
ILogger<MpDataService> logger,
IServiceScopeFactory scopeFactory,
IMtcSetupService mtcServ)
{
_logger = logger;
_logger.LogInformation("Starting MpDataService INIT");
_configuration = configuration;
_scopeFactory = scopeFactory;
// setup compoenti REDIS
redisConn = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("Redis"));
redisConnAdmin = ConnectionMultiplexer.Connect(_configuration.GetConnectionString("RedisAdmin"));
redisDb = redisConn.GetDatabase();
BroadastMsgPipe = new MessagePipe(redisConn, Constants.BROADCAST_M_PIPE);
// leggo cache (lungo periodo e corto periodo)
int.TryParse(_configuration.GetValue<string>("ServerConf:redisLongTimeCache"), out redisLongTimeCache);
int.TryParse(_configuration.GetValue<string>("ServerConf:redisShortTimeCache"), out redisShortTimeCache);
Log.Info($"Redis INIT | redisLongTimeCache: {redisLongTimeCache} min | redisShortTimeCache {redisShortTimeCache} min");
// gestione scope factory
useFactory = _configuration.GetValue<bool>("ServerConf:useFactory");
// conf base x servizi condivisi IO/IOC
MpIoNS = _configuration.GetValue<string>("ServerConf:MpIoNS") ?? "MP";
Log.Info($"MpDataService | useFactory {useFactory} | MpIoNS {MpIoNS}");
// conf DB
string connStr = _configuration.GetConnectionString("MP.Data") ?? "";
if (string.IsNullOrEmpty(connStr))
{
Log.Error("DbController: ConnString empty!");
}
else
{
SpecDbController = new MpSpecController(configuration);
IocDbController = new MpIocController(configuration);
Log.Info("DbControllers INIT OK");
}
MtcService = mtcServ;
// conf mongo...
connStr = _configuration.GetConnectionString("mdbConnString") ?? "";
if (string.IsNullOrEmpty(connStr))
{
Log.Error("MongoController: ConnString empty!");
}
else
{
mongoController = new MpMongoController(configuration);
Log.Info("MongoController INIT OK");
}
}
#endregion Public Constructors
#region Public Properties
public static MpIocController IocDbController { get; set; } = null!;
public static MpMongoController mongoController { get; set; } = null!;
public static MpSpecController SpecDbController { get; set; } = null!;
public MessagePipe BroadastMsgPipe { get; set; } = null!;
/// <summary>
/// Dizionario dei tag configurati per IOB
/// </summary>
public Dictionary<string, List<TagData>> currTagConf { get; set; } = new Dictionary<string, List<TagData>>();
#endregion Public Properties
#region Public Methods
/// <summary>
/// Recupera eventuali azioni richieste
/// </summary>
/// <returns></returns>
public async Task<DisplayAction> ActionGetReq()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
DisplayAction? result = null;
// cerco in redis...
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisActionReq);
if (!string.IsNullOrEmpty($"{rawData}"))
{
result = JsonConvert.DeserializeObject<DisplayAction>($"{rawData}");
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ActionGetReq Read from REDIS: {ts.TotalMilliseconds}ms");
}
if (result == null)
{
result = new DisplayAction();
}
return result;
}
/// <summary>
/// Salva richiesta azione
/// </summary>
/// <param name="act2save"></param>
/// <returns></returns>
public bool ActionSetReq(DisplayAction? act2save)
{
bool fatto = false;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// cerco in redis...
string rawData = JsonConvert.SerializeObject(act2save);
// invio broadcast + salvo in redis
BroadastMsgPipe.saveAndSendMessage(Utils.redisActionReq, rawData);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ActionSetReq REDIS send to broadcast + Write cache: {ts.TotalMilliseconds}ms");
return fatto;
}
/// <summary>
/// Verifica se sia da reinviare un tName alla macchina dall'elenco di quelli salvati (in
/// modalità upsert) se non scaduti
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="taskKey"></param>
/// <param name="taskVal"></param>
/// <returns></returns>
public bool AddCheckTask4Machine(string idxMacchina, taskType taskKey, string taskVal)
{
bool answ = false;
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
Log.Info($"addCheckTask4Machine idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}");
try
{
Dictionary<string, string> savedTask = mSavedTaskMacchina(idxMacchina);
// cerco valOut saved
string savedVal = savedTask[taskKey.ToString()];
// se ho un valOut != "" --> rimetto in coda di invio...
if (!string.IsNullOrEmpty(savedVal) && (savedVal != taskVal))
{
// leggo tName attuali...
Dictionary<string, string> currTask = mTaskMacchina(idxMacchina);
// rimetto in tName da eseguire...
currTask[taskKey.ToString()] = savedVal;
RedisSetHashDict(currHash, currTask);
answ = true;
Log.Info($"re-issued task4machine: idxMacchina: {idxMacchina} | taskKey: {taskKey} | savedVal: {savedVal}");
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in AddCheckTask4Machine{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Aggiunge un PARAMETRO OPZIONALE all'elenco di quelli salvati (in modalità upsert)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="taskKey"></param>
/// <param name="taskVal"></param>
/// <returns></returns>
public bool AddOptPar4Machine(string idxMacchina, string taskKey, string taskVal)
{
bool answ = false;
RedisKey currHash = Utils.RedKeyOptPar(idxMacchina, MpIoNS);
try
{
// leggo tName attuali...
var currVal = mOptParMacchina(idxMacchina);
// verifico se esista o se vada aggiunto...
if (currVal.ContainsKey(taskKey))
{
currVal[taskKey] = taskVal;
}
else
{
currVal.Add(taskKey, taskVal);
}
RedisSetHashDict(currHash, currVal);
answ = true;
}
catch (Exception exc)
{
Log.Error($"Eccezione in addOptPar4Machine{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Aggiunge un tName all'elenco di quelli salvati (in modalità upsert)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="taskKey"></param>
/// <param name="taskVal"></param>
/// <returns></returns>
public bool AddTask4Machine(string idxMacchina, Enums.taskType taskKey, string taskVal)
{
bool answ = false;
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
var currSavedParHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina, MpIoNS);
Dictionary<string, string> currTask = new Dictionary<string, string>();
Dictionary<string, string> savedTask = new Dictionary<string, string>();
try
{
// leggo tName attuali...
currTask = mTaskMacchina(idxMacchina);
if (currTask.ContainsKey($"{taskKey}"))
{
currTask[$"{taskKey}"] = taskVal;
}
else
{
currTask.Add($"{taskKey}", taskVal);
}
RedisSetHashDict(currHash, currTask);
answ = true;
Log.Info($"Task ADD | hash: {currHash} | idxMacchina: {idxMacchina} | taskKey: {taskKey} | taskVal: {taskVal}");
}
catch { }
// verifico in base al tipo di tName se fare backup...
switch (taskKey)
{
case Enums.taskType.setArt:
case Enums.taskType.setComm:
case Enums.taskType.setPzComm:
case Enums.taskType.setProg:
// leggo tName SALVATI attuali...
savedTask = mSavedTaskMacchina(idxMacchina);
savedTask[taskKey.ToString()] = taskVal;
RedisSetHashDict(currSavedParHash, savedTask);
answ = true;
break;
case Enums.taskType.endProd:
// salvo un DICT vuoto x resettare
savedTask = new Dictionary<string, string>();
RedisSetHashDict(currSavedParHash, savedTask);
answ = true;
break;
default:
break;
}
return answ;
}
/// <summary>
/// Aggiunge un set di task x macchina all'elenco di quelli salvati (in modalità upsert)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="taskKey"></param>
/// <param name="taskVal"></param>
/// <returns></returns>
public async Task<bool> AddTask4MacListAsync(string idxMacchina, Dictionary<Enums.taskType, string> taskDict)
{
bool answ = false;
bool needSaveParams = false;
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
var currSavedParHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina, MpIoNS);
Dictionary<string, string> currTask = new Dictionary<string, string>();
Dictionary<string, string> savedTask = new Dictionary<string, string>();
// leggo valori attuali...
currTask = await mTaskMacchinaAsync(idxMacchina);
// verifico processing dei ricevuti
foreach (var item in taskDict)
{
if (currTask.ContainsKey($"{item.Key}"))
{
currTask[$"{item.Key}"] = item.Value;
}
else
{
currTask.Add($"{item.Key}", item.Value);
}
Log.Trace($"Task ADD | hash: {currHash} | idxMacchina: {idxMacchina} | taskKey: {item.Key} | taskVal: {item.Value}");
// verifico in base al tipo di tName se fare backup...
switch (item.Key)
{
case Enums.taskType.setArt:
case Enums.taskType.setComm:
case Enums.taskType.setPzComm:
case Enums.taskType.setProg:
// leggo tName SALVATI attuali...
savedTask = mSavedTaskMacchina(idxMacchina);
savedTask[item.Key.ToString()] = item.Value;
needSaveParams = true;
break;
case Enums.taskType.endProd:
// salvo un DICT vuoto x resettare
savedTask = new Dictionary<string, string>();
needSaveParams = true;
break;
default:
break;
}
}
// salvo!
await RedisSetHashDictAsync(currHash, currTask);
answ = true;
if (needSaveParams)
{
await RedisSetHashDictAsync(currSavedParHash, savedTask);
}
return answ;
}
/// <summary>
/// Insert record allarme
/// </summary>
/// <param name="dtRif">Data evento</param>
/// <param name="idxMacchina">Idx macchina</param>
/// <param name="memAddress">area memoria</param>
/// <param name="memAddress">indice memoria</param>
/// <param name="memAddress">valOut status</param>
/// <param name="memAddress">valOut decodificato</param>
/// <returns></returns>
public async Task<bool> AlarmInsertAsync(DateTime dtRif, string idxMacchina, string memAddress, int memIndex, int statusVal, string valDecoded)
{
// aggiorno record sul DB
bool answ = await IocDbController.AlarmLogInsertAsync(dtRif, idxMacchina, memAddress, memIndex, statusVal, valDecoded);
return answ;
}
public async Task<List<ListValuesModel>> AnagStatiComm()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
List<ListValuesModel>? result = new List<ListValuesModel>();
// cerco in redis...
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisStatoCom);
if (!string.IsNullOrEmpty($"{rawData}"))
{
result = JsonConvert.DeserializeObject<List<ListValuesModel>>($"{rawData}");
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"AnagStatiComm Read from REDIS: {ts.TotalMilliseconds}ms");
}
else
{
result = await Task.FromResult(SpecDbController.AnagStatiComm());
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(Utils.redisStatoCom, rawData, getRandTOut(redisLongTimeCache));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"AnagStatiComm Read from DB: {ts.TotalMilliseconds}ms");
}
if (result == null)
{
result = new List<ListValuesModel>();
}
return result;
}
/// <summary>
/// Restituisce l'anagrafica STATI per intero
/// </summary>
/// <returns></returns>
public async Task<List<AnagStatiModel>> AnagStatiGetAllAsync()
{
List<AnagStatiModel> dbResult = new List<AnagStatiModel>();
// cerco in redis...
var currKey = Utils.redisAnagStati;
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
dbResult = JsonConvert.DeserializeObject<List<AnagStatiModel>>($"{rawData}") ?? new();
}
else
{
dbResult = await IocDbController.AnagStatiGetAllAsync();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(dbResult);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
return dbResult;
}
public async Task<List<ListValuesModel>> AnagTipoArtLV()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string source = "DB";
List<ListValuesModel>? result = new List<ListValuesModel>();
// cerco in redis...
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisTipoArt);
if (!string.IsNullOrEmpty($"{rawData}"))
{
result = JsonConvert.DeserializeObject<List<ListValuesModel>>($"{rawData}");
source = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.AnagTipoArtLV());
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(Utils.redisTipoArt, rawData, getRandTOut(redisLongTimeCache));
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"AnagTipoArtLV Read from {source}: {ts.TotalMilliseconds}ms");
if (result == null)
{
result = new List<ListValuesModel>();
}
return result;
}
/// <summary>
/// Elenco Codice articolo con dati dossier gestiti
/// </summary>
/// <returns></returns>
public async Task<List<string>> ArticleWithDossier()
{
List<string>? result = new List<string>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = Utils.redisArtByDossier;
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.ArticleWithDossier());
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<string>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ArticleWithDossier | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Eliminazione record selezionato
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public async Task<bool> ArticoliDeleteRecord(AnagArticoliModel currRec)
{
bool fatto = await SpecDbController.ArticoliDeleteRecord(currRec);
await resetCacheArticoli();
return fatto;
}
/// <summary>
/// Elenco ultimi articoli data amcchina
/// </summary>
/// <param name="idxMacc"></param>
/// <returns></returns>
public async Task<List<AnagArticoliModel>> ArticoliGetLastByMaccAsync(string idxMacc)
{
List<AnagArticoliModel>? result = new List<AnagArticoliModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisArtList}:Last:{idxMacc}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<AnagArticoliModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await IocDbController.ArticoliGetLastByMaccAsync(idxMacc);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<AnagArticoliModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ArticoliGetLastByMaccAsync | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Restitusice elenco articoli cercati
/// </summary>
/// <param name="numRecord"></param>
/// <param name="searchVal"></param>
/// <returns></returns>
public async Task<List<AnagArticoliModel>> ArticoliGetSearch(int numRecord, string azienda, string searchVal)
{
List<AnagArticoliModel>? result = new List<AnagArticoliModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string sKey = string.IsNullOrEmpty(searchVal) ? "***" : searchVal;
string currKey = $"{Utils.redisArtList}:{azienda}:{sKey}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<AnagArticoliModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.ArticoliGetSearch(numRecord, azienda, searchVal));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
}
if (result == null)
{
result = new List<AnagArticoliModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ArticoliGetSearch | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Aggiornamento record selezionato
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public async Task<bool> ArticoliUpdateRecord(AnagArticoliModel currRec)
{
bool fatto = await SpecDbController.ArticoliUpdateRecord(currRec);
await resetCacheArticoli();
return fatto;
}
/// <summary>
/// Verifica se sia possiubile cancellare articolo dato suo CodArt cercando su redis o su
/// tab veto da DB
/// </summary>
/// <param name="CodArt"></param>
/// <returns></returns>
public bool ArticoloDelEnabled(object CodArt)
{
bool answ = false;
string codArticolo = $"{CodArt}";
int cacheCheckArtUsato = 1;
int.TryParse(_configuration.GetValue<string>("ServerConf:cacheCheckArtUsato"), out cacheCheckArtUsato);
TimeSpan TTLCache = getRandTOut(cacheCheckArtUsato);
// cerco in cache redis...
string redKeyArtUsed = $"{Utils.redKeyArtUsed}:{codArticolo}";
string redKeyTabCheckArt = Utils.redKeyTabCheckArt;
var rawData = redisDb.StringGet(redKeyArtUsed);
if (!string.IsNullOrEmpty(rawData))
{
bool.TryParse(rawData, out answ);
}
else
{
// controllo non sia stato mai prodotto sennò non posso cancellare...
try
{
// cerco in cache se ci sia la tabella con gli articoli impiegati...
var rawTable = redisDb.StringGet(redKeyTabCheckArt);
List<string>? artList = new List<string>();
if (!string.IsNullOrEmpty(rawTable))
{
artList = JsonConvert.DeserializeObject<List<string>>($"{rawTable}");
}
// rileggo...
if (artList == null || artList.Count == 0)
{
artList = new List<string>();
var tabArticoli = SpecDbController.ArticoliGetUsed();
var codList = tabArticoli.Select(x => x.CodArticolo);
foreach (string cod in codList)
{
artList.Add(cod);
}
// SE fosse vuoto aggiungo comunque il cado "ND"...
if (artList.Count == 0)
{
artList.Add("ND");
}
// salvo
rawTable = JsonConvert.SerializeObject(artList);
redisDb.StringSet(redKeyTabCheckArt, rawTable, TTLCache);
}
// cerco nella tabella: se ci fosse --> disabilitato delete
bool usato = false;
if (artList != null && artList.Count > 0)
{
usato = artList.Contains(codArticolo);
}
answ = !usato;
redisDb.StringSet(redKeyArtUsed, $"{answ}", TTLCache);
}
catch
{ }
}
return answ;
}
/// <summary>
/// Effettua split ODL
/// </summary>
/// <param name="idxMacchina">macchina</param>
/// <param name="doConfirm">effettuare conferma qty</param>
/// <param name="qtyFromLast">imposta la qty prox ODL da ODL che si chiude</param>
/// <param name="matrOpr">matricola operatore</param>
/// <param name="roundStep">Round Step quantità prox ODL (corrente come riferimento)</param>
/// <param name="keyRichiesta">Cod ext da associare all'ODL</param>
/// <returns></returns>
public async Task<string> AutoStartOdlAsync(string idxMacchina, bool doConfirm, bool qtyFromLast, int matrOpr, int roundStep = 100, string keyRichiesta = "")
{
string answ = "KO";
DateTime adesso = DateTime.Now;
// verifico NON CI SIA un veto a NUOVI split...
string redKey = $"{Utils.redisVetoSplitOdl}:{idxMacchina}";
var rawData = await redisDb.StringGetAsync(redKey);
if (rawData.HasValue)
{
Log.Info($"VETO ATTIVO | Richiesto forceSplitOdl per impianto {idxMacchina} | impossibile procedere");
}
else
{
// registro VETO x altri split... 5 minuti
await redisDb.StringSetAsync(redKey, $"Inizio SPLIT-ODL {adesso}", TimeSpan.FromMinutes(5));
// setup dati da config
bool confRett = false;
int modoConfProd = -1;
bool slaveConfirmPzProd = false;
var configData = await ConfigGetAllAsync();
if (configData != null)
{
var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
if (currRec != null)
{
bool.TryParse(currRec.Valore, out confRett);
}
currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
if (currRec != null)
{
int.TryParse(currRec.Valore, out modoConfProd);
}
currRec = configData.FirstOrDefault(x => x.Chiave == "SlaveConfirmPzProd");
if (currRec != null)
{
bool.TryParse(currRec.Valore, out slaveConfirmPzProd);
}
}
// calcolo la qta da gestire
int qtyConf = 0;
int qtyNew = 0;
int qtyScarto = 0;
if (doConfirm)
{
try
{
var rigaProd = await IocDbController.PezziProdMacchinaAsync(idxMacchina);
var statoProd = await IocDbController.StatoProdMacchinaAsync(idxMacchina, adesso);
qtyConf = rigaProd.pezziNonConfermati;
qtyScarto = statoProd.Pz2RecScarto;
// calcolo nuovi pezzi da confermare
if (qtyFromLast)
{
roundStep = roundStep == 0 ? 1 : roundStep;
double ratio = (double)qtyConf / roundStep;
qtyNew = (int)Math.Round(Math.Ceiling(ratio) * roundStep, 0);
}
}
catch (Exception exc)
{
Log.Error($"AutoStartOdlAsync | Errore recupero pezzi da confermare | idxMacchina {idxMacchina}{Environment.NewLine}{exc}");
}
}
// chiamo metodo redis/db...
try
{
// recupero ODL corrente
var currData = await IocDbController.OdlCurrByMaccAsync(idxMacchina);
if (currData != null && currData.IdxOdl > 0)
{
// preparo var x master/slave
bool isMachMaster = await IobIsMasterAsync(idxMacchina);
List<Macchine2SlaveModel> slaveList = new();
if (isMachMaster)
{
List<Macchine2SlaveModel> allSlaveList = await IocDbController.Macchine2SlaveAsync();
slaveList = allSlaveList.Where(x => x.IdxMacchina == idxMacchina).ToList();
}
// registro un evento di inizio attrezzaggio (idxTipoEv = 2)
int idxEvento = 2;
Log.Info($"Invio evento ODL-SPLIT per macchina {idxMacchina} | ev: {idxEvento} | art: {currData.CodArticolo} | qty conf: {qtyConf} | sty sca: {qtyScarto} | new qty: {qtyNew}");
// creo evento
EventListModel newRecEv = new EventListModel()
{
CodArticolo = currData.CodArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxEvento,
InizioStato = adesso,
MatrOpr = matrOpr,
pallet = "",
Value = "ODL-SPLIT"
};
inputComandoMapo resCmd = await scriviRigaEventoBarcodeAsync(newRecEv);
// era 100, messo 50...
int wTime = 50;
// eventuale conferma produzione
if (doConfirm)
{
await Task.Delay(wTime);
adesso = DateTime.Now;
// chiamo conferma produzione...
try
{
string chiamata = confRett ? "confermaProdMacchinaFull" : "confermaProdMacchina";
Log.Info($"Chiamata a {chiamata} con parametri {currData.IdxMacchina} |{matrOpr} | {DateTime.Now.AddDays(-10)} | {DateTime.Now} | {qtyConf} | 0 | {qtyScarto} | {DateTime.Now} | false");
string idxMacchinaSel = currData.IdxMacchina;
bool fatto = false;
if (confRett)
{
// confermo al netto dei pezzi lasciati...
fatto = await IocDbController.ConfermaProdMacchinaFullAsync(idxMacchinaSel, modoConfProd, qtyConf, 0, qtyScarto, adesso, matrOpr);
if (slaveConfirmPzProd)
{
foreach (var machine in slaveList)
{
await IocDbController.ConfermaProdMacchinaFullAsync(machine.IdxMacchinaSlave, modoConfProd, qtyConf, 0, qtyScarto, adesso, matrOpr);
}
}
}
else
{
fatto = await IocDbController.ConfermaProdMacchinaAsync(idxMacchinaSel, modoConfProd, qtyConf, qtyScarto, adesso, matrOpr);
if (slaveConfirmPzProd)
{
foreach (var machine in slaveList)
{
await IocDbController.ConfermaProdMacchinaAsync(idxMacchinaSel, modoConfProd, qtyConf, qtyScarto, adesso, matrOpr);
}
}
}
if (!fatto)
{
Log.Error($"ERRORE in chiamata {chiamata}");
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in ConfermaProduzione{Environment.NewLine}{exc}");
}
}
// 2025.02.19 portato da 100 a 1000 ms attesa x evitare che ODL sia avviato PRIMA della conferma
// attendo 1000 msec x chiudere ODL
await Task.Delay(1000);
// chiamo splitOdl
await IocDbController.AutoStartOdlAsync(currData.IdxOdl, 0, idxMacchina, currData.TCRichAttr, currData.PzPallet, $"Nuovo ODL da forceSplitOdl.autoStart", true, qtyNew, keyRichiesta);
// elimino eventuale ODL precedente...
string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
await redisDb.KeyDeleteAsync(currKey);
// ricalcola ODL macchina
var newOdl = await GetCurrOdlAsync(idxMacchina);
// attendo 1000 msec
await Task.Delay(1000);
adesso = DateTime.Now;
// registro fine ODL (idxTipoEv = 1)
idxEvento = 1;
Log.Info($"Invio evento FINE ODL-SPLIT | idx: {idxMacchina} | ev: {idxEvento} | art: {currData.CodArticolo}");
// costruisco nuovo evento
newRecEv = new EventListModel()
{
CodArticolo = currData.CodArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxEvento,
InizioStato = adesso,
MatrOpr = matrOpr,
pallet = "",
Value = "ODL-START"
};
resCmd = await scriviRigaEventoBarcodeAsync(newRecEv);
// invio eventi setup a macchina....
string setArtVal = $"{currData.CodArticolo}";
string setPzCommVal = $"{qtyNew}";
string setCommVal = $"ODL{newOdl}";
if (!string.IsNullOrEmpty(keyRichiesta))
{
setCommVal = $"{keyRichiesta} ODL{newOdl}";
}
try
{
// invio task caricamento dati ODL
Dictionary<taskType, string> updDict = new Dictionary<taskType, string>();
updDict.Add(taskType.setArt, setArtVal);
updDict.Add(taskType.setComm, setCommVal);
updDict.Add(taskType.setPzComm, setPzCommVal);
#if false
addTask4Machine(idxMacchina, taskType.setArt, setArtVal);
addTask4Machine(idxMacchina, taskType.setComm, setCommVal);
addTask4Machine(idxMacchina, taskType.setPzComm, setPzCommVal);
updateMachineParameter(idxMacchina, "setArt", setArtVal);
updateMachineParameter(idxMacchina, "setComm", setCommVal);
updateMachineParameter(idxMacchina, "setPzComm", setPzCommVal);
#endif
// recupero set attuale parametri
var currMachPar = await MachineParamListAsync(idxMacchina);
List<ObjItemDTO> list2upd = new();
// aggiorno i valori interessati tra quelli nel dizionario
foreach (var item in updDict)
{
var cRec = currMachPar.FirstOrDefault(x => x.uid == $"{item.Key}");
if (cRec != null)
{
list2upd.Add(cRec);
}
}
// aggiungo task di setParameters x la commessa...
updDict.Add(taskType.setParameter, setCommVal);
// salvo
await AddTask4MacListAsync(idxMacchina, updDict);
await MachineParamUpsertAsync(idxMacchina, list2upd);
}
catch
{ }
// chiamo refresh MSE
await IocDbController.RecalcMseAsync(idxMacchina, 0);
// resetto stato macchina...
var kStatoMacc = $"{Utils.redisStatoMacch}:{idxMacchina}";
await redisDb.KeyDeleteAsync(kStatoMacc);
answ = "OK";
Log.Info($"Effettuato reset e ricalcoli x split ODL per macchina {idxMacchina}");
// se è una master richiamo fix x child...
if (isMachMaster)
{
Dictionary<taskType, string> updDict = new Dictionary<taskType, string>();
string ts = "";
string outData = "";
await IocDbController.OdlFixMachineSlaveAsync(idxMacchina, 30, 1);
foreach (var machine in slaveList)
{
// invio chiusura attrezzaggio
ts = string.Format("{0:yyMMdd}T{0:HHmmss.fff}Z", DateTime.Now);
outData = $"TS:{ts}|MATR:{matrOpr}|ODL:{newOdl}";
updDict.Clear();
updDict.Add(taskType.setArt, setArtVal);
updDict.Add(taskType.setComm, setCommVal);
updDict.Add(taskType.setPzComm, setPzCommVal);
#if false
addTask4Machine(machine.IdxMacchinaSlave, taskType.fixStopSetup, outData);
addTask4Machine(machine.IdxMacchinaSlave, taskType.forceResetPzCount, outData);
// invio task caricamento dati ODL
addTask4Machine(machine.IdxMacchinaSlave, taskType.setArt, setArtVal);
addTask4Machine(machine.IdxMacchinaSlave, taskType.setComm, setCommVal);
addTask4Machine(machine.IdxMacchinaSlave, taskType.setPzComm, setPzCommVal);
updateMachineParameter(machine.IdxMacchinaSlave, "setArt", setArtVal);
updateMachineParameter(machine.IdxMacchinaSlave, "setComm", setCommVal);
updateMachineParameter(machine.IdxMacchinaSlave, "setPzComm", setPzCommVal);
#endif
// recupero set attuale parametri
var currMachPar = await MachineParamListAsync(machine.IdxMacchinaSlave);
List<ObjItemDTO> list2upd = new();
// aggiorno i valori interessati tra quelli nel dizionario
foreach (var item in updDict)
{
var cRec = currMachPar.FirstOrDefault(x => x.uid == $"{item.Key}");
if (cRec != null)
{
list2upd.Add(cRec);
}
}
// aggiungo task di setParameters x la commessa...
updDict.Add(taskType.fixStopSetup, outData);
updDict.Add(taskType.forceResetPzCount, outData);
updDict.Add(taskType.setParameter, setCommVal);
// salvo
await AddTask4MacListAsync(machine.IdxMacchinaSlave, updDict);
await MachineParamUpsertAsync(machine.IdxMacchinaSlave, list2upd);
}
}
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}");
}
}
return answ;
}
public string CalcRecipe(RecipeModel currRecipe)
{
return mongoController.CalcRecipe(currRecipe);
}
/// <summary>
/// controlla se da il segnale di "microstato" deriva un evento da generare - modalità OFFLINE
/// </summary>
/// <param name="idxMacchina">idx macchina</param>
/// <param name="valore">valOut ingresso</param>
/// <param name="dtEve">data-ora evento (server)</param>
/// <param name="contatore">sequenza dati inviati</param>
/// <param name="datiMaccCache">dati macchina in cache (opzionale, se null fa lookup)</param>
/// <returns></returns>
public async Task<inputComandoMapo> CheckMicroStatoAsync(string idxMacchina, string valore, DateTime dtEve, string contatore, Dictionary<string, string>? datiMaccCache = null)
{
// recupero SE IMPIEGATO REDIS i valori del Dictionary della macchina...
Dictionary<string, string> datiMacc = datiMaccCache ?? await mDatiMacchineAsync(idxMacchina);
// processing
inputComandoMapo answ = new inputComandoMapo();
// SE no trovassi verifico se esista la macchina altrimenti la creo... REDIS compliant
if (!datiMacc.ContainsKey(idxMacchina))
{
await verificaIdxMacchinaAsync(idxMacchina);
}
// continuo processing...
string CodArticolo = datiMacc["CodArticolo"];
if (string.IsNullOrEmpty(CodArticolo))
{
var allDatiMacch = await IocDbController.DatiMacchineGetAllAsync();
var recMacc = allDatiMacch.FirstOrDefault(x => x.IdxMacchina == idxMacchina);
if (recMacc != null)
{
CodArticolo = recMacc.CodArticoloA;
}
}
// preparo gestione val ingresso
int? valINT = 0;
int idxTipoEv = 0;
int next_idxMS = 0;
try
{
valINT = int.Parse(valore, NumberStyles.HexNumber);
int idxFamIn = Convert.ToInt32(datiMacc["IdxFamIn"]);
int idxMicroStato = Convert.ToInt32(datiMacc["IdxMicroStato"]);
int valIOB = Convert.ToInt32(valINT);
next_idxMS = idxMicroStato;
// recupero singolo valOut (stringa) x chiave
string todoSMI = await ValoreSmiAsync(idxFamIn, idxMicroStato, valIOB);
// solo se ho trovato un risultato nella tab SMI della famiglia macchina...
if (!string.IsNullOrEmpty(todoSMI) && todoSMI.Contains("_"))
{
// splitto e salvo valori OUT...
string[] valori = todoSMI.Split('_');
idxTipoEv = Convert.ToInt32(valori[0]);
next_idxMS = Convert.ToInt32(valori[1]);
}
}
catch (Exception exc)
{
Log.Error($"[ChkMiSt_5a] - - Eccezione in recupero riga Trans ingressi | idxMacchina {idxMacchina} | valINT {valINT}:{Environment.NewLine}{exc}", Environment.NewLine, exc, valINT, idxMacchina);
}
// effettuo update vari SU DB!!!
MicroStatoMacchinaModel newRecMsm = new MicroStatoMacchinaModel()
{
IdxMacchina = idxMacchina,
IdxMicroStato = next_idxMS,
InizioStato = dtEve,
Value = valore
};
if (idxTipoEv > 0)
{
// preparo record
string valEsteso = string.Format("[{0}] {1}", contatore.PadLeft(3, '0'), valore);
// creo evento
EventListModel newRecEv = new EventListModel()
{
CodArticolo = CodArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxTipoEv,
InizioStato = dtEve,
MatrOpr = 0,
pallet = "-",
Value = valEsteso
};
// salva e processa evento + microstato
answ = await scriviRigaEventoAsync(newRecMsm, newRecEv);
}
else
{
if (useFactory)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var iocService = scope.ServiceProvider.GetRequiredService<IIocService>();
// solo microstato
await iocService.MicroStatoMacchinaUpsertAsync(newRecMsm);
}
else
{
// solo microstato
await IocDbController.MicroStatoMacchinaUpsertAsync(newRecMsm);
}
}
return answ;
}
public async Task<List<ConfigModel>> ConfigGetAllAsync()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
List<ConfigModel>? result = new List<ConfigModel>();
// cerco in redis...
RedisValue rawData = await redisDb.StringGetAsync(Utils.redisConfKey);
if (!string.IsNullOrEmpty($"{rawData}"))
{
result = JsonConvert.DeserializeObject<List<ConfigModel>>($"{rawData}");
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ConfigGetAllAsync Read from REDIS: {ts.TotalMilliseconds}ms");
}
else
{
result = await IocDbController.ConfigGetAllAsync();
//result = await Task.FromResult(SpecDbController.ConfigGetAllAsync());
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(Utils.redisConfKey, rawData, getRandTOut(redisLongTimeCache));
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ConfigGetAllAsync Read from DB: {ts.TotalMilliseconds}ms");
}
if (result == null)
{
result = new List<ConfigModel>();
}
return result;
}
/// <summary>
/// Reset dati cache config
/// </summary>
/// <returns></returns>
public async Task ConfigResetCache()
{
await redisDb.StringSetAsync(Utils.redisConfKey, "");
}
/// <summary>
/// Update chiave config
/// </summary>
/// <returns></returns>
public async Task<bool> ConfigUpdate(ConfigModel updRec)
{
return await Task.FromResult(SpecDbController.ConfigUpdate(updRec));
}
/// <summary>
/// Elenco completo valori DatiMacchine
/// </summary>
/// <returns></returns>
public async Task<List<DatiMacchineModel>> DatiMacchineGetAll()
{
List<DatiMacchineModel>? result = new List<DatiMacchineModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisBaseAddr}:TabDatiMacchine:ALL";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<DatiMacchineModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.DatiMacchineGetAll());
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<DatiMacchineModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"DatiMacchineGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
public async Task<List<DecNumArticoliModel>> DecNumArtGetFiltAsync(string codArt = "")
{
List<DecNumArticoliModel> result = new();
string tag = string.IsNullOrEmpty(codArt) ? "ALL" : codArt;
string currKey = $"{Utils.redisDecNumArtKey}:{tag}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<DecNumArticoliModel>>($"{rawData}") ?? new();
}
else
{
result = await IocDbController.DecNumArtGetFiltAsync(codArt);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
return result;
}
/// <summary>
/// Dispose del connettore ai dati
/// </summary>
public void Dispose()
{
// Clear database controller
SpecDbController.Dispose();
mongoController.Dispose();
redisConn.Dispose();
}
/// <summary>
/// Restituisce l'elenco delle date dei dossier x una macchina (se presenti) Impiegata anche
/// cache redis
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<List<DossierModel>> DossierLastByMachAsync(string idxMacchina)
{
List<DossierModel> result = new List<DossierModel>();
var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<DossierModel>>($"{rawData}") ?? new();
}
else
{
result = await IocDbController.DossGetLastByMaccAsync(idxMacchina);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<DossierModel>();
}
return result;
}
/// <summary>
/// Eliminazione di un dossier
/// </summary>
/// <param name="selRecord">record dossier da eliminare</param>
/// <returns></returns>
public async Task<bool> DossiersDeleteRecord(DossierModel selRecord)
{
bool result = false;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
result = await SpecDbController.DossiersDeleteRecord(selRecord);
// elimino cache redis...
RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
bool answ = await RedisFlushPatternAsync(pattern);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"DossiersDeleteRecord | IdxMacchina {selRecord.IdxMacchina} | DtRif {selRecord.DtRif} | IdxODL {selRecord.IdxODL} | {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Elenco ultimi n record DOssiers (che contengono ad esempio "salvataggi" di FLuxLog) dato
/// macchina (ordinato x data registrazione)
/// </summary>
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data macchina</param>
/// <param name="DtStart">Data minima per estrazione records</param>
/// <param name="DtEnd">Data Massima per estrazione records</param>
/// <param name="MaxRec">Num Max records da recuperare</param>
/// <returns></returns>
public async Task<List<DossierModel>> DossiersGetLastFilt(string IdxMacchina, string CodArticolo, DateTime DtStart, DateTime DtEnd, int MaxRec)
{
List<DossierModel>? result = new List<DossierModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisDossByMac}:{IdxMacchina}:{CodArticolo}:{DtStart:yyyyMMddHHmm}:{DtEnd:yyyyMMddHHmm}:{MaxRec}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<DossierModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await SpecDbController.DossiersGetLastFiltAsync(IdxMacchina, CodArticolo, DtStart, DtEnd, MaxRec);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
}
if (result == null)
{
result = new List<DossierModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"DossiersGetLastFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Inserimento nuovo record dossier
/// </summary>
/// <param name="currDoss"></param>
/// <returns></returns>
public async Task<bool> DossiersInsert(DossierModel currDoss)
{
// aggiorno record sul DB
bool answ = await SpecDbController.DossiersInsert(currDoss);
return answ;
}
/// <summary>
/// Effettua salvataggio snapshot parametri (con stored) + svuota eventuale cache redis
/// </summary>
/// <param name="IdxMacchina">macchina</param>
/// <param name="MaxSec">NUm massimo secondi per recuperare dati correnti</param>
/// <param name="DtRif">DataOra riferimento x cui prendere valori antecedenti</param>
/// <returns></returns>
public async Task<bool> DossiersTakeParamsSnapshotLast(string IdxMacchina, DateTime dtMin, DateTime dtMax)
{
bool answ = false;
await Task.Delay(1);
Log.Info($"Richiesta snapshot per macchina {IdxMacchina} | periodo {dtMin} --> {dtMax}");
// chiamo stored x salvare parametri
SpecDbController.DossiersTakeParamsSnapshotLast(IdxMacchina, dtMin, dtMax);
// elimino cache redis...
RedisValue pattern = new RedisValue($"{Utils.redisDossByMac}:*");
answ = await RedisFlushPatternAsync(pattern);
Log.Info($"Svuotata cache dossier | {pattern}");
return answ;
}
/// <summary>
/// Update valOut dossier
/// </summary>
/// <param name="currDoss"></param>
/// <returns></returns>
public async Task<bool> DossiersUpdateValore(DossierModel currDoss)
{
// aggiorno record sul DB
bool answ = await SpecDbController.DossiersUpdateValore(currDoss);
return answ;
}
/// <summary>
/// Restitusice elenco aziende
/// </summary>
/// <returns></returns>
public Task<List<AnagGruppiModel>> ElencoAziende()
{
return Task.FromResult(SpecDbController.AnagGruppiAziende());
}
/// <summary>
/// Restitusice elenco fasi
/// </summary>
/// <returns></returns>
public Task<List<AnagGruppiModel>> ElencoGruppiFase()
{
List<AnagGruppiModel> result = new List<AnagGruppiModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisAnagGruppi}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
var rawResult = JsonConvert.DeserializeObject<List<AnagGruppiModel>>($"{rawData}");
if (rawResult != null)
{
result = rawResult;
}
readType = "REDIS";
}
else
{
result = SpecDbController.AnagGruppiFase();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache / 5));
}
if (result == null)
{
result = new List<AnagGruppiModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ElencoGruppiFase | Read from {readType}: {ts.TotalMilliseconds}ms");
return Task.FromResult(result);
}
public Task<List<LinkMenuModel>> ElencoLink()
{
return Task.FromResult(SpecDbController.ElencoLink());
}
/// <summary>
/// Aggiunta record EventList
/// </summary>
/// <param name="newRec"></param>
/// <returns></returns>
public async Task<bool> EvListInsert(EventListModel newRec)
{
return await SpecDbController.EvListInsert(newRec);
}
/// <summary>
/// Imposta in redis la scadenza della pagina x il reload
/// </summary>
/// <param name="expTime"></param>
/// <returns></returns>
public DateTime ExpiryReloadParamGet()
{
DateTime dtRif = DateTime.Now;
string currKey = $"{Utils.redisParamPageExp}";
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
dtRif = JsonConvert.DeserializeObject<DateTime>($"{rawData}");
}
return dtRif;
}
/// <summary>
/// Imposta in redis la scadenza della pagina x il reload
/// </summary>
/// <param name="expTime"></param>
/// <returns></returns>
public bool ExpiryReloadParamSet(DateTime expTime)
{
bool fatto = false;
string currKey = $"{Utils.redisParamPageExp}";
string rawData = JsonConvert.SerializeObject(expTime);
fatto = redisDb.StringSet(currKey, rawData);
return fatto;
}
/// <summary>
/// Task completo sistemazione dossier quotidiani mancanti
/// </summary>
/// <param name="idxMacc"></param>
/// <returns></returns>
public async Task<string> FixDailyDossierAsync(string idxMacc)
{
string answ = "";
// verifico se si possa processare, ovvero tab ConfFlux x macchina sia valorizzata...
var confDataMach = await ConfFluxMach(idxMacc);
if (confDataMach.Count > 0)
{
// determino ultima data da processare (inizio oggi, a mezzanotte)
DateTime dtTo = DateTime.Today;
DateTime dtFrom = dtTo;
// determino data di partenza, prima da dossier esistenti
var listaDoss = await DossierLastByMachAsync(idxMacc);
if (listaDoss.Count > 0)
{
// primo giorno DOPO ultima registrazione
dtFrom = listaDoss
.Select(x => x.DtRif)
.OrderByDescending(x => x)
.FirstOrDefault()
.AddDays(1);
}
else
{
// ...o da fluxLog acquisiti...
var listaFL = await FluxLogFirstByMachAsync(idxMacc);
if (listaFL.Count > 0)
{
// giorno successivo a prima registrazione
dtFrom = listaFL
.OrderBy(x => x)
.FirstOrDefault()
.AddDays(1);
}
}
string caller = $"takeFlogSnapshot({idxMacc})";
DateTime dtStart = dtFrom.Date;
DateTime dtEnd = dtFrom;
// max 10 dossier alla volta (se non configurato diversamente)
int maxAdd = 1;
string confVal = await tryGetConfigAsync("IO_numDossMaxCreate");
if (!string.IsNullOrEmpty(confVal))
{
int.TryParse(confVal, out maxAdd);
}
if (dtStart < dtTo)
{
// verifico di avere almeno 1 dossier da produrre ciclo fino ad esaurire le
// date da processare
while (dtStart < dtTo && maxAdd > 0)
{
// sistemo end
dtEnd = dtStart.AddDays(1);
// effettuo chiamata registrazione snapshot!
answ = await FluxLogSaveSnapshotAsync(idxMacc, dtStart, dtEnd, caller);
// incremento START...
dtStart = dtEnd;
// riduco il numero di chiamate ammesse x singolo task
maxAdd--;
}
// reset cache dossier...
await DossierLastByMachResetAsync(idxMacc);
answ = "OK";
}
else
{
Log.Warn("FixDailyDossierAsync | NO more to add");
}
}
else
{
Log.Warn("FixDailyDossierAsync | NO ConfFluxData");
}
return answ;
}
public async Task<bool> FlushRedisCache()
{
await Task.Delay(1);
RedisValue pattern = Utils.RedValue("*");
bool answ = await RedisFlushPatternAsync(pattern);
// rileggo vocabolario.,..
ObjVocabolario = VocabolarioGetAll();
return answ;
}
public async Task<bool> FlushRedisKey(string redKey)
{
await Task.Delay(1);
RedisValue pattern = Utils.RedValue(redKey);
bool answ = await RedisFlushPatternAsync(pattern);
return answ;
}
public List<FluxLogDTO> FluxLogDtoGetByFlux(string Valore)
{
List<FluxLogDTO> answ = new List<FluxLogDTO>();
DossierFluxLogDTO? result = JsonConvert.DeserializeObject<DossierFluxLogDTO>(Valore);
if (result != null)
{
if (result.ODL != null)
{
answ = result
.ODL
.OrderBy(x => x.CodFlux)
.ToList();
// inizializzo SE necessario
foreach (var item in answ)
{
item.ValoreEdit = String.IsNullOrEmpty(item.ValoreEdit) ? item.Valore : item.ValoreEdit;
}
}
}
return answ;
}
/// <summary>
/// Elenco ultimi n record flux log dato macchina e flusso (ordinato x data registrazione)
/// </summary>
/// <param name="DtMax">Data massima x eventi</param>
/// <param name="DtMin">Data minima x eventi</param>
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data macchina</param>
/// <param name="CodFlux">*=tutti, altrimenti solo selezionato</param>
/// <param name="MaxRec">numero massimo record da restituire</param>
/// <returns></returns>
public async Task<List<FluxLogModel>> FluxLogGetLastFilt(DateTime DtMax, DateTime DtMin, string IdxMacchina, string CodFlux, int MaxRec, double redisCacheSec)
{
List<FluxLogModel>? result = new List<FluxLogModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisFluxLogFilt}:{IdxMacchina}:{CodFlux}:{MaxRec}:{DtMax:yyyyMMddHHmm}:{DtMin:yyyyMMddHHmm}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<FluxLogModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.FluxLogGetLastFilt(DtMax, DtMin, IdxMacchina, CodFlux, MaxRec));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
if (string.IsNullOrEmpty(canCacheParametri))
{
canCacheParametri = await tryGetConfigAsync("SPEC_ParametriEnableRedisCache");
}
if (canCacheParametri != "false")
{
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisCacheSec));
}
}
if (result == null)
{
result = new List<FluxLogModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"FluxLogGetLastFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
/// ODL NO invio/gestione ODL)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<string> GetCurrOdlAsync(string idxMacchina)
{
string result = "";
string currKey = $"{Utils.redisOdlCurrByMac}:{idxMacchina}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = $"{rawData}";
}
else
{
result = await GetCurrOdlByProdAsync(idxMacchina);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
return result;
}
/// <summary>
/// Restituisce il valOut dell'ODL corrente (ODL deve esserci per gestione contapezzi, senza
/// ODL NO invio/gestione ODL)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="forceDb">indica se forzare lettura da db (true) o meno</param>
/// <returns></returns>
public async Task<string> GetCurrOdlAsync(string idxMacchina, bool forceDb)
{
string answ = "";
// se ho forceDB leggo dai dati prod...
if (forceDb)
{
var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now, true);
if (datiProd != null)
{
answ = datiProd.IdxOdl.ToString();
}
}
else
{
answ = await GetCurrOdlAsync(idxMacchina);
}
return answ;
}
/// <summary>
/// Restituisce il valOut dell'ultimo ODL
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<ODLExpModel> GetLastOdlAsync(string idxMacchina)
{
ODLExpModel result = new ODLExpModel();
string currKey = $"{Utils.redisOdlLastByMac}:{idxMacchina}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<ODLExpModel>($"{rawData}") ?? new();
}
else
{
result = await IocDbController.OdlLastByMaccAsync(idxMacchina);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
return result;
}
/// <summary>
/// Effettua calcolo data-ora di riferimento per il server a partire da
/// </summary>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <returns></returns>
public DateTime GetSrvDtEvent(string dtEve, string dtCurr)
{
DateTime dataOraEvento = DateTime.Now;
// 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi...
dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve;
dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr;
DateTime dtEvento, dtCorrente;
// controllo: se ho valori dt x evento e orario DIVERSI per acquisitore IOB calcolo
// dataOraEvento corretto
if (dtEve != dtCurr)
{
Int64 delta = 0;
try
{
// se ho meno decimali x evento rispetto dtCorrente...
if (dtEve.Length < dtCurr.Length)
{
dtEve = dtEve.PadRight(dtCurr.Length, '0');
}
delta = Convert.ToInt64(dtCurr) - Convert.ToInt64(dtEve);
// se meno di 60'000 ms ...
if (delta < 59999)
{
dataOraEvento = dataOraEvento.AddMilliseconds(-delta);
}
else
{
// in questo caso elimino i MS dalle stringhe e converto i datetime....
CultureInfo provider = CultureInfo.InvariantCulture;
string format = "yyyyMMddHHmmssfff";
dtEvento = DateTime.ParseExact(dtEve, format, provider);
dtCorrente = DateTime.ParseExact(dtCurr, format, provider);
TimeSpan deltaTS = dtCorrente.Subtract(dtEvento);
dataOraEvento = dataOraEvento.Add(-deltaTS);
}
}
catch (Exception exc)
{
Log.Error($"getSrvDtEvent | Errore calcolo ora corrente da IOB remoto | dtEve: {dtEve} | dtCurr: {dtCurr}{Environment.NewLine}" +
$"{exc}");
}
}
return dataOraEvento;
}
/// <summary>
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<Dictionary<string, string>> GetTask2ExeMacchinaAsync(string idxMacchina)
{
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
return await RedisGetHashDictAsync(currHash);
}
/// <summary>
/// Init ricetta
/// </summary>
/// <param name="confPath"></param>
/// <param name="idxPODL"></param>
/// <param name="CalcArgs"></param>
/// <returns></returns>
public RecipeModel InitRecipe(string confPath, int idxPODL, Dictionary<string, string> CalcArgs)
{
return mongoController.InitRecipe(confPath, idxPODL, CalcArgs);
}
/// <summary>
/// Restituisce il valOut booleano se la macchina sia abilitata all'input
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<bool> IobInsEnabAsync(string idxMacchina)
{
var key = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
string? val = await redisDb.HashGetAsync(key, "insEnabled");
if (val == null)
{
var data = await ResetDatiMacchinaAsync(idxMacchina);
data.TryGetValue("insEnabled", out val);
}
return val != null && (val == "1" || val.ToLower() == "true");
}
/// <summary>
/// Restituisce il valOut booleano se la macchina sia master
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<bool> IobIsMasterAsync(string idxMacchina)
{
var key = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
// 1. Tentativo ottimizzato: leggiamo solo il campo che ci serve
// Supponendo che tu usi StackExchange.Redis direttamente o un wrapper
string? val = await redisDb.HashGetAsync(key, "Master");
// 2. Se non c'è in cache, carichiamo/resettiamo tutto
if (val == null)
{
//var data = ResetDatiMacchina(idxMacchina);
var data = await ResetDatiMacchinaAsync(idxMacchina);
data.TryGetValue("Master", out val);
}
// 3. Parsing sicuro
return val != null && (val == "1" || val.ToLower() == "true");
}
/// <summary>
/// Restituisce il valOut booleano se la macchina sia abilitata all'inserimento COMPLETO nel
/// Signal Log
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<bool> IobSLogEnabAsync(string idxMacchina)
{
bool answ = false;
// ORA recupero da memoria redis...
try
{
var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
RedisValue rawData = await redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
// se è vuoto... leggo da DB e popolo!
if (!rawData.HasValue)
{
await ResetDatiMacchinaAsync(idxMacchina);
// riprovo
rawData = await redisDb.HashGetAsync(currHash, (RedisValue)"sLogEnabled");
}
// provo conversione
bool.TryParse($"{rawData}", out answ);
}
catch (Exception exc)
{
Log.Error($"Errore IobSLogEnabAsync | idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// </summary>
/// <param name="IdxOdl">idxMacc odl da cercare</param>
/// <returns></returns>
public async Task<List<AnagGiacenzeModel>> ListGiacenze(int IdxOdl)
{
List<AnagGiacenzeModel>? result = new List<AnagGiacenzeModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisGiacenzaList}:{IdxOdl}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<AnagGiacenzeModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.ListGiacenze(IdxOdl));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
}
if (result == null)
{
result = new List<AnagGiacenzeModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ListGiacenze | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
public async Task<List<ListValuesModel>> ListValuesFilt(string tabName, string fieldName)
{
List<ListValuesModel> resultList = new List<ListValuesModel>();
string tag = "";
tag += string.IsNullOrEmpty(tabName) ? "" : $"{tabName}:";
tag += string.IsNullOrEmpty(fieldName) ? "" : $"{fieldName}:";
var currKey = $"{Utils.redisConfFlux}:{tag}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
resultList = JsonConvert.DeserializeObject<List<ListValuesModel>>($"{rawData}") ?? new();
}
else
{
resultList = await IocDbController.ListValuesFiltAsync(tabName, fieldName);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(resultList);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (resultList == null)
{
resultList = new();
}
return resultList;
}
/// <summary>
/// Elenco completo valori Macchine 2 Slave
/// </summary>
/// <returns></returns>
public async Task<List<Macchine2SlaveModel>> Macchine2SlaveGetAllAsync()
{
List<Macchine2SlaveModel>? result = new List<Macchine2SlaveModel>();
string currKey = $"{Utils.redisBaseAddr}:M2STab";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<Macchine2SlaveModel>>($"{rawData}");
}
else
{
if (useFactory)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var mtcService = scope.ServiceProvider.GetRequiredService<MpIocController>();
result = await mtcService.Macchine2SlaveAsync();
}
else
{
result = await IocDbController.Macchine2SlaveAsync();
}
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
}
if (result == null)
{
result = new List<Macchine2SlaveModel>();
}
return result;
}
/// <summary>
/// Elenco di tutte le macchine gestite
/// </summary>
/// <param name="codGruppo"></param>
/// <returns></returns>
public async Task<List<MacchineModel>> MacchineGetFilt(string codGruppo)
{
List<MacchineModel>? result = new List<MacchineModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string keyGrp = codGruppo != "*" ? codGruppo : "ALL";
string currKey = $"{Utils.redisMacList}:{keyGrp}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<MacchineModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.MacchineGetFilt(codGruppo));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<MacchineModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"MacchineGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Verifica se la macchina abbia un codice PATH ricette associato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<string> MacchineRecipeArchive(string idxMacchina)
{
string? result = "";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisMacRecipePath}:{idxMacchina}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<string>($"{rawData}");
readType = "REDIS";
}
else
{
//recupero elenco macchine...
var machineList = await MacchineGetFilt("*");
var currMach = machineList.Where(x => x.IdxMacchina == idxMacchina).FirstOrDefault();
result = currMach != null ? currMach.RecipeArchivePath : null;
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"MacchineRecipeArchive | Read from {readType}: {ts.TotalMilliseconds}ms");
return result ?? "";
}
/// <summary>
/// Verifica se la macchina abbia un codice CONF ricetta associato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<string> MacchineRecipeConf(string idxMacchina)
{
string? result = "";
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisMacRecipeConf}:{idxMacchina}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<string>($"{rawData}");
readType = "REDIS";
}
else
{
//recupero elenco macchine...
var machineList = await MacchineGetFilt("*");
var currMach = machineList.Where(x => x.IdxMacchina == idxMacchina).FirstOrDefault();
result = currMach != null ? currMach.RecipePath : null;
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"MacchineRecipeConf | Read from {readType}: {ts.TotalMilliseconds}ms");
return result ?? "";
}
/// <summary>
/// Elenco idxMacc Macchine che abbiano dati FLuxLog, nel periodo indicato
/// </summary>
/// <param name="dtStart"></param>
/// <param name="dtEnd"></param>
/// <returns></returns>
public async Task<List<string>> MacchineWithFlux(DateTime dtStart, DateTime dtEnd)
{
List<string>? result = new List<string>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisMacByFlux}:{dtStart:yyyyMMddHHmm}:{dtEnd:yyyyMMddHHmm}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await SpecDbController.MacchineWithFlux(dtStart, dtEnd);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<string>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"MacchineWithFlux | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Lista parametri correnti (ObjItemDTO) della macchina (ex getCurrObjItems)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public List<ObjItemDTO> MachineParamList(string idxMacchina)
{
// setup parametri costanti
string source = "NA";
Stopwatch sw = new Stopwatch();
sw.Start();
List<ObjItemDTO>? result = new List<ObjItemDTO>();
// cerco in _redisConn...
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue && rawData.Length() > 2)
{
var rawVal = JsonConvert.DeserializeObject<List<ObjItemDTO>>($"{rawData}");
// ordino!
result = rawVal
.OrderBy(x => x.displOrdinal)
.ThenBy(x => x.description)
.ToList();
source = "REDIS";
}
if (result == null)
{
result = new List<ObjItemDTO>();
source = "NONE";
}
sw.Stop();
Log.Debug($"MachineParamList | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Lista parametri correnti (ObjItemDTO) della macchina (ex getCurrObjItems)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<List<ObjItemDTO>> MachineParamListAsync(string idxMacchina)
{
// setup parametri costanti
string source = "NA";
Stopwatch sw = new Stopwatch();
sw.Start();
List<ObjItemDTO>? result = new List<ObjItemDTO>();
// cerco in _redisConn...
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue && rawData.Length() > 2)
{
var rawVal = JsonConvert.DeserializeObject<List<ObjItemDTO>>($"{rawData}");
// ordino!
result = rawVal
.OrderBy(x => x.displOrdinal)
.ThenBy(x => x.description)
.ToList();
source = "REDIS";
}
if (result == null)
{
result = new List<ObjItemDTO>();
source = "NONE";
}
sw.Stop();
Log.Debug($"MachineParamListAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Lista parametri correnti che necessitano di write della macchina (ex getCurrObjItems)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<List<ObjItemDTO>> MachineParamListPendingWriteAsync(string idxMacchina)
{
List<ObjItemDTO>? result = new List<ObjItemDTO>();
// recupero tutti i parametri
var allData = await MachineParamListAsync(idxMacchina);
result = allData.Where(x => x.writable && !string.IsNullOrEmpty(x.reqValue)).ToList();
return result;
}
/// <summary>
/// Esegue aggiornamento MachineParamList (ex CurrObjItems) Async
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="currData"></param>
/// <returns></returns>
public async Task<bool> MachineParamListSetAsync(string idxMacchina, List<ObjItemDTO> currData)
{
string serVal = JsonConvert.SerializeObject(currData);
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
bool fatto = await redisDb.StringSetAsync(currKey, serVal);
return fatto;
}
/// <summary>
/// Effettua UPSERT elenco parametri correnti x IOB (se c'è UPDATE, se manca ADD)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="innovations"></param>
/// <returns></returns>
public async Task<bool> MachineParamUpsertAsync(string idxMacchina, List<ObjItemDTO> innovations)
{
bool answ = false;
if (innovations != null)
{
Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
// leggo i valori attuali...
List<ObjItemDTO> actValues = await MachineParamListAsync(idxMacchina);
// per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti
// in REDIS
foreach (var item in actValues)
{
// cerco nelle innovazioni SE CI SIA il valOut...
var trovato = innovations.Find(obj => obj.uid == item.uid);
// se non trovato nelle innovazioni...
if (trovato == null)
{
// lo ri-aggiungo x non perderlo
innovations.Add(item);
// in base a value (value == null) uso debug/info
if (string.IsNullOrEmpty(item.value))
{
Log.Debug($"idxMacchina: {idxMacchina} | innovations | add | item.uid: {item.uid} | item.value: {item.value}");
}
else
{
Log.Info($"idxMacchina: {idxMacchina} | innovations | add | item.uid: {item.uid} | item.value: {item.value}");
}
}
// altrimenti aggiorno campo (non trasmesso) name e tengo il resto...
else
{
trovato.name = item.name;
Log.Debug($"idxMacchina: {idxMacchina} | innovations | update | item.uid: {item.uid} | item.value: {item.value} --> {trovato.value} ");
}
}
// serializzo e salvo
answ = await MachineParamListSetAsync(idxMacchina, innovations);
}
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<Dictionary<string, string>> mDatiMacchineAsync(string idxMacchina)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
try
{
var currHash = Utils.RedKeyDatiMacc(idxMacchina, MpIoNS);
answ = await RedisGetHashDictAsync(currHash);
// se è vuoto... leggo da DB e popolo!
if (answ.Count == 0)
{
answ = await ResetDatiMacchinaAsync(idxMacchina);
}
}
catch (Exception exc)
{
Log.Error($"Errore in compilazione dati Macchine x Redis - idxMacchina {idxMacchina}:{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public Dictionary<string, string> mOptParMacchina(string idxMacchina)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
RedisKey currHash = Utils.RedKeyOptPar(idxMacchina, MpIoNS);
answ = RedisGetHashDict(currHash);
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei TASK SALVATI (da passare a IOB-WIN) per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public Dictionary<string, string> mSavedTaskMacchina(string idxMacchina)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
try
{
RedisKey currHash = Utils.RedKeySavedTask2ExeMacc(idxMacchina);
answ = RedisGetHashDict(currHash);
}
catch (Exception exc)
{
Log.Info($"Errore in recupero dati SAVED TASK x Redis mSavedTaskMacchina | idxMacchina {idxMacchina}{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Elenco da tabella MappaStatoExplModel
/// </summary>
/// <returns></returns>
public async Task<List<MappaStatoExplModel>> MseGetAllAsync(bool forceDb = false)
{
Stopwatch sw = new Stopwatch();
string source = "DB";
sw.Start();
List<MappaStatoExplModel>? result = new List<MappaStatoExplModel>();
// cerco in _redisConn...
RedisValue rawData = await redisDb.StringGetAsync(Constants.redisMseKey);
if (rawData.HasValue && !forceDb)
{
result = JsonConvert.DeserializeObject<List<MappaStatoExplModel>>($"{rawData}") ?? new();
source = "REDIS";
}
else
{
result = await IocDbController.MseGetAllAsync(maxAge);
// serializzp e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(Constants.redisMseKey, rawData, getRandTOut(redisShortTimeCache / 2));
}
if (result == null)
{
result = new List<MappaStatoExplModel>();
}
sw.Stop();
Log.Debug($"MseGetAllAsync | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Restitusice elenco KVP (async) per evitare blocchi quando chiamato da metodi asincroni
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<KeyValuePair<string, string>[]> mTabMSMIAsync(string idxMacchina)
{
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
answ[0] = new KeyValuePair<string, string>("0", "0");
try
{
var currHash = Utils.RedKeyMsmi(idxMacchina);
answ = await RedisGetHashAsync(currHash);
if (answ == null || answ.Length == 0)
{
answ = await resetMSMIAsync(idxMacchina);
}
}
catch (Exception exc)
{
Log.Error($"Errore in compilazione Tabella Multi State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public Dictionary<string, string> mTaskMacchina(string idxMacchina)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
try
{
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
answ = RedisGetHashDict(currHash);
}
catch (Exception exc)
{
Log.Error(string.Format("Errore in mTaskMacchina | idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina));
}
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei TASK (da passare a IOB-WIN) per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<Dictionary<string, string>> mTaskMacchinaAsync(string idxMacchina)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
answ = await RedisGetHashDictAsync(currHash);
return answ;
}
/// <summary>
/// Generazione autoOdl
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="dataInizio"></param>
/// <param name="dataFine"></param>
/// <param name="codArticolo"></param>
/// <returns></returns>
public async Task<bool> OdlAutoDayGenAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo)
{
var result = await IocDbController.OdlAutoDayGenAsync(idxMacchina, dataInizio, dataFine, codArticolo);
return result;
}
/// <summary>
/// Generazione autoOdl
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="dataInizio"></param>
/// <param name="dataFine"></param>
/// <param name="codArticolo"></param>
/// <param name="pzPODL"></param>
/// <param name="pzPallet"></param>
/// <param name="keyRichiesta"></param>
/// <param name="tcAssegnato"></param>
/// <param name="codGruppo"></param>
/// <param name="flgCreaPODL"></param>
/// <param name="flgCheckTC"></param>
/// <returns></returns>
public async Task<bool> OdlAutoDayGenFullAsync(string idxMacchina, DateTime dataInizio, DateTime dataFine, string codArticolo, int? pzPODL, int? pzPallet, string? keyRichiesta, int? tcAssegnato, string? codGruppo, bool flgCreaPODL, bool flgCheckTC)
{
var result = await IocDbController.OdlAutoDayGenFullAsync(idxMacchina, dataInizio, dataFine, codArticolo, pzPODL, pzPallet, keyRichiesta, tcAssegnato, codGruppo, flgCreaPODL, flgCheckTC);
return result;
}
/// <summary>
/// Elenco ODL dato batch selezionato
/// </summary>
/// <param name="BatchSel">Batch richiesto</param>
/// <returns></returns>
public async Task<List<int>> OdlByBatch(string BatchSel)
{
List<int>? result = new List<int>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = Utils.redisOdlByBatch;
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<int>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.OdlByBatch(BatchSel));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<int>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"OdlByBatch | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// ODL da chiave
/// </summary>
/// <param name="IdxOdl"></param>
/// <returns></returns>
public ODLExpModel OdlByKey(int IdxOdl)
{
ODLExpModel? result = new ODLExpModel();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
result = SpecDbController.OdlByKey(IdxOdl);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"OdlByKey | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Effettua chiusura dell'ODL indicato, andand
/// </summary>
/// <param name="idxOdl">idx odl da chiudere</param>
/// <param name="idxMacchina">idx macchina</param>
/// <param name="matrOpr">matricola operatore</param>
/// <param name="confPezzi">indica se confermare i pezzi priam di chiudere ODL</param>
public async Task<bool> ODLClose(int idxOdl, string idxMacchina, int matrOpr, bool confPezzi)
{
bool fatto = false;
await Task.Delay(1);
// recupero dati x conf modalità conferma
var configData = await ConfigGetAllAsync();
if (configData != null)
{
bool confRett = false;
var currRec = configData.FirstOrDefault(x => x.Chiave == "confRett");
if (currRec != null)
{
bool.TryParse(currRec.Valore, out confRett);
}
int modoConfProd = 0;
currRec = configData.FirstOrDefault(x => x.Chiave == "modoConfProd");
if (currRec != null)
{
int.TryParse(currRec.Valore, out modoConfProd);
}
// chiamo metodo conferma!
fatto = await SpecDbController.ODLClose(idxOdl, idxMacchina, matrOpr, confPezzi, confRett, modoConfProd);
}
return fatto;
}
public async Task<ODLExpModel> OdlCurrByMaccAsync(string IdxMacchina)
{
ODLExpModel result = new();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisOdlList}:Current:{IdxMacchina}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<ODLExpModel>($"{rawData}") ?? new();
readType = "REDIS";
}
else
{
result = await IocDbController.OdlCurrByMaccAsync(IdxMacchina);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
}
if (result == null)
{
result = new();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"OdlCurrByMaccAsync | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Record ODL da chaive
/// </summary>
/// <returns></returns>
public async Task<ODLModel> OdlGetByKey(int IdxOdl)
{
await Task.Delay(1);
var dbResult = await SpecDbController.OdlGetByKey(IdxOdl);
return dbResult;
}
/// <summary>
/// ODL correnti (tutti)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public List<string> OdlGetCurrent()
{
List<string>? dbResult = new List<string>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisOdlCurrByMac}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
try
{
dbResult = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
}
catch
{ }
readType = "REDIS";
}
else
{
dbResult = SpecDbController.OdlGetCurrent().Select(x => x.IdxMacchina).Distinct().ToList();
rawData = JsonConvert.SerializeObject(dbResult);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(3));
}
if (dbResult == null)
{
dbResult = new List<string>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"OdlGetCurrent | Read from {readType}: {ts.TotalMilliseconds}ms");
return dbResult;
}
/// <summary>
/// elenco TUTTI gli ODL
/// </summary>
/// <param name="IdxOdl"></param>
/// <returns></returns>
public List<ODLModel> OdlListAll()
{
List<ODLModel>? result = new List<ODLModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
result = SpecDbController.OdlListAll();
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"OdlListAll | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Elenco ODL filtrati x stato, articolo, KeyRich (che contiene stato)
/// </summary>
/// <param name="inCorso">Stato ODL: true=in corso/completato</param>
/// <param name="codArt">Cod articolo</param>
/// <param name="keyRichPart">KeyRich (parziale) da cercare (es cod stato x yacht)</param>
/// <param name="Reparto">Reparto selezionato</param>
/// <param name="IdxMacchina">Macchina selezionata</param>
/// <param name="startDate">Data inizio</param>
/// <param name="endDate">Data fine</param>
/// <returns></returns>
public async Task<List<ODLExpModel>> OdlListGetFilt(bool inCorso, string codArt, string keyRichPart, string Reparto, string IdxMacchina, DateTime startDate, DateTime endDate)
{
List<ODLExpModel>? result = new List<ODLExpModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisOdlList}:{inCorso}:{codArt}:{keyRichPart}:{Reparto}:{IdxMacchina}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<ODLExpModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.ListODLFilt(inCorso, codArt, keyRichPart, Reparto, IdxMacchina, startDate, endDate));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
}
if (result == null)
{
result = new List<ODLExpModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"OdlListGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Elenco di tutti i parametri filtrati x macchina
/// </summary>
/// <param name="IdxMacchina">* = tutte, altrimenti solo x una data macchina</param>
/// <returns></returns>
public async Task<List<string>> ParametriGetFilt(string IdxMacchina)
{
List<string>? result = new List<string>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisFluxByMac}:{IdxMacchina}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<string>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.ParametriGetFilt(IdxMacchina));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<string>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"ParametriGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Eliminazione record selezionato
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public async Task<bool> POdlDeleteRecord(PODLExpModel currRec)
{
var dbResult = await SpecDbController.PODLDeleteRecord(currRec);
// elimino cache redis...
await POdlFlushCache();
await Task.Delay(1);
return dbResult;
}
/// <summary>
/// Avvio fase setup per il record selezionato
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public async Task<bool> POdlDoSetup(PODLExpModel currRec)
{
var dbResult = await SpecDbController.PODL_startSetup(currRec, 0, 1, 1, "", DateTime.Now);
// elimino cache redis...
await POdlFlushCache();
await Task.Delay(1);
return dbResult;
}
/// <summary>
/// Recupero PODL da chiave
/// </summary>
/// <param name="idxPODL"></param>
/// <returns></returns>
public async Task<PODLModel> POdlGetByKey(int idxPODL)
{
PODLModel result = new PODLModel();
if (idxPODL != 0)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisPOdlByPOdl}:{idxPODL}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
var rawResult = JsonConvert.DeserializeObject<PODLModel>($"{rawData}");
if (rawResult != null)
{
result = rawResult;
readType = "REDIS";
}
}
else
{
result = await SpecDbController.PODL_getByKey(idxPODL);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new PODLModel();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"POdlGetByKey | Read from {readType}: {ts.TotalMilliseconds}ms");
}
else
{
Log.Debug("Errore IdxPODL = 0");
}
return result;
}
public async Task<List<PODLExpModel>> POdlGetByMaccArtAsync(string idxMacchina, string codArticolo, string codGruppo, bool onlyFree)
{
List<PODLExpModel> result = new List<PODLExpModel>();
var currKey = $"{Utils.redisPOdlByMaccArt}:{idxMacchina}";
if (!string.IsNullOrEmpty(codArticolo))
{
currKey += $":A{codArticolo}";
}
if (!string.IsNullOrEmpty(codGruppo))
{
currKey += $":G{codGruppo}";
}
currKey += onlyFree ? $":FREE" : ":ALL";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<PODLExpModel>>($"{rawData}") ?? new();
}
else
{
result = await IocDbController.POdlGetByMaccArtAsync(idxMacchina, codArticolo, codGruppo, onlyFree);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<PODLExpModel>();
}
return result;
}
/// <summary>
/// Recupero PODL da IdxODL
/// </summary>
/// <param name="idxODL"></param>
/// <returns></returns>
public PODLModel POdlGetByOdl(int idxODL)
{
PODLModel result = new PODLModel();
if (idxODL != 0)
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisPOdlByOdl}:{idxODL}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
var rawResult = JsonConvert.DeserializeObject<PODLModel>($"{rawData}");
if (rawResult != null)
{
result = rawResult;
}
readType = "REDIS";
}
else
{
result = SpecDbController.PODL_getByOdl(idxODL);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new PODLModel();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Trace($"POdlGetByOdl | Read from {readType}: {ts.TotalMilliseconds}ms");
}
else
{
Log.Debug("Errore IdxODL = 0");
}
return result;
}
/// <summary>
/// Elenco PODL non avviati filtrati x articolo, KeyRich (che contiene stato)
/// </summary>
/// <param name="lanciato">Solo lanciati (1) o ancora disponibili (0)</param>
/// <param name="keyRichPart">KeyRich (parziale) da cercare (es cod stato x yacht)</param>
/// <param name="idxMacchina">Macchina</param>
/// <param name="codGruppo">Gruppo</param>
/// <param name="startDate">Data inizio</param>
/// <param name="endDate">Data fine</param>
/// <returns></returns>
public async Task<List<PODLExpModel>> POdlListGetFilt(bool lanciato, string keyRichPart, string idxMacchina, string codGruppo, DateTime startDate, DateTime endDate)
{
List<PODLExpModel>? result = new List<PODLExpModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisPOdlList}:{codGruppo}:{idxMacchina}:{keyRichPart}:{lanciato}:{startDate:yyyyMMdd_HHmmss}:{endDate:yyyyMMdd_HHmmss}";
// cerco in redis dato valOut sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<PODLExpModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = await Task.FromResult(SpecDbController.ListPODLFilt(lanciato, keyRichPart, idxMacchina, codGruppo, startDate, endDate));
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, TimeSpan.FromSeconds(redisShortTimeCache));
}
if (result == null)
{
result = new List<PODLExpModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"POdlListGetFilt | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Aggiornamento record selezionato
/// </summary>
/// <param name="currRec"></param>
/// <returns></returns>
public async Task<bool> POdlUpdateRecord(PODLModel currRec)
{
var dbResult = await SpecDbController.PODLUpdateRecord(currRec);
// elimino cache redis...
await POdlFlushCache();
return dbResult;
}
/// <summary>
/// Processa registrazione FL da IOB
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="flux"></param>
/// <param name="valore"></param>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <param name="contatore"></param>
/// <param name="disabKA"></param>
/// <returns></returns>
public async Task<string> ProcessFluxLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, bool disabKA)
{
// se non vietato...
if (!disabKA)
{
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
}
string answ = "";
DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr);
// inizio processing vero e proprio INPUT...
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(valore))
{
string errore = "processFluxLog | Errore: parametri macchina/valOut vuoti";
Log.Error(errore);
answ = errore;
}
else
{
FluxLogModel newRec = new FluxLogModel()
{
IdxMacchina = idxMacchina,
dtEvento = dataOraEvento,
CodFlux = flux,
Valore = valore,
Cnt = contatore
};
await IocDbController.FluxLogInsertAsync(newRec);
// 2022.06.06 salvo su redis il valOut ULTIMO del flux x recupero rapido ultimo valOut
var currKey = Utils.RedKeyLastFLog(idxMacchina, flux, MpIoNS);
// 10 min cache max...
await redisDb.StringSetAsync(currKey, valore, TimeSpan.FromMinutes(10));
// registro in risposta che è andato tutto bene...
answ = "OK";
}
return answ;
}
/// <summary>
/// Validazione preliminare valori input
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="valore"></param>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <returns></returns>
private bool ValidateinputParams(string idxMacchina, string valore, string dtEve, string dtCurr)
{
bool isValid = false;
// preparo stringa valori correnti
string currVals = $"idxMacchina: {idxMacchina} | valOut: {valore} | dtEve: {dtEve} | dtCurr:{dtCurr}";
if (dtEve == null || dtCurr == null)
{
Log.Warn($"procInput: null found | {currVals}");
}
else if (dtEve.Length < 17 || dtCurr.Length < 17)
{
Log.Info($"procInput: invalid data | {currVals}");
}
else if (string.IsNullOrEmpty(idxMacchina))
{
Log.Info($"procInput: missing IdxMacchina | {currVals}");
}
else if (string.IsNullOrEmpty(valore))
{
Log.Info($"procInput: missing valOut | {currVals}");
}
else
{
isValid = true;
}
return isValid;
}
/// <summary>
/// Calcola dataora evento da info dt ricevute
/// </summary>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <returns></returns>
private DateTime ParseEventTime(string dtEve, string dtCurr)
{
DateTime dataOraEvento = DateTime.Now;
// fix formato dataora in ingresso
string stdEve = dtFormStd(dtEve);
string stdCurr = dtFormStd(dtCurr);
// 2. Se le stringhe normalizzate coincidono, skip dei calcoli
if (stdEve != stdCurr)
{
// 3. Parsing sicuro
if (DateTime.TryParseExact(stdEve, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtEvento) &&
DateTime.TryParseExact(stdCurr, dtFormat, ciProvider, DateTimeStyles.None, out DateTime dtCorrente))
{
TimeSpan diff = dtCorrente - dtEvento;
double ms = Math.Abs(diff.TotalMilliseconds);
// 4. Classificazione delta con switch expression (più leggibile e performante)
string deltaClass = ms switch
{
<= 10 => "0-10 ms",
<= 100 => "10-100 ms",
<= 1000 => "100-1000 ms",
<= 10000 => "1-10 sec",
_ => "> 10 sec"
};
Log.Debug($"Correzione delta {deltaClass}");
// 5. Correzione data/ora server: sottrao lo scarto calcolato
dataOraEvento = dataOraEvento.Subtract(diff);
}
else
{
Log.Error($"Errore parsing date: {stdEve} | {stdCurr}");
}
}
return dataOraEvento;
}
/// <summary>
/// Processa input da IOB eventualmente registrando i segnali inviati
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="valore"></param>
/// <param name="dtEve"></param>
/// <param name="dtCurr"></param>
/// <param name="contatore"></param>
/// <returns></returns>
public async Task<string> ProcessInputAsync(string idxMacchina, string valore, string dtEve, string dtCurr, string contatore)
{
string answ = "";
if (ValidateinputParams(idxMacchina, valore, dtEve, dtCurr))
{
DateTime dataOraEvento = ParseEventTime(dtEve, dtCurr);
// se abilitato registro evento sul DB
if (await IobSLogEnabAsync(idxMacchina))
{
int cntVal = 0;
int.TryParse(contatore, out cntVal);
await saveSigLogAsync(idxMacchina, valore, dataOraEvento, cntVal);
}
// continuo col resto
try
{
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
// Cache dati macchina per evitare lookup ridondanti
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
// verifico se sia una macchina MULTI....
if (isMulti(idxMacchina, datiMacc))
{
// inizio preprocessing
string newVal = "";
// processo OGNI macchina a stati dell'impianto... (KEY:IdxMacchina / IdxMacchina#qualcosa, Val = IdxFamIn)
foreach (var item in await mTabMSMIAsync(idxMacchina))
{
newVal = preProcInput(item.Key, valore, datiMacc);
// ora processo e salvo il valOut del microstato...
// INTERNAMENTE gestisce i casi DB/REDIS secondo necessità
await CheckMicroStatoAsync(item.Key, newVal, dataOraEvento, contatore, datiMacc);
}
}
else
{
// ora processo e salvo il valOut del microstato... INTERNAMENTE
// gestisce i casi DB/REDIS secondo necessità
await CheckMicroStatoAsync(idxMacchina, valore, dataOraEvento, contatore, datiMacc);
}
// forzo RESET dati macchina...
await ResetDatiMacchinaAsync(idxMacchina);
// registro in risposta che è andato tutto bene...
answ = "OK";
}
catch (Exception exc)
{
string errore = $"Errore: {Environment.NewLine}{exc}";
Log.Error(errore);
answ = errore;
}
}
return answ;
}
/// <summary>
/// Processa registrazione UserLog da IOB
/// </summary>
/// <param name="idxMacchina">Macchina</param>
/// <param name="flux">Flusso: DI/RC/RC</param>
/// <param name="valore">valOut = note/valString</param>
/// <param name="dtEve">data evento</param>
/// <param name="dtCurr">data corrente</param>
/// <param name="contatore">contatore invio</param>
/// <param name="matrOpr">Matricola Operatore</param>
/// <param name="label">label = causale scarto / tagCode</param>
/// <param name="valNum">valNum = esitoOk (0/1) / Quantità di scarto associata</param>
/// <returns></returns>
public async Task<string> ProcessUserLogAsync(string idxMacchina, string flux, string valore, string dtEve, string dtCurr, int contatore, int matrOpr, string label, int valNum)
{
// scrivo keep alive!!! (se necessario, altrimenti è in cache...)
await ScriviKeepAliveAsync(idxMacchina, DateTime.Now);
// 2017.09.14 trimmo eventualmente lo zero finale dalle date SE supera i millisecondi...
dtEve = dtEve.Length > 17 ? dtEve.Substring(0, 17) : dtEve;
dtCurr = dtCurr.Length > 17 ? dtCurr.Substring(0, 17) : dtCurr;
string answ = "";
DateTime dataOraEvento = GetSrvDtEvent(dtEve, dtCurr);
// inizio processing vero e proprio INPUT...
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(flux))
{
string errore = "processFluxLog | Errore: parametri macchina/flux vuoti";
Log.Error(errore);
answ = errore;
}
else
{
// in base al flusso decido dove e cosa scrivere...
switch (flux)
{
case "DI":
RegistroDichiarazioniModel recDich = new RegistroDichiarazioniModel()
{
IdxMacchina = idxMacchina,
DtRec = dataOraEvento,
MatrOpr = matrOpr,
ValString = valore,
TagCode = label
};
await IocDbController.RegDichiarInsertAsync(recDich);
break;
case "RC":
bool esitoOk = valNum != 0;
await IocDbController.RegControlliInsertAsync(idxMacchina, matrOpr, esitoOk, valore, dataOraEvento);
break;
case "RS":
RegistroScartiModel recSca = new RegistroScartiModel()
{
IdxMacchina = idxMacchina,
DataOra = dataOraEvento,
Causale = label,
Qta = valNum,
Note = valore,
MatrOpr = matrOpr
};
await IocDbController.RegScartiInsertAsync(recSca);
break;
default:
break;
}
// registro in risposta che è andato tutto bene...
answ = "OK";
}
return answ;
}
/// <summary>
/// Restituisce il contapezzi salvato per la macchina
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<int> pzCounter(string idxMacchina)
{
int answ = -1;
try
{
var currKey = Utils.RedKeyPzCount(idxMacchina, MpIoNS);
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
int.TryParse(rawData, out answ);
}
else
{
answ = await PzCounterTcAsync(idxMacchina);
// salvo in _redisConn...
await redisDb.StringSetAsync(currKey, answ.ToString(), TimeSpan.FromSeconds(1));
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in pzCounter{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Restituisce il contapezzi come CONTEGGIO da TCRilevati per la macchina - ASYNC
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<int> PzCounterTcAsync(string idxMacchina)
{
int answ = -1;
DateTime dataRif = DateTime.Now;
var datiProd = await StatoProdMacchinaAsync(idxMacchina, dataRif);
if (datiProd != null)
{
answ = datiProd.PzTotODL;
}
return answ;
}
/// <summary>
/// Ricerca ricetta su MongoDB dato PODL
/// </summary>
/// <param name="idxPODL"></param>
/// <returns></returns>
public async Task<RecipeModel?> RecipeGetByPODL(int idxPODL)
{
RecipeModel? result = null;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "MongoDB";
result = await mongoController.RecipeGetByPODL(idxPODL);
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"RecipeGetByPODL | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Salva ricetta su MongoDB
/// </summary>
/// <param name="currRecord"></param>
/// <returns></returns>
public async Task<bool> RecipeSetByPODL(RecipeModel currRecord)
{
bool answ = false;
answ = await mongoController.RecipeSetByPODL(currRecord);
if (answ)
{
await POdlFlushCache();
}
return answ;
}
/// <summary>
/// Effettua conteggio chaivi REDIS dato pattern ricerca
/// </summary>
/// <param name="keyPattern"></param>
/// <returns></returns>
public int RedisCountKey(string keyPattern)
{
int num = 0;
keyPattern = (string.IsNullOrEmpty(keyPattern) ? "**" : keyPattern);
try
{
var listEndpoints = redisConnAdmin.GetEndPoints();
foreach (var endPoint in listEndpoints)
{
var server = redisConnAdmin.GetServer(endPoint);
foreach (RedisKey item in server.Keys(pattern: keyPattern, database: redisDb.Database, pageSize: 250, cursor: 0L))
{
num++;
}
}
}
catch (Exception arg)
{
Log.Error($"Eccezione in RedisCountKey{Environment.NewLine}{arg}");
}
return num;
}
/// <summary>
/// Esegue eliminazione memoria redis keyVal
/// </summary>
/// <param name="keyVal"></param>
/// <returns></returns>
public bool RedisDelKey(string keyVal)
{
bool answ = redisDb.KeyDelete((RedisKey)keyVal);
#if false
var listEndpoints = redisConnAdmin.GetEndPoints();
foreach (var endPoint in listEndpoints)
{
var server = redisConnAdmin.GetServer(endPoint);
if (server != null)
{
redisDb.KeyDelete((RedisKey)keyVal);
answ = true;
}
}
#endif
return answ;
}
/// <summary>
/// Esegue eliminazione memoria redis keyVal
/// </summary>
/// <param name="keyVal"></param>
/// <returns></returns>
public async Task<bool> RedisDelKeyAsync(RedisKey keyVal)
{
return await redisDb.KeyDeleteAsync(keyVal);
}
/// <summary>
/// Esegue flush memoria redis dato keyVal
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
public bool RedisFlushPattern(string pattern)
{
bool answ = false;
var listEndpoints = redisConnAdmin.GetEndPoints();
foreach (var endPoint in listEndpoints)
{
var server = redisConnAdmin.GetServer(endPoint);
if (server != null)
{
var keyList = server.Keys(redisDb.Database, pattern);
foreach (var item in keyList)
{
redisDb.KeyDelete(item);
}
answ = true;
}
}
return answ;
}
/// <summary>
/// Esegue flush memoria redis dato keyVal, async
/// </summary>
/// <param name="pattern"></param>
/// <returns></returns>
public async Task<bool> RedisFlushPatternAsync(RedisValue pattern)
{
Log.Debug($"Richiesta flush pattern: {pattern}");
// 1. Target ONLY master (le replica sono in read-only)
var master = redisConnAdmin.GetEndPoints()
.Where(ep => redisConnAdmin.GetServer(ep).IsConnected && !redisConnAdmin.GetServer(ep).IsReplica)
.FirstOrDefault();
if (master == null)
{
Log.Warn($"Nessun master Redis raggiungibile per il pattern {pattern}");
return false;
}
// 2. Flush intero DB se richiesto
if (pattern.ToString() == "*")
{
Log.Debug($"Full DB reset da pattern {pattern}");
if (master != null)
{
redisConnAdmin.GetServer(master).FlushDatabase(redisDb.Database);
Log.Info($"Flush database {redisDb.Database} completato");
}
return true;
}
// altrimenti faccio ciclo!
var server = redisConnAdmin.GetServer(master);
var db = redisConnAdmin.GetDatabase(redisDb.Database);
const int batchSize = 500;
var batch = new List<RedisKey>(batchSize);
int deletedCount = 0;
try
{
// KeysAsync usa SCAN automaticamente quando i risultati sono grandi
await foreach (var key in server.KeysAsync(
database: redisDb.Database,
pattern: pattern.ToString(),
pageSize: batchSize))
{
batch.Add(key);
if (batch.Count >= batchSize)
{
// Esecuzione batch in parallelo controllato
await Task.WhenAll(batch.Select(k => db.KeyDeleteAsync(k)));
batch.Clear();
deletedCount += batchSize;
}
}
// Restanti
if (batch.Count > 0)
{
await Task.WhenAll(batch.Select(k => db.KeyDeleteAsync(k)));
deletedCount += batch.Count;
}
Log.Info("Flush pattern {Pattern}: eliminate {Count} chiavi", pattern, deletedCount);
return true;
}
catch (RedisConnectionException ex)
{
Log.Error(ex, "Connessione Redis persa durante il flush di {pattern}", pattern);
return false;
}
catch (Exception ex)
{
Log.Error(ex, "Errore imprevisto nel flush pattern {pattern}", pattern);
throw;
}
}
public KeyValuePair<string, string>[] RedisGetHash(RedisKey redKey)
{
HashEntry[] rawData = redisDb.HashGetAll(redKey);
var result = rawData.Where(x => !x.Name.IsNull).Select(x => new KeyValuePair<string, string>($"{x.Name}", $"{x.Value}")).ToArray();
return result;
}
public async Task<KeyValuePair<string, string>[]> RedisGetHashAsync(RedisKey redKey)
{
HashEntry[] rawData = await redisDb.HashGetAllAsync(redKey);
var result = rawData.Where(x => !x.Name.IsNull).Select(x => new KeyValuePair<string, string>($"{x.Name}", $"{x.Value}")).ToArray();
return result;
}
public Dictionary<string, string> RedisGetHashDict(RedisKey hashKey)
{
HashEntry[] rawData = redisDb.HashGetAll(hashKey);
var result = rawData.Where(x => !x.Name.IsNull).ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
return result;
}
public async Task<Dictionary<string, string>> RedisGetHashDictAsync(RedisKey hashKey)
{
HashEntry[] rawData = await redisDb.HashGetAllAsync(hashKey);
var result = rawData
.Where(x => !x.Name.IsNull)
.ToDictionary(x => x.Name.ToString(), x => x.Value.ToString());
return result;
}
public async Task<RedisValue> RedisGetHashFieldAsync(RedisKey key, string hashField)
{
return await redisDb.HashGetAsync(key, hashField);
}
public bool RedisKeyPresent(RedisKey key)
{
return redisDb.KeyExists(key);
}
public async Task<bool> RedisKeyPresentAsync(RedisKey key)
{
return await redisDb.KeyExistsAsync(key);
}
public void RedisSetHash(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0)
{
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
redisDb.HashSet(redKey, redHash);
if (expireSeconds > 0.0)
{
redisDb.KeyExpire(redKey, DateTime.Now.AddSeconds(expireSeconds));
}
}
public async Task RedisSetHashAsync(RedisKey redKey, KeyValuePair<string, string>[] valori, double expireSeconds = -1.0)
{
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
await redisDb.HashSetAsync(redKey, redHash);
if (expireSeconds > 0.0)
{
await redisDb.KeyExpireAsync(redKey, DateTime.Now.AddSeconds(expireSeconds));
}
}
public void RedisSetHashDict(RedisKey redKey, Dictionary<string, string> valori, double expireSeconds = -1.0)
{
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
redisDb.HashSet(redKey, redHash);
if (expireSeconds > 0.0)
{
redisDb.KeyExpire(redKey, DateTime.Now.AddSeconds(expireSeconds));
}
}
public async Task RedisSetHashDictAsync(RedisKey redKey, Dictionary<string, string> valori, double expireSeconds = -1.0)
{
HashEntry[] redHash = valori.Select(x => new HashEntry(x.Key, x.Value)).ToArray();
await redisDb.HashSetAsync(redKey, redHash);
if (expireSeconds > 0.0)
{
await redisDb.KeyExpireAsync(redKey, DateTime.Now.AddSeconds(expireSeconds));
}
}
/// <summary>
/// Inserisce record RRL + fa pulizia vecchi record
/// </summary>
/// <returns></returns>
public async Task<bool> RemRebootLogAddAsync(RemoteRebootLogModel newRec)
{
// verifica preliminare ultima esecuzione (max 1 ogni 60 min...)
DateTime adesso = DateTime.Now;
bool doClean = false;
if (adesso.Subtract(lastCleanupRRL).TotalMinutes > 60)
{
lastCleanupRRL = adesso;
doClean = true;
}
string confVal = await tryGetConfigAsync("IO_NumReboot2Keep");
int num2keep = int.TryParse(confVal, out int n) ? n : 5;
// insert del record + pulizia
bool fatto = await IocDbController.RemRebootLogAddAndCleanAsync(newRec, doClean, num2keep);
if (fatto)
{
// svuota cache
var currKey = $"{Utils.redisRemRebLog}:*";
await RedisFlushPatternAsync(currKey);
}
return fatto;
}
/// <summary>
/// Recupera tutti i record di RemoteRebootLog
/// </summary>
/// <returns></returns>
public async Task<List<RemoteRebootLogModel>> RemRebootLogGetAllAsync()
{
// setup parametri costanti
string source = "DB";
Stopwatch sw = new Stopwatch();
sw.Start();
List<RemoteRebootLogModel> result = new List<RemoteRebootLogModel>();
// cerco in _redisConn...
var currKey = $"{Utils.redisRemRebLog}:ALL";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
//if (!string.IsNullOrEmpty($"{rawData}"))
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<RemoteRebootLogModel>>($"{rawData}") ?? new();
source = "REDIS";
}
else
{
result = await IocDbController.RemRebootLogGetAllAsync();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(30));
}
if (result == null)
{
result = new List<RemoteRebootLogModel>();
}
sw.Stop();
Log.Debug($"RemRebootLogGetAll | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Recupera ultimo record x ogni IdxMacchina x avere ultimo attivo
/// </summary>
/// <returns></returns>
public async Task<List<RemoteRebootLogModel>> RemRebootLogGetLast()
{
// setup parametri costanti
string source = "DB";
Stopwatch sw = new Stopwatch();
sw.Start();
List<RemoteRebootLogModel> result = new List<RemoteRebootLogModel>();
// cerco in _redisConn...
var currKey = $"{Utils.redisRemRebLog}:LAST";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<RemoteRebootLogModel>>($"{rawData}") ?? new();
source = "REDIS";
}
else
{
result = await IocDbController.RemRebootLogGetLastAsync();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(30));
}
if (result == null)
{
result = new List<RemoteRebootLogModel>();
}
sw.Stop();
Log.Debug($"RemRebootLogGetLast | {source} | {sw.Elapsed.TotalMilliseconds}ms");
return result;
}
/// <summary>
/// Elimina da elenco KVP il TASK per l'impianto indicato
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="tName"></param>
/// <returns></returns>
public async Task<Dictionary<string, string>> RemTask2ExeMacchinaAsync(string idxMacchina, taskType tName)
{
// hard coded dimensione vettore DatiMacchine
Dictionary<string, string> answ = new Dictionary<string, string>();
// ORA recupero da memoria redis...
try
{
var currHash = Utils.RedKeyTask2ExeMacc(idxMacchina, MpIoNS);
answ = await RedisGetHashDictAsync(currHash);
answ.Remove($"{tName}");
// riscrivo!
await RedisDelKeyAsync(currHash);
await RedisSetHashDictAsync(currHash, answ);
Log.Info($"Task REM - idxMacchina: {idxMacchina} | taskKey: {tName.ToString()}");
}
catch (Exception exc)
{
Log.Info(string.Format("Errore in RemTask2ExeMacchinaAsync | idxMacchina {2}:{0}{1}", Environment.NewLine, exc, idxMacchina));
}
return answ;
}
/// <summary>
/// Resetta (rileggendo) i dati della State Machine multi ingressi nel formato
/// currKey: IdxMacchina
/// value: IdxFamigliaIngresso
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
public async Task<KeyValuePair<string, string>[]> resetMSMIAsync(string idxMacchina)
{
var currHash = Utils.RedKeyMsmi(idxMacchina);
// recupero records
var tabMSMI = await IocDbController.VMSFDGetMultiByMaccAsync(idxMacchina);
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[tabMSMI.Count];
// salvo tutti i valori StateMachineIngressi...
int i = 0;
foreach (var item in tabMSMI)
{
answ[i] = new KeyValuePair<string, string>(item.IdxMacchina, item.IdxFamigliaIngresso.ToString());
i++;
}
// verifico il timeout (default 60 sec...)
var sTOutSmi = await tryGetConfigAsync("TmOut.MSMI");
int tOut = 60;
int.TryParse(sTOutSmi, out tOut);
tOut = tOut <= 60 ? 60 : tOut;
// salvo in redis!
await RedisSetHashAsync(currHash, answ, tOut);
return answ;
}
/// <summary>
/// Processa registrazione EVENTO CONTEGGIO PEZZI x una data macchina IOB
/// </summary>
/// <param name="idxMacchina">Macchina</param>
/// <param name="qty">Pezzi da registrare</param>
/// <returns></returns>
public async Task<string> saveCaricoPezzi(string idxMacchina, string qty)
{
// default: 0, non registrato x cautela...
string answ = "0";
// controllo per proseguire
if (string.IsNullOrEmpty(idxMacchina) || string.IsNullOrEmpty(qty))
{
string errore = $"Errore: mancano parametri macchina/incremento: idxMacchina {idxMacchina} | qty {qty}";
Log.Error(errore);
answ = errore;
}
else
{
int numPzIncr = -1;
int.TryParse(qty, out numPzIncr);
// se il conteggio è >= 0 SALVO evento...
if (numPzIncr >= 0)
{
// recupero info tra cui ODL corrente
Dictionary<string, string> datiMacc = await mDatiMacchineAsync(idxMacchina);
// registro evento 120 --> contapezzi in blocco !!!HARD CODED!!! !!!FIXME!!!
int idxEvento = 120;
DateTime adesso = DateTime.Now;
string codArticolo = "ND";
if (datiMacc.ContainsKey("CodArticolo"))
{
codArticolo = datiMacc["CodArticolo"];
}
// creo evento
EventListModel newRecEv = new EventListModel()
{
CodArticolo = codArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxEvento,
InizioStato = adesso,
MatrOpr = 0,
pallet = "-",
Value = qty
};
// salva e processa
var resp = await scriviRigaEventoAsync(newRecEv);
// registro in risposta che è andato tutto bene... ovvero la qty richiesta...
answ = qty;
}
}
return answ;
}
/// <summary>
/// Processa registrazione EVENTO CONTEGGIO PEZZI x una data macchina IOB
/// </summary>
/// <param name="idxMacchina">Macchina</param>
/// <param name="qty">Pezzi da registrare</param>
/// <param name="dtEve">DataOra evento</param>
/// <param name="dtCurr">DataOra corrente</param>
/// <returns></returns>
public async Task<string> SaveCaricoPezziAsync(string idxMacchina, string qty, string dtEve = "", string dtCurr = "")
{
// default: 0, non registrato x cautela...
string answ = "0";
// Verifica se evento realtime oppure ho data specificata x processing @dtEve
DateTime adesso = DateTime.Now;
DateTime dtEvent = adesso;
bool rtimeProc = string.IsNullOrEmpty(dtEve);
if (!rtimeProc)
{
dtEvent = GetSrvDtEvent(dtEve, dtCurr);
}
// controllo per proseguire
if (!string.IsNullOrEmpty(idxMacchina) && !string.IsNullOrEmpty(qty))
{
int numPzIncr = -1;
int.TryParse(qty, out numPzIncr);
// se il conteggio è >= 0 SALVO evento...
if (numPzIncr >= 0)
{
var listOdl = await IocDbController.OdlListByMaccPeriodoAsync(idxMacchina, dtEvent, dtEvent.AddSeconds(1));
if (listOdl != null && listOdl.Count > 0)
{
string codArticolo = listOdl.FirstOrDefault()?.CodArticolo ?? "ND";
// registro evento 120 --> contapezzi in blocco !!!HARD CODED!!! !!!FIXME!!!
int idxEvento = 120;
// creo evento
EventListModel newRecEv = new EventListModel()
{
CodArticolo = codArticolo,
IdxMacchina = idxMacchina,
IdxTipo = idxEvento,
InizioStato = dtEvent,
MatrOpr = 0,
pallet = "-",
Value = qty
};
// salva e processa
var resp = await scriviRigaEventoAsync(newRecEv);
// registro in risposta che è andato tutto bene... ovvero la qty richiesta...
answ = qty;
}
}
}
else
{
string errore = $"Errore: mancano parametri macchina/incremento: idxMacchina {idxMacchina} | qty {qty}";
Log.Error(errore);
answ = errore;
}
return answ;
}
/// <summary>
/// Processa registrazione di un counter x una data macchina IOB
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="counter">contapezzi</param>
/// <returns></returns>
public async Task<string> SaveCounterAsync(string idxMacchina, string counter)
{
string answ = "0";
// inizio processing vero e proprio INPUT...
if (string.IsNullOrEmpty(idxMacchina))
{
string errore = "Errore: parametro macchina vuoto";
Log.Info(errore);
answ = errore;
}
else
{
if (string.IsNullOrEmpty(counter))
{
string errore = "Errore: parametro counter vuoto";
Log.Error(errore);
answ = errore;
}
else
{
int newCounter = -1;
int.TryParse(counter, out newCounter);
// se il conteggio è >= 0 SALVO come nuovo conteggio...
if (newCounter >= 0)
{
var currKey = Utils.RedKeyPzCount(idxMacchina, MpIoNS);
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
// salvo per + tempo...
await redisDb.StringSetAsync(currKey, answ.ToString());
answ = counter;
}
else
{
int currCount = await PzCounterTcAsync(idxMacchina);
answ = currCount.ToString();
// salvo per meno tempo...
await redisDb.StringSetAsync(currKey, answ);
}
}
}
}
return answ;
}
public async Task<bool> SaveDataItemsAsync(string id, List<MachDataItem> dataList)
{
bool answ = false;
if (mongoController != null)
{
answ = mongoController.SaveMachineDataItems(id, dataList);
}
else
{
// modalità con SqlSb (no mongo)
if (useFactory)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var mtcService = scope.ServiceProvider.GetRequiredService<IMtcSetupService>();
answ = await mtcService.ReplaceMachineDataAsync(id, dataList);
}
else
{
answ = await MtcService.ReplaceMachineDataAsync(id, dataList);
}
}
return answ;
}
public async Task<bool> SaveMachine2Iob(string idxMacchina, string serData)
{
bool fatto = false;
var currKey = Utils.RedKeyMach2Iob(idxMacchina);
// se != null --> salvo!
if (!string.IsNullOrEmpty(serData))
{
fatto = await redisDb.StringSetAsync(currKey, serData);
}
return fatto;
}
public async Task<bool> SaveMachineIobConf(string idxMacchina, Dictionary<string, string> currDict)
{
bool fatto = false;
var currKey = Utils.RedKeyMachIobConf(idxMacchina);
// se != null --> salvo!
if (currDict != null)
{
await RedisSetHashDictAsync(currKey, currDict);
fatto = true;
}
return fatto;
}
/// <summary>
/// salva il segnale di "microstato" (segnale) ASYNC
/// </summary>
/// <param name="idxMacchina">idx macchina</param>
/// <param name="valore">valOut ingresso</param>
/// <param name="dtEve">data-ora evento (server)</param>
/// <param name="contatore">contatore sequenza dati inviati</param>
/// <returns></returns>
public async Task<bool> saveSigLogAsync(string idxMacchina, string valore, DateTime dtEve, int contatore)
{
SignalLogModel newRec = new SignalLogModel()
{
IdxMacchina = idxMacchina,
DtCurr = DateTime.Now,
DtEve = dtEve,
Contatore = contatore,
Valore = valore
};
return await IocDbController.SignalLogInsertAsync(newRec);
}
/// <summary>
/// scrive un evento di keepalive sulla tabella
/// </summary>
/// <param name="IdxMacchina"></param>
/// <param name="oraMacchina"></param>
/// <returns></returns>
public async Task ScriviKeepAliveAsync(string IdxMacchina, DateTime oraMacchina)
{
// cerco se ho keep alive in redis,
var currKey = Utils.RedKeyHash($"KeepAlive:{IdxMacchina}");
bool keyPresent = await RedisKeyPresentAsync(currKey);
// se NON presente salvo in REDIS con TTL 10 sec e sul DB...
if (!keyPresent)
{
DateTime adesso = DateTime.Now;
await redisDb.StringSetAsync(currKey, adesso.ToString("s"), TimeSpan.FromSeconds(30));
// effettuo scrittura sul DB
await IocDbController.KeepAliveUpsertAsync(IdxMacchina, DateTime.Now, oraMacchina);
}
}
/// <summary>
/// Salvataggio YAML completo di configurazione dell'IOB
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="iobConfFull"></param>
/// <returns></returns>
public async Task<bool> SetIobConfYamlAsync(string idxMacchina, string iobConfFull)
{
bool answ = false;
// se ho un area memoria valida...
if (!string.IsNullOrEmpty(iobConfFull))
{
// salvo!
var currKey = Utils.RedKeyIobConfYaml(idxMacchina, MpIoNS);
answ = await redisDb.StringSetAsync(currKey, iobConfFull);
}
return answ;
}
public async Task<bool> SetIobMemMap(string idxMacchina, PlcMemMapDto currMap)
{
bool answ = false;
// se ho un area memoria valida...
if (currMap != null)
{
// salvo!
var currKey = Utils.RedKeyIobMemMap(idxMacchina, MpIoNS);
string serVal = JsonConvert.SerializeObject(currMap);
answ = await redisDb.StringSetAsync(currKey, serVal);
}
return answ;
}
/// <summary>
/// Restitusice elenco KVP dei campi della State Machine ingressi nel formato
/// currKey: cState_nVal (current MICRO-STATE + "_" + new Value)
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE
/// </summary>
/// <param name="idxFamIn"></param>
/// <returns></returns>
public async Task<KeyValuePair<string, string>[]> StateMachInByKeyAsync(int idxFamIn)
{
// hard coded dimensione vettore DatiMacchine
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[1];
// iniziualizzo con un valOut... 0/0
answ[0] = new KeyValuePair<string, string>("0", "0");
// ORA recupero da memoria redis...
try
{
var currHash = Utils.GetHashSMI(idxFamIn);
answ = await RedisGetHashAsync(currHash);
// se è vuoto... leggo da DB e popolo!
if (answ.Length == 0)
{
answ = await resetSMIAsync(idxFamIn);
}
}
catch (Exception exc)
{
Log.Error($"Errore in compilazione State Machine Ingressi x Redis:{Environment.NewLine}{exc}");
}
return answ;
}
/// <summary>
/// Statistiche ODL calcolate (da stored stp_STAT_ODL)
/// </summary>
/// <returns></returns>
public Task<List<StatODLModel>> StatOdl(int IdxOdl)
{
return SpecDbController.OdlStart(IdxOdl);
}
/// <summary>
/// restituisce il valOut da REDIS associato al tag richeisto
/// </summary>
/// <param name="redKey">Chiave in cui cercare il valOut</param>
/// <returns></returns>
public string TagConfGetKey(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;
}
/// <summary>
/// Elenco setup dei tag conf correnti
/// </summary>
/// <returns></returns>
public Task<Dictionary<string, List<TagData>>> TagsGetAll()
{
return Task.FromResult(currTagConf);
}
/// <summary>
/// Esegue traduzione dato vocabolario da Lingua + Lemma
/// </summary>
/// <param name="lemma"></param>
/// <param name="lingua"></param>
/// <returns></returns>
public string Traduci(string lemma, string lingua)
{
string answ = $"[{lemma}]";
// verifico se ho qualcosa nell'obj vocabolario...
if (ObjVocabolario == null || ObjVocabolario.Count == 0)
{
// inizializzo il vocabolario...
ObjVocabolario = VocabolarioGetAll();
}
var record = ObjVocabolario.Where(x => x.Lingua == lingua && x.Lemma == lemma).FirstOrDefault();
if (record != null)
{
answ = record.Traduzione;
}
return answ;
}
public async Task<bool> updateDossierValue(DossierModel currDoss, FluxLogDTO editFL)
{
bool answ = false;
// recupero intero set valori dossier deserializzando...
var fluxLogList = FluxLogDtoGetByFlux(currDoss.Valore);
await Task.Delay(1);
// se tutto ok
if (fluxLogList != null)
{
// da provare...!!!!
// elimino vecchio record
var currRec = fluxLogList.FirstOrDefault(x => x.CodFlux == editFL.CodFlux && x.dtEvento == editFL.dtEvento);
if (currRec != null)
{
fluxLogList.Remove(currRec);
// aggiungo nuovo
fluxLogList.Add(editFL);
}
// serializzo nuovamente valOut
DossierFluxLogDTO? result = new DossierFluxLogDTO();
var ODLflux = result.ODL.ToList();
foreach (var item in fluxLogList)
{
ODLflux.Add(item);
}
DossierFluxLogDTO updatedResult = new DossierFluxLogDTO() { ODL = ODLflux };
string rawVal = JsonConvert.SerializeObject(updatedResult);
currDoss.Valore = rawVal;
// aggiorno record sul DB
await SpecDbController.DossiersUpdateValore(currDoss);
}
return answ;
}
/// <summary>
/// Effettua UPSERT elenco parametri correnti x IOB (se c'è UPDATE, se manca ADD)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="innovations"></param>
/// <returns></returns>
public async Task<bool> UpsertCurrObjItemsAsync(string idxMacchina, List<ObjItemDTO> innovations)
{
bool answ = false;
if (innovations != null)
{
Log.Info($"upsertCurrObjItems | idxMacchina: {idxMacchina} | {innovations.Count} innovations");
// leggo i valori attuali...
List<ObjItemDTO> actValues = await MachineParamListAsync(idxMacchina);
// per ogni valOut passatomi faccio insert o update rispetto elenco valori correnti in REDIS
foreach (var item in actValues)
{
// cerco nelle innovazioni SE CI SIA il valOut...
var trovato = innovations.Find(obj => obj.uid == item.uid);
// se non trovato nelle innovazioni...
if (trovato == null)
{
// lo ri-aggiungo x non perderlo
innovations.Add(item);
Log.Trace($"innovations | add | item.uid: {item.uid} | item.value: {item.value}");
}
else
// altrimenti aggiorno campo (non trasmesso) name e tengo il resto...
{
trovato.name = item.name;
Log.Info($"innovations | update | item.uid: {item.uid} | item.value: {item.value} --> {trovato.value} ");
}
}
// serializzo e salvo
string serVal = JsonConvert.SerializeObject(innovations);
var currKey = Utils.RedKeyCurrObjItems(idxMacchina, MpIoNS);
RedisValue rawData = await redisDb.StringSetAsync(currKey, serVal);
}
return answ;
}
/// <summary>
/// Restituisce il valore SPECIFICATO per la state machine ingressi
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
/// </summary>
/// <param name="idxFamIn"></param>
/// <param name="idxMicroStato"></param>
/// <param name="valoreIn"></param>
/// <returns></returns>
public async Task<string> ValoreSmiAsync(int idxFamIn, int idxMicroStato, int valoreIn)
{
string valOut = "";
var currHash = Utils.GetHashSMI(idxFamIn);
string field = $"{idxMicroStato}_{valoreIn}";
var searchVal = await RedisGetHashFieldAsync(currHash, field);
if (!searchVal.HasValue)
{
// ricarico tabella (salvando in redis x ricerca successiva)!
var valori = await StateMachInByKeyAsync(idxFamIn);
if (valori.Any(x => x.Key == field))
{
searchVal = valori.FirstOrDefault(x => x.Key == field).Value;
}
}
valOut = $"{searchVal}";
return valOut;
}
/// <summary>
/// Elenco completo tabella Vocabolario
/// </summary>
/// <returns></returns>
public List<VocabolarioModel> VocabolarioGetAll()
{
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
List<VocabolarioModel>? result = new List<VocabolarioModel>();
string source = "REDIS";
// cerco in redis...
RedisValue rawData = redisDb.StringGet(Utils.redisVocabolario);
if (!string.IsNullOrEmpty($"{rawData}"))
{
result = JsonConvert.DeserializeObject<List<VocabolarioModel>>($"{rawData}");
}
else
{
result = SpecDbController.VocabolarioGetAll();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(Utils.redisVocabolario, rawData, getRandTOut(redisLongTimeCache / 5));
source = "DB";
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"VocabolarioGetAll Read from {source}: {ts.TotalMilliseconds}ms");
if (result == null)
{
result = new List<VocabolarioModel>();
}
return result;
}
#endregion Public Methods
#region Internal Methods
/// <summary>
/// Recupera ArtNum dato CodArt (per impianti che accettano solo INT in scrittura)
/// </summary>
/// <param name="CodArt">
/// CodArt richiesto, se vuoto restituisce TUTTI i valori in tabella di decodifica
/// </param>
/// <returns>Dizionario contenente le righe delle codifiche attive Articolo/Numero</returns>
internal async Task<Dictionary<string, int>> GetArtNumAsync(string codArt)
{
Dictionary<string, int> answ = new Dictionary<string, int>();
var currData = await DecNumArtGetFiltAsync(codArt);
foreach (var item in currData)
{
answ.Add(item.CodArticolo, item.NumART);
}
return answ;
}
#endregion Internal Methods
#region Protected Fields
protected Random rand = new Random();
#endregion Protected Fields
#region Protected Properties
protected string canCacheParametri { get; set; } = "";
#endregion Protected Properties
#region Protected Methods
/// <summary>
/// Restituisce un timeout dai minuti richiesti + tempo random 1..60 sec
/// </summary>
/// <param name="stdMinutes"></param>
/// <returns></returns>
protected TimeSpan getRandTOut(double stdMinutes)
{
double rndValue = stdMinutes + (double)rand.Next(1, 60) / 60;
return TimeSpan.FromMinutes(rndValue);
}
#endregion Protected Methods
#region Private Fields
private static IConfiguration _configuration = null!;
private static ILogger<MpDataService> _logger = null!;
private static Logger Log = LogManager.GetCurrentClassLogger();
private static IMtcSetupService MtcService = null!;
#if false
/// <summary>
/// Elenco completo valori Macchine 2 Slave
/// </summary>
/// <returns></returns>
public List<Macchine2SlaveModel> Macchine2SlaveGetAll()
{
List<Macchine2SlaveModel>? result = new List<Macchine2SlaveModel>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
string readType = "DB";
string currKey = $"{Utils.redisBaseAddr}:M2STab";
// cerco in redis dato valore sel macchina...
RedisValue rawData = redisDb.StringGet(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<List<Macchine2SlaveModel>>($"{rawData}");
readType = "REDIS";
}
else
{
result = IocDbController.Macchine2Slave();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
redisDb.StringSet(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (result == null)
{
result = new List<Macchine2SlaveModel>();
}
stopWatch.Stop();
TimeSpan ts = stopWatch.Elapsed;
Log.Debug($"Macchine2SlaveGetAll | Read from {readType}: {ts.TotalMilliseconds}ms");
return result;
}
#endif
private readonly IServiceScopeFactory _scopeFactory;
/// <summary>
/// Provider CultureInfo x parse valori (es dataora)
/// </summary>
private CultureInfo ciProvider = CultureInfo.InvariantCulture;
/// <summary>
/// Formato dataora standard x parsing
/// </summary>
private string dtFormat = "yyyyMMddHHmmssfff";
/// <summary>
/// Ultima esecuzione pulizia RRL x evitgare congestioni
/// </summary>
private DateTime lastCleanupRRL = DateTime.Now.AddHours(-1);
/// <summary>
/// MS max age x dato MSE
/// </summary>
private int maxAge = 2000;
private string MpIoNS = "";
/// <summary>
/// Oggetto vocabolario x uso continuo traduzione
/// </summary>
private List<VocabolarioModel> ObjVocabolario = new List<VocabolarioModel>();
/// <summary>
/// Oggetto per connessione a REDIS
/// </summary>
private ConnectionMultiplexer redisConn = null!;
/// <summary>
/// Oggetto per connessione a REDIS modalità admin (ex flux dati)
/// </summary>
private ConnectionMultiplexer redisConnAdmin = null!;
/// <summary>
/// Oggetto DB redis da impiegare x chiamate R/W
/// </summary>
private IDatabase redisDb = null!;
private int redisLongTimeCache = 5;
private int redisShortTimeCache = 2;
/// <summary>
/// Generatore random classe
/// </summary>
private Random rnd = new Random();
private bool useFactory = false;
#endregion Private Fields
#region Private Methods
/// <summary>
/// Verifica se sia necessario inserire un cambio di stato impianto (DiarioDi Bordo) in modalità batch
/// </summary>
/// <param name="tipoInput"></param>
/// <param name="IdxMacchina"></param>
/// <param name="InizioStato"></param>
/// <param name="IdxTipo"></param>
/// <param name="CodArt"></param>
/// <param name="Value"></param>
/// <param name="MatrOpr"></param>
/// <param name="pallet"></param>
private async Task CheckCambiaStatoBatchAsync(tipoInputEvento tipoInput, string IdxMacchina, DateTime InizioStato, int IdxTipo, string CodArt, string Value, int MatrOpr, string pallet)
{
await IocDbController.CheckCambiaStatoBatchAsync(tipoInput, IdxMacchina, InizioStato, IdxTipo, CodArt, Value, MatrOpr, pallet);
#if false
List<TransizioneStatiModel> listTransit = new List<TransizioneStatiModel>();
TransizioneStatiModel? rigaTrans = null;
switch (tipoInput)
{
case tipoInputEvento.barcode:
// effettuo cambio stato INDIPENDENTEMENTE da stato precedente
listTransit = await IocDbController.SMES_getUserForcedAsync(IdxMacchina, IdxTipo);
if (listTransit.Count > 0)
{
rigaTrans = listTransit.FirstOrDefault();
// solo se cambia stato...
if (rigaTrans != null && rigaTrans.IdxStato != rigaTrans.next_IdxStato)
{
await IocDbController.DDB_InsStatoBatchAsync(IdxMacchina, InizioStato, rigaTrans.next_IdxStato, CodArt, Value, MatrOpr, pallet);
// aggiorno MSE
await IocDbController.RecalcMseAsync(IdxMacchina, 0);
}
}
else
{
Log.Debug($"Non trovata riga per: BARCODE | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}");
}
break;
case tipoInputEvento.hw:
// verifico se ci sia necessità di cambio stato
listTransit = await IocDbController.SMES_getHwTransitionsAsync(IdxMacchina, IdxTipo);
if (listTransit.Count > 0)
{
rigaTrans = listTransit.FirstOrDefault();
if (rigaTrans != null && rigaTrans.IdxStato != rigaTrans.next_IdxStato)
{
await IocDbController.DDB_InsStatoBatchAsync(IdxMacchina, InizioStato, rigaTrans.next_IdxStato, CodArt, Value, MatrOpr, pallet);
// aggiorno MSE
await IocDbController.RecalcMseAsync(IdxMacchina, 0);
}
}
else
{
Log.Debug($"Non trovata riga per: HW | IdxMacchina: {IdxMacchina} | IdxTipo: {IdxTipo} | CodArt: {CodArt} | Value: {Value} | MatrOpr: {MatrOpr} | pallet: {pallet}");
}
break;
default:
break;
}
#endif
}
/// <summary>
/// Restituisce l'elenco codici flusso (da confFlux) x una macchina (se presenti) Impiegata
/// anche cache redis
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
private async Task<List<string>> ConfFluxMach(string idxMacchina)
{
List<string> resultList = new List<string>();
string tag = string.IsNullOrEmpty(idxMacchina) ? "ALL" : idxMacchina;
var currKey = $"{Utils.redisConfFlux}:{tag}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
resultList = JsonConvert.DeserializeObject<List<string>>($"{rawData}") ?? new();
}
else
{
var dbData = await IocDbController.ConfFluxFiltAsync(idxMacchina);
resultList = dbData
.Select(x => x.CodFlux)
.ToList();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(resultList);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (resultList == null)
{
resultList = new();
}
return resultList;
}
/// <summary>
/// Svuota la cache redis x l'elenco delle righe di confFlux x una macchina (se presenti)
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
private async Task<bool> DossierLastByMachResetAsync(string idxMacchina)
{
bool answ = false;
var currKey = $"{Utils.redisDossByMacLast}:{idxMacchina}";
await redisDb.KeyDeleteAsync(currKey);
return answ;
}
/// <summary>
/// Helper standardizzazione valOut dataora ricevuto da IOB remoti
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private string dtFormStd(string? s)
{
return s?.Length > 17 ? s[..17] : s?.PadRight(17, '0') ?? string.Empty;
}
/// <summary>
/// Restituisce l'elenco delle data-ora di confFlux x una macchina (se presenti) Impiegata
/// anche cache redis
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="numMax">num record da recuperare</param>
/// <returns></returns>
private async Task<List<DateTime>> FluxLogFirstByMachAsync(string idxMacchina, int numMax = 10)
{
List<DateTime> resultList = new List<DateTime>();
var currKey = $"{Utils.redisFluxByMacFirst}:{idxMacchina}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
resultList = JsonConvert.DeserializeObject<List<DateTime>>($"{rawData}") ?? new();
}
else
{
var dbData = await IocDbController.FluxLogFirstByMaccAsync(idxMacchina, numMax);
resultList = dbData
.Select(x => x.dtEvento)
.ToList();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(resultList);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache));
}
if (resultList == null)
{
resultList = new List<DateTime>();
}
return resultList;
}
/// <summary>
/// Effettua vera chiamata x salvataggio snapshot dati FluxLog
/// </summary>
/// <param name="id"></param>
/// <param name="maxSec"></param>
/// <param name="caller"></param>
/// <returns></returns>
private async Task<string> FluxLogSaveSnapshotAsync(string id, DateTime dtStart, DateTime dtEnd, string caller)
{
string answ = "";
DateTime dataOraEvento = DateTime.Now;
Log.Debug($"{caller} | Richiesta snapshot dati FluxLog macchina: id: {id} | periodo: {dtStart} - {dtEnd}");
try
{
bool fatto = await IocDbController.FluxLogTakeSnapshotLastAsync(id, dtStart, dtEnd);
answ = fatto ? "OK" : "KO";
}
catch (Exception exc)
{
Log.Error($"Errore in {caller}{Environment.NewLine}{exc}");
answ = "NO";
}
return answ;
}
/// <summary>
/// Recupero info ODL corrente da dati prod macchina
/// </summary>
/// <param name="idxMacchina"></param>
/// <returns></returns>
private async Task<string> GetCurrOdlByProdAsync(string idxMacchina)
{
string answ = "";
// recupero stato...
var datiProd = await StatoProdMacchinaAsync(idxMacchina, DateTime.Now);
if (datiProd != null)
{
answ = datiProd.IdxOdl.ToString();
}
// ultimo controllo su idxOdl...
answ = answ == "" ? "0" : answ;
// restituisco!
return answ;
}
/// <summary>
/// Restituisce il valOut booleano se la macchina sia di tipo MULTI (con più state machine x INGRESSI)
/// usando dati macchina in cache per evitare lookup ridondanti
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="datiMacc"></param>
/// <returns></returns>
private bool isMulti(string idxMacchina, Dictionary<string, string> datiMacc)
{
bool answ = false;
try
{
answ = Convert.ToBoolean(datiMacc.ContainsKey("Multi") && datiMacc["Multi"] == "1");
}
catch (Exception exc)
{
Log.Error($"Eccezione in isMulti{Environment.NewLine}{exc}");
}
return answ;
}
private async Task<HashSet<string>> ListMasterAsync()
{
HashSet<string> result = new();
string currKey = $"{Utils.redisBaseAddr}:ListMaster";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<HashSet<string>>($"{rawData}") ?? new();
}
else
{
var fullList = await Macchine2SlaveGetAllAsync();
result = fullList.Select(x => x.IdxMacchina).ToHashSet<string>();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
}
return result;
}
private async Task<HashSet<string>> ListSlaveAsync()
{
HashSet<string> result = new();
string currKey = $"{Utils.redisBaseAddr}:ListSlave";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue)
{
result = JsonConvert.DeserializeObject<HashSet<string>>($"{rawData}") ?? new();
}
else
{
var fullList = await Macchine2SlaveGetAllAsync();
result = fullList.Select(x => x.IdxMacchinaSlave).Distinct().ToHashSet<string>();
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, getRandTOut(redisLongTimeCache * 10));
}
return result;
}
private async Task<bool> POdlFlushCache()
{
bool answ = false;
RedisValue pattern = new RedisValue($"{Utils.redisXdlData}:*");
answ = await RedisFlushPatternAsync(pattern);
pattern = new RedisValue($"{Utils.redisPOdlByOdl}:*");
answ = await RedisFlushPatternAsync(pattern);
pattern = new RedisValue($"{Utils.redisPOdlByPOdl}:*");
answ = await RedisFlushPatternAsync(pattern);
pattern = new RedisValue($"{Utils.redisPOdlList}:*");
answ = await RedisFlushPatternAsync(pattern);
return answ;
}
/// <summary>
/// Calcola l'effettivo valOut da passare alla macchina a stati INGRESSI usando dati macchina in cache
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="valore"></param>
/// <param name="datiMacc"></param>
/// <returns></returns>
private string preProcInput(string idxMacchina, string valore, Dictionary<string, string> datiMacc)
{
string newVal = "";
try
{
// variabili
int valINT = 0;
int BitFilt = 0;
int BSR = 0;
bool ExplodeBit = false;
int NumBit = 0;
int newValInt = 0;
// recupero parametri dalla cache...
int.TryParse(datiMacc.ContainsKey("BitFilt") ? datiMacc["BitFilt"] : "0", out BitFilt);
int.TryParse(datiMacc.ContainsKey("BSR") ? datiMacc["BSR"] : "0", out BSR);
Boolean.TryParse(datiMacc.ContainsKey("ExplodeBit") ? datiMacc["ExplodeBit"] : "false", out ExplodeBit);
// non usato (x ora)
int.TryParse(datiMacc.ContainsKey("NumBit") ? datiMacc["NumBit"] : "0", out NumBit);
// recupero valOut
valINT = int.Parse(valore, NumberStyles.HexNumber);
// filtro
newValInt = MP.Core.Utils.bMaskInt(valINT, BitFilt);
// effettuo eventuale BitShiftRight
if (BSR > 0)
{
newValInt = newValInt >> BSR;
}
// effettuo eventuale esplosione in BIT esclusivi
if (ExplodeBit)
{
newValInt = Convert.ToInt32(1 << newValInt);
}
// riconverto a STRING HEX!!!
newVal = newValInt.ToString("X");
}
catch
{
newVal = valore;
}
return newVal;
}
private async Task resetCacheArticoli()
{
RedisValue pattern = new RedisValue($"{Utils.redisArtByDossier}:*");
await RedisFlushPatternAsync(pattern);
pattern = new RedisValue($"{Utils.redisArtList}:*");
await RedisFlushPatternAsync(pattern);
}
/// <summary>
/// Restitusice elenco KVP dei campi DatiMacchine + StatoMacchine per l'impianto indicato
/// </summary>
/// <param name="idxMacc"></param>
/// <returns></returns>
private async Task<Dictionary<string, string>> ResetDatiMacchinaAsync(string idxMacc)
{
Dictionary<string, string> result = new Dictionary<string, string>();
VMSFDModel? dbResult = null;
if (useFactory)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var mtcService = scope.ServiceProvider.GetRequiredService<MpIocController>();
dbResult = await mtcService.VMSFDGetByMaccAsync(idxMacc);
}
else
{
dbResult = await IocDbController.VMSFDGetByMaccAsync(idxMacc);
}
if (dbResult == null) return new Dictionary<string, string>();
double numSecCache = redisLongTimeCache;
// converto in formato dizionario...
if (dbResult != null)
{
// salvo 1:1 i valori... STATO
result.Add("IdxMicroStato", $"{dbResult.IdxMicroStato}");
result.Add("IdxStato", $"{dbResult.IdxStato}");
result.Add("CodArticolo", $"{dbResult.CodArticolo}");
result.Add("insEnabled", $"{dbResult.InsEnabled}");
result.Add("sLogEnabled", $"{dbResult.SLogEnabled}");
result.Add("pallet", $"{dbResult.Pallet}");
result.Add("CodArticolo_A", $"{dbResult.CodArticoloA}");
result.Add("CodArticolo_B", $"{dbResult.CodArticoloB}");
result.Add("TempoCicloBase", $"{dbResult.TempoCicloBase}");
result.Add("PzPalletProd", $"{dbResult.PzPalletProd}");
result.Add("MatrOpr", $"{dbResult.MatrOpr}");
result.Add("lastVal", $"{dbResult.LastVal}");
result.Add("TCBase", $"{dbResult.TempoCicloBase}");
//...e SETUP
result.Add("CodMacc", $"{dbResult.Codmacchina}");
result.Add("IdxFamIn", $"{dbResult.IdxFamigliaIngresso}");
result.Add("Multi", $"{dbResult.Multi}");
result.Add("BitFilt", $"{dbResult.BitFilt}");
result.Add("MaxVal", $"{dbResult.MaxVal}");
result.Add("BSR", $"{dbResult.Bsr}");
result.Add("ExplodeBit", $"{dbResult.ExplodeBit}");
result.Add("NumBit", $"{dbResult.NumBit}");
result.Add("IdxFamMacc", $"{dbResult.IdxFamiglia}");
result.Add("simplePallet", $"{dbResult.SimplePallet}");
result.Add("palletChange", $"{dbResult.PalletChange}");
// durata cache in secondi dal valOut insEnabled...
//double numSecCache = ((result["insEnabled"].ToLower() == "true") ? redisShortTimeCache : redisLongTimeCache);
numSecCache = dbResult.InsEnabled ? redisShortTimeCache : redisLongTimeCache;
}
else
{
}
// dati master/slave
string isMaster = (await ListMasterAsync()).Contains(idxMacc) ? "1" : "0";
string isSlave = (await ListSlaveAsync()).Contains(idxMacc) ? "1" : "0";
result.Add("Master", isMaster);
result.Add("Slave", isSlave);
// Processing redis in transazoine...
var redKey = Utils.RedKeyDatiMacc(idxMacc, MpIoNS);
// variazione con redis transaction...
var transaction = redisDb.CreateTransaction();
// 1. Eliminiamo la chiave (rimuove i vecchi campi)
_ = transaction.KeyDeleteAsync(redKey);
// 2. Prepariamo gli HashEntry per il batch (più efficiente di un Dictionary)
HashEntry[] entries = result.Select(kvp => new HashEntry(kvp.Key, kvp.Value)).ToArray();
// 3. Inseriamo i nuovi valori
_ = transaction.HashSetAsync(redKey, entries);
// 4. Impostiamo l'expiration in un unico colpo
_ = transaction.KeyExpireAsync(redKey, TimeSpan.FromSeconds(numSecCache));
// Eseguiamo tutto in un unico viaggio verso Redis
bool success = await transaction.ExecuteAsync();
return result;
}
/// <summary>
/// Resetta (rileggendo) i dati della State Machine ingressi nel formato
/// currKey: cState_nVal (current MICRO-STATE + "_" + new Value)
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
/// </summary>
/// <param name="idxFamIn"></param>
/// <returns></returns>
private async Task<KeyValuePair<string, string>[]> resetSMIAsync(int idxFamIn)
{
var currHash = Utils.GetHashSMI(idxFamIn);
// leggo da DB...
var tabSMI = await IocDbController.StateMachineIngressiAsync(idxFamIn);
KeyValuePair<string, string>[] answ = new KeyValuePair<string, string>[tabSMI.Count];
// salvo tutti i valori StateMachineIngressi...
int i = 0;
string key = "";
string val = "";
foreach (var item in tabSMI)
{
key = string.Format("{0}_{1}", item.IdxMicroStato, item.ValoreIngresso);
val = string.Format("{0}_{1}", item.IdxTipoEvento, item.NextIdxMicroStato);
answ[i] = new KeyValuePair<string, string>(key, val);
i++;
}
// verifico il timeout (default 60 sec...)
int tOut = 300;
var sTOutSmi = await tryGetConfigAsync("TmOut.SMI");
if (!string.IsNullOrEmpty(sTOutSmi))
{
int.TryParse(sTOutSmi, out tOut);
}
// salvo in redis!
await RedisSetHashAsync(currHash, answ, tOut);
return answ;
}
#if false
/// <summary>
/// Scrive una riga di evento nel db + check cambio stato DiarioDiBordo
/// </summary>
/// <param name="newRec">codice macchina</param>
/// <returns></returns>
private inputComandoMapo scriviRigaEvento(EventListModel newRec)
{
bool inserito = false;
try
{
// inserisco evento
inserito = IocDbController.EvListInsert(newRec);
// faccio controllo per eventuale cambio stato da tab transizioni...
CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
}
catch (Exception exc)
{
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
}
// formatto output
inputComandoMapo answ = new inputComandoMapo();
answ.outValue = inserito.ToString();
answ.needStatusRefresh = true;
return answ;
}
#endif
/// <summary>
/// Scrive una riga di evento nel db + check cambio stato DiarioDiBordo
/// </summary>
/// <param name="newRec">codice macchina</param>
/// <returns></returns>
private async Task<inputComandoMapo> scriviRigaEventoAsync(EventListModel newRec)
{
bool inserito = false;
try
{
// inserisco evento
inserito = await IocDbController.EvListInsertAsync(newRec);
// faccio controllo per eventuale cambio stato da tab transizioni...
await CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
}
catch (Exception exc)
{
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
}
// formatto output
inputComandoMapo answ = new inputComandoMapo();
answ.outValue = inserito.ToString();
answ.needStatusRefresh = true;
return answ;
}
/// <summary>
/// Scrive una riga evento + una riga microstato insieme, ed effettua verifica necessità cambio stato
/// </summary>
/// <param name="newRecMsm">Record MicroStatoMacchina</param>
/// <param name="newRecEv">record EventList</param>
/// <returns></returns>
private async Task<inputComandoMapo> scriviRigaEventoAsync(MicroStatoMacchinaModel newRecMsm, EventListModel newRecEv)
{
bool inserito = false;
if (useFactory)
{
await using var scope = _scopeFactory.CreateAsyncScope();
var iocService = scope.ServiceProvider.GetRequiredService<IIocService>();
// inserisco evento
inserito = await iocService.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
// faccio controllo per eventuale cambio stato da tab transizioni...
await iocService.CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRecEv.IdxMacchina, newRecEv.InizioStato ?? DateTime.Now, newRecEv.IdxTipo, newRecEv.CodArticolo, newRecEv.Value, newRecEv.MatrOpr, newRecEv.pallet);
}
else
{
try
{
// inserisco evento
inserito = await IocDbController.EvListMicroStatoInsertAsync(newRecMsm, newRecEv);
// faccio controllo per eventuale cambio stato da tab transizioni...
await CheckCambiaStatoBatchAsync(tipoInputEvento.hw, newRecEv.IdxMacchina, newRecEv.InizioStato ?? DateTime.Now, newRecEv.IdxTipo, newRecEv.CodArticolo, newRecEv.Value, newRecEv.MatrOpr, newRecEv.pallet);
}
catch (Exception exc)
{
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRecEv.IdxMacchina} | IdxTipo {newRecEv.IdxTipo} | codArticolo {newRecEv.CodArticolo} | Value {newRecEv.Value} | MatrOpr {newRecEv.MatrOpr} | Pallet {newRecEv.pallet} | dTime {newRecEv.InizioStato}{Environment.NewLine}{exc}");
}
}
// formatto output
inputComandoMapo answ = new inputComandoMapo();
answ.outValue = inserito.ToString();
answ.needStatusRefresh = true;
return answ;
}
/// <summary>
/// Scrive una riga di evento manuale (barcode) nel db + check cambio stato DiarioDiBordo
/// </summary>
/// <param name="newRec">codice macchina</param>
/// <returns></returns>
private async Task<inputComandoMapo> scriviRigaEventoBarcodeAsync(EventListModel newRec)
{
bool inserito = false;
try
{
// inserisco evento
inserito = await IocDbController.EvListInsertAsync(newRec);
// faccio controllo per eventuale cambio stato da tab transizioni...
await CheckCambiaStatoBatchAsync(tipoInputEvento.barcode, newRec.IdxMacchina, newRec.InizioStato ?? DateTime.Now, newRec.IdxTipo, newRec.CodArticolo, newRec.Value, newRec.MatrOpr, newRec.pallet);
}
catch (Exception exc)
{
Log.Error($"Errore in scriviRigaEvento | IdxMacchina {newRec.IdxMacchina} | IdxTipo {newRec.IdxTipo} | codArticolo {newRec.CodArticolo} | Value {newRec.Value} | MatrOpr {newRec.MatrOpr} | Pallet {newRec.pallet} | dTime {newRec.InizioStato}{Environment.NewLine}{exc}");
}
// formatto output
inputComandoMapo answ = new inputComandoMapo();
answ.outValue = inserito.ToString();
answ.needStatusRefresh = true;
return answ;
}
/// <summary>
/// Stato prod macchina (completo)
/// </summary>
/// <param name="idxMacchina"></param>
/// <param name="dtReq"></param>
/// <returns></returns>
private async Task<StatoProdModel> StatoProdMacchinaAsync(string idxMacchina, DateTime dtReq, bool forceDb = false)
{
// setup parametri costanti
string source = "DB";
StatoProdModel? result = new StatoProdModel();
// cerco in _redisConn...
string currKey = $"{Utils.redisStatoProd}:{idxMacchina}:{dtReq:HHmm}";
RedisValue rawData = await redisDb.StringGetAsync(currKey);
if (rawData.HasValue && !forceDb)
{
result = JsonConvert.DeserializeObject<StatoProdModel>($"{rawData}");
source = "REDIS";
}
else
{
result = await IocDbController.StatoProdMacchinaAsync(idxMacchina, dtReq);
// serializzo e salvo...
rawData = JsonConvert.SerializeObject(result);
await redisDb.StringSetAsync(currKey, rawData, TimeSpan.FromSeconds(60));
}
if (result == null)
{
result = new StatoProdModel();
}
return result;
}
/// <summary>
/// Restituisce valOut della stringa (SE disponibile)
/// </summary>
/// <param name="keyName"></param>
/// <returns></returns>
private async Task<string> tryGetConfigAsync(string keyName)
{
string answ = "";
// preselezione valori
var configData = await ConfigGetAllAsync();
var currRec = configData.FirstOrDefault(x => x.Chiave == keyName);
if (currRec != null)
{
answ = currRec.Valore;
}
return answ;
}
#if false
/// <summary>
/// Restituisce il valOut SPECIFICATO per la state machine ingressi
/// value: iTipoEv_nState (IdxTipoEv da trasmettere + New MICRO-STATE)
/// </summary>
/// <param name="idxFamIn"></param>
/// <param name="idxMicroStato"></param>
/// <param name="valoreIn"></param>
/// <returns></returns>
private string valoreSMI(int idxFamIn, int idxMicroStato, int valoreIn)
{
var currHash = Utils.GetHashSMI(idxFamIn);
string field = string.Format("{0}_{1}", idxMicroStato, valoreIn);
return RedisGetHashFieldAsync(currHash, field);
}
#endif
/// <summary>
/// cerca codice in anagrafica macchine ed eventualmente inserisce nuova macchina
/// </summary>
/// <param name="IdxMacchina"></param>
private async Task verificaIdxMacchinaAsync(string IdxMacchina)
{
bool needDB = false;
try
{
// esecuzione in REDIS...cerco status macchina...
if ((await mDatiMacchineAsync(IdxMacchina)).Count == 0)
{
needDB = true;
}
}
catch { }
if (needDB)
{
// verifico se esiste su DB
var dbRec = await IocDbController.MacchineGetByIdxAsync(IdxMacchina);
if (dbRec == null)
{
MacchineModel newRec = new MacchineModel()
{
IdxMacchina = IdxMacchina,
CodMacchina = "0000",
Nome = IdxMacchina,
Descrizione = "Macchina non codificata",
Note = "-",
locazione = "",
RecipeArchivePath = "",
RecipePath = ""
};
await IocDbController.MacchineUpsertAsync(newRec);
// verifico ci sia un microstato macchina...
var recMSM = await IocDbController.MicroStatoMacchinaGetByIdxMaccAsync(IdxMacchina);
if (recMSM.Count == 0)
{
// inserisco nuovo stato...
MicroStatoMacchinaModel msRec = new MicroStatoMacchinaModel()
{
IdxMacchina = IdxMacchina,
IdxMicroStato = 0,
InizioStato = DateTime.Now,
Value = "00"
};
await IocDbController.MicroStatoMacchinaUpsertAsync(msRec);
}
}
}
}
#endregion Private Methods
}
}