1575 lines
65 KiB
C#
1575 lines
65 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using Org.BouncyCastle.Utilities;
|
|
using SMGen.Core;
|
|
using SMGen.Data.Controllers;
|
|
using SMGen.Data.Data;
|
|
using SMGen.Data.DbModels;
|
|
using StackExchange.Redis;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
|
|
namespace SMGen.Data.Services
|
|
{
|
|
public class SMGDataService
|
|
{
|
|
#region Public Fields
|
|
|
|
public static SMGenController dbController = null!;
|
|
|
|
#endregion Public Fields
|
|
|
|
#region Public Constructors
|
|
|
|
public SMGDataService(IConfiguration configuration, IConnectionMultiplexer redisConnMult)
|
|
{
|
|
_configuration = configuration;
|
|
// Conf cache
|
|
redisConn = redisConnMult;
|
|
redisDb = this.redisConn.GetDatabase();
|
|
|
|
// json serializer... FIX errore loop circolare https://www.ryadel.com/en/jsonserializationexception-self-referencing-loop-detected-error-fix-entity-framework-asp-net-core/
|
|
JSSettings = new JsonSerializerSettings()
|
|
{
|
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
|
};
|
|
|
|
// cod app
|
|
CodApp = _configuration["CodApp"];
|
|
// Conf DB
|
|
string connStr = _configuration.GetConnectionString("SMGen.DB");
|
|
if (string.IsNullOrEmpty(connStr))
|
|
{
|
|
Log.Info("ConnString empty!");
|
|
}
|
|
else
|
|
{
|
|
dbController = new SMGenController(configuration);
|
|
}
|
|
|
|
// chiudo log
|
|
Log.Info("Avviata classe WebDoorCreatorService");
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Properties
|
|
|
|
public string CodApp { get; set; } = "";
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Public Methods
|
|
|
|
public async Task<Dictionary<int, string>> AnagEventiGetAll()
|
|
{
|
|
string source = "DB";
|
|
Dictionary<int, string> dbResult = new Dictionary<int, string>();
|
|
try
|
|
{
|
|
// cerco da cache
|
|
string currKey = $"{Constants.rKeyEventi}";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<Dictionary<int, string>>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new Dictionary<int, string>();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.AnagEventiGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, UltraLongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new Dictionary<int, string>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"AnagEventiGetAll | {source} in: {ts.TotalMilliseconds} ms");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Exception during AnagEventiGetAll: {exc}{Environment.NewLine}");
|
|
}
|
|
return dbResult;
|
|
}
|
|
public async Task<Dictionary<int, string>> AnagStatiGetAll()
|
|
{
|
|
string source = "DB";
|
|
Dictionary<int, string> dbResult = new Dictionary<int, string>();
|
|
try
|
|
{
|
|
// cerco da cache
|
|
string currKey = $"{Constants.rKeyStati}";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<Dictionary<int, string>>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new Dictionary<int, string>();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.AnagStatiGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, UltraLongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new Dictionary<int, string>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"AnagStatiGetAll | {source} in: {ts.TotalMilliseconds} ms");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Exception during AnagStatiGetAll: {exc}{Environment.NewLine}");
|
|
}
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<bool> AnagEventinInsert(List<AnagEventiModelTemp> newEvList)
|
|
{
|
|
var dbResult = await dbController.AnagEventinInsert(newEvList);
|
|
return dbResult;
|
|
}
|
|
|
|
/// <summary>
|
|
/// </summary>
|
|
/// <param name="pattern"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> ExecFlushRedisPattern(RedisValue pattern)
|
|
{
|
|
bool answ = false;
|
|
var listEndpoints = redisConn.GetEndPoints();
|
|
foreach (var endPoint in listEndpoints)
|
|
{
|
|
var server = redisConn.GetServer(endPoint);
|
|
if (server != null)
|
|
{
|
|
var keyList = server.Keys(redisDb.Database, pattern);
|
|
foreach (var item in keyList)
|
|
{
|
|
await redisDb.KeyDeleteAsync(item);
|
|
}
|
|
answ = true;
|
|
}
|
|
}
|
|
|
|
return answ;
|
|
}
|
|
|
|
public async Task<List<FamIngressiViewModel>> FamIngressiGetAll()
|
|
{
|
|
string source = "DB";
|
|
List<FamIngressiViewModel> dbResult = new List<FamIngressiViewModel>();
|
|
try
|
|
{
|
|
// cerco da cache
|
|
string currKey = $"{Constants.rKeyFamIng}";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<List<FamIngressiViewModel>>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new List<FamIngressiViewModel>();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.FamIngressiGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, UltraLongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<FamIngressiViewModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"FamIngressiGetAll | {source} in: {ts.TotalMilliseconds} ms");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Exception during FamIngressiGetAll: {exc}{Environment.NewLine}");
|
|
}
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<List<FamStatiViewModel>> FamStatiGetAll()
|
|
{
|
|
string source = "DB";
|
|
List<FamStatiViewModel> dbResult = new List<FamStatiViewModel>();
|
|
try
|
|
{
|
|
// cerco da cache
|
|
string currKey = $"{Constants.rKeyFamStati}";
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
string? rawData = await redisDb.StringGetAsync(currKey);
|
|
if (!string.IsNullOrEmpty(rawData))
|
|
{
|
|
source = "REDIS";
|
|
var tempResult = JsonConvert.DeserializeObject<List<FamStatiViewModel>>(rawData);
|
|
if (tempResult == null)
|
|
{
|
|
dbResult = new List<FamStatiViewModel>();
|
|
}
|
|
else
|
|
{
|
|
dbResult = tempResult;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dbResult = dbController.FamStatiGetAll();
|
|
rawData = JsonConvert.SerializeObject(dbResult, JSSettings);
|
|
await redisDb.StringSetAsync(currKey, rawData, UltraLongCache);
|
|
}
|
|
if (dbResult == null)
|
|
{
|
|
dbResult = new List<FamStatiViewModel>();
|
|
}
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Debug($"FamStatiGetAll | {source} in: {ts.TotalMilliseconds} ms");
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Exception during FamStatiGetAll: {exc}{Environment.NewLine}");
|
|
}
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<Dictionary<string, FilesClass>> FilesGetAll()
|
|
{
|
|
Dictionary<string, FilesClass> dbResult = new Dictionary<string, FilesClass>();
|
|
string currKey = $"{Constants.FILES_TO_PROC}";
|
|
var rawData = await redisDb.HashGetAllAsync(currKey);
|
|
foreach (var item in rawData)
|
|
{
|
|
var desVal = JsonConvert.DeserializeObject<FilesClass>(item.Value!);
|
|
dbResult.Add($"{item.Name}", desVal!);
|
|
}
|
|
|
|
return dbResult;
|
|
}
|
|
|
|
public async Task<bool> FilesLoadRedis(Dictionary<string, FilesClass> filesDict)
|
|
{
|
|
bool fatto = false;
|
|
string currKey = $"{Constants.FILES_TO_PROC}";
|
|
await ExecFlushRedisPattern(currKey);
|
|
|
|
foreach (var item in filesDict)
|
|
{
|
|
string valSer = JsonConvert.SerializeObject(item.Value, JSSettings);
|
|
|
|
await RedHashUpsert(currKey, item.Key, valSer);
|
|
}
|
|
|
|
fatto = true;
|
|
|
|
return fatto;
|
|
}
|
|
|
|
public async Task<bool> FileUpdate(string origFileName, FilesClass fileNewInfo)
|
|
{
|
|
bool fatto = false;
|
|
string currKey = $"{Constants.FILES_TO_PROC}";
|
|
//await ExecFlushRedisPattern(currKey);
|
|
string valSer = JsonConvert.SerializeObject(fileNewInfo, JSSettings);
|
|
|
|
await RedHashUpsert(currKey, origFileName, valSer);
|
|
|
|
fatto = true;
|
|
|
|
return fatto;
|
|
}
|
|
public async Task<bool> TranInInsert(List<TransizioneIngressiModelTemp> newTIList, int currIdxFamiglia)
|
|
{
|
|
var dbResult = await dbController.TranInInsert(newTIList, currIdxFamiglia);
|
|
return dbResult;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
public Dictionary<int, string> eventsFromDb = new Dictionary<int, string>();
|
|
private bool b_rules_definition = false;
|
|
List<CsvClass> csvLines = new List<CsvClass>();
|
|
List<string> linesList = new List<string>();
|
|
private int n_bits = 0;
|
|
private string n_state_machine_index = "";
|
|
private int n_states = 0;
|
|
private string sz_state_machine_name = "";
|
|
public List<AnagEventiModelTemp> events2Add { get; set; } = new List<AnagEventiModelTemp>();
|
|
|
|
public List<AnagEventiModelTemp> eventsAll { get; set; } = new List<AnagEventiModelTemp>();
|
|
|
|
protected string bitCsvPath
|
|
{
|
|
get => _configuration.GetValue<string>("ServerConf:BitCsvPath");
|
|
}
|
|
|
|
protected string procRootDir
|
|
{
|
|
get => _configuration.GetValue<string>("ServerConf:ProcCsvRootPath");
|
|
}
|
|
|
|
protected List<string> States2Rules { get; set; } = new List<string>();
|
|
protected Dictionary<string, int> StatesAll { get; set; } = new Dictionary<string, int>();
|
|
protected Dictionary<string, int> StatesAll2 { get; set; } = new Dictionary<string, int>();
|
|
protected string statiCsvPath
|
|
{
|
|
get => _configuration.GetValue<string>("ServerConf:StatiCsvPath");
|
|
}
|
|
|
|
private List<string> actStates2Chk { get; set; } = new List<string>();
|
|
private List<string> Bits { get; set; } = new List<string>();
|
|
private Dictionary<string, int> evOk { get; set; } = new Dictionary<string, int>();
|
|
private FileLinesClass linesChecked { get; set; } = new FileLinesClass();
|
|
|
|
private List<string> nextStates2Chk { get; set; } = new List<string>();
|
|
private List<RuleClass> Rules { get; set; } = new List<RuleClass>();
|
|
private Dictionary<string, int> Events_to_send { get; set; } = new Dictionary<string, int>();
|
|
private List<string> States { get; set; } = new List<string>();
|
|
private List<TransizioneIngressiModelTemp> TranInList2add { get; set; } = new List<TransizioneIngressiModelTemp>();
|
|
|
|
|
|
/// <summary>
|
|
/// Verifica su DB eventi e stati
|
|
/// </summary>
|
|
/// <param name="currFile"></param>
|
|
/// <returns></returns>
|
|
public async Task<FileLinesClass> DoCheckUnusedEv(FilesClass currFile)
|
|
{
|
|
await Task.Delay(1);
|
|
States.Clear();
|
|
Bits.Clear();
|
|
Events_to_send.Clear();
|
|
Rules.Clear();
|
|
eventsAll.Clear();
|
|
evOk.Clear();
|
|
StatesAll.Clear();
|
|
string lineOk = "";
|
|
// recupero nome file x partire
|
|
string filePath = currFile.tempFileName;
|
|
FileLinesClass answ = new FileLinesClass();
|
|
string[] lines = File.ReadAllLines(filePath, Encoding.UTF8);
|
|
try
|
|
{
|
|
foreach (var line in lines)
|
|
{
|
|
lineOk = line.Trim();
|
|
if (!lineOk.StartsWith("#") && !string.IsNullOrEmpty(lineOk) && lineOk.Length >= 3)
|
|
{
|
|
if (lineOk.Contains("#"))
|
|
{
|
|
var lineSplit = lineOk.Split("#");
|
|
lineOk = lineSplit[0];
|
|
}
|
|
|
|
var sz_tokens = lineOk.Split(":");
|
|
|
|
var sz_temp = sz_tokens[0].Trim();
|
|
switch (sz_temp)
|
|
{
|
|
case "$DEFINITIONS":
|
|
b_rules_definition = false;
|
|
break;
|
|
|
|
case "$NAME":
|
|
break;
|
|
|
|
case "$IDX":
|
|
break;
|
|
|
|
case "$STATE":
|
|
if (!StatesAll.ContainsKey(sz_tokens[2].Trim().ToUpper()))
|
|
{
|
|
StatesAll.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
break;
|
|
|
|
case "$EVENT":
|
|
if (!Events_to_send.ContainsValue(int.Parse(sz_tokens[1].Trim().ToUpper())))
|
|
{
|
|
Events_to_send.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
var newEvent = new AnagEventiModelTemp()
|
|
{
|
|
IdxTipo = int.Parse(sz_tokens[1].Trim().ToUpper()),
|
|
Nome = sz_tokens[2].Trim().ToUpper()
|
|
};
|
|
break;
|
|
|
|
case "$RULES":
|
|
b_rules_definition = true;
|
|
break;
|
|
case "$DO":
|
|
b_rules_definition = false;
|
|
|
|
break;
|
|
default:
|
|
if (b_rules_definition)
|
|
{
|
|
var state = sz_temp.Trim().ToUpper();
|
|
var event_to_send = sz_tokens[1].Trim().ToUpper();
|
|
var next_state = sz_tokens[2].Trim().ToUpper();
|
|
|
|
var temp_rule = new RuleClass()
|
|
{
|
|
state = state,
|
|
event_to_send = event_to_send,
|
|
next_state = next_state
|
|
};
|
|
Rules.Add(temp_rule);
|
|
States2Rules.Add(next_state);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//linesChecked.Add(line, true);
|
|
}
|
|
}
|
|
foreach (var item in States2Rules)
|
|
{
|
|
if (!StatesAll2.ContainsKey(item))
|
|
{
|
|
StatesAll2.Add(item, StatesAll[item]);
|
|
}
|
|
}
|
|
foreach (var ev in Events_to_send)
|
|
{
|
|
var rule2Ev = Rules.FirstOrDefault(x => x.event_to_send == ev.Key);
|
|
if (rule2Ev != null)
|
|
{
|
|
if (!evOk.ContainsKey(ev.Key) && !evOk.ContainsValue(ev.Value))
|
|
{
|
|
evOk.Add(ev.Key, ev.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"{exc}{Environment.NewLine}");
|
|
}
|
|
|
|
answ.file = currFile.tempFileName;
|
|
answ.statesOK = StatesAll2;
|
|
answ.eventsOK = evOk;
|
|
answ.lines = lines.ToList();
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica su DB eventi e stati
|
|
/// </summary>
|
|
/// <param name="currFile"></param>
|
|
/// <returns></returns>
|
|
public async Task<FileLinesClass> DoCheckUnusedEvSt(FilesClass currFile)
|
|
{
|
|
await Task.Delay(1);
|
|
States.Clear();
|
|
Bits.Clear();
|
|
Events_to_send.Clear();
|
|
Rules.Clear();
|
|
eventsAll.Clear();
|
|
evOk.Clear();
|
|
StatesAll.Clear();
|
|
string lineOk = "";
|
|
// recupero nome file x partire
|
|
string filePath = currFile.tempFileName;
|
|
FileLinesClass answ = new FileLinesClass();
|
|
string[] lines = File.ReadAllLines(filePath, Encoding.UTF8);
|
|
try
|
|
{
|
|
foreach (var line in lines)
|
|
{
|
|
lineOk = line.Trim();
|
|
if (!lineOk.StartsWith("#") && !string.IsNullOrEmpty(lineOk) && lineOk.Length >= 3)
|
|
{
|
|
if (lineOk.Contains("#"))
|
|
{
|
|
var lineSplit = lineOk.Split("#");
|
|
lineOk = lineSplit[0];
|
|
}
|
|
|
|
var sz_tokens = lineOk.Split(":");
|
|
|
|
var sz_temp = sz_tokens[0].Trim();
|
|
switch (sz_temp)
|
|
{
|
|
case "$DEFINITIONS":
|
|
b_rules_definition = false;
|
|
break;
|
|
|
|
case "$NAME":
|
|
break;
|
|
|
|
case "$IDX":
|
|
break;
|
|
|
|
case "$STATE":
|
|
if (!StatesAll.ContainsKey(sz_tokens[2].Trim().ToUpper()))
|
|
{
|
|
StatesAll.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
break;
|
|
|
|
case "$EVENT":
|
|
if (!Events_to_send.ContainsValue(int.Parse(sz_tokens[1].Trim().ToUpper())))
|
|
{
|
|
Events_to_send.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
var newEvent = new AnagEventiModelTemp()
|
|
{
|
|
IdxTipo = int.Parse(sz_tokens[1].Trim().ToUpper()),
|
|
Nome = sz_tokens[2].Trim().ToUpper()
|
|
};
|
|
break;
|
|
|
|
case "$RULES":
|
|
b_rules_definition = true;
|
|
break;
|
|
case "$DO":
|
|
b_rules_definition = false;
|
|
|
|
break;
|
|
default:
|
|
if (b_rules_definition)
|
|
{
|
|
var state = sz_temp.Trim().ToUpper();
|
|
var event_to_send = sz_tokens[1].Trim().ToUpper();
|
|
var next_state = sz_tokens[2].Trim().ToUpper();
|
|
|
|
var temp_rule = new RuleClass()
|
|
{
|
|
state = state,
|
|
event_to_send = event_to_send,
|
|
next_state = next_state
|
|
};
|
|
Rules.Add(temp_rule);
|
|
States2Rules.Add(next_state);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//linesChecked.Add(line, true);
|
|
}
|
|
}
|
|
foreach (var item in States2Rules)
|
|
{
|
|
if (!StatesAll2.ContainsKey(item))
|
|
{
|
|
StatesAll2.Add(item, StatesAll[item]);
|
|
}
|
|
}
|
|
foreach (var ev in Events_to_send)
|
|
{
|
|
var rule2Ev = Rules.FirstOrDefault(x => x.event_to_send == ev.Key);
|
|
if (rule2Ev != null)
|
|
{
|
|
if (!evOk.ContainsKey(ev.Key) && !evOk.ContainsValue(ev.Value))
|
|
{
|
|
evOk.Add(ev.Key, ev.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"{exc}{Environment.NewLine}");
|
|
}
|
|
|
|
answ.file = currFile.tempFileName;
|
|
answ.statesOK = StatesAll2;
|
|
answ.eventsOK = evOk;
|
|
answ.lines = lines.ToList();
|
|
return answ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Valuta un file di ruoles x ingressi 2 eventi e restituisce esito
|
|
/// </summary>
|
|
/// <param name="currFile">Path file *.rul da processare</param>
|
|
/// <param name="saveToDb">Indica se salvare sul DB</param>
|
|
/// <param name="doProcState">Indica se processare parte state (x state machine stati)</param>
|
|
/// <returns></returns>
|
|
///
|
|
public async Task<FilesClass> EvalIn2EvRuleFile(FilesClass currFile, bool saveToDb, bool doProcState)
|
|
{
|
|
await Task.Delay(1);
|
|
Dictionary<string, string> evSt2Change = new Dictionary<string, string>();
|
|
sz_state_machine_name = "";
|
|
n_state_machine_index = "";
|
|
n_states = 0;
|
|
n_bits = 0;
|
|
States.Clear();
|
|
Bits.Clear();
|
|
Events_to_send.Clear();
|
|
Rules.Clear();
|
|
eventsAll.Clear();
|
|
evOk.Clear();
|
|
StatesAll.Clear();
|
|
string line = "";
|
|
// recupero nome file x partire
|
|
string filePath = currFile.tempFileName;
|
|
string errMgs = "";
|
|
eventsFromDb = await AnagEventiGetAll();
|
|
try
|
|
{
|
|
// stream lettura file
|
|
var isProcActive = true;
|
|
if (isProcActive)
|
|
{
|
|
using (StreamReader sr = new StreamReader(filePath))
|
|
{
|
|
while ((line = await sr.ReadLineAsync().ConfigureAwait(false)) != null)
|
|
{
|
|
if (!line.StartsWith("#") && !string.IsNullOrEmpty(line) && line.Length >= 3)
|
|
{
|
|
if (line.Contains("#"))
|
|
{
|
|
var lineSplit = line.Split("#");
|
|
line = lineSplit[0];
|
|
}
|
|
|
|
var sz_tokens = line.Split(":");
|
|
|
|
var sz_temp = sz_tokens[0].Trim().ToUpper();
|
|
switch (sz_temp)
|
|
{
|
|
case "$DEFINITIONS":
|
|
b_rules_definition = false;
|
|
break;
|
|
|
|
case "$NAME":
|
|
sz_state_machine_name = sz_tokens[1].Trim();
|
|
break;
|
|
|
|
case "$IDX":
|
|
n_state_machine_index = sz_tokens[1].Trim();
|
|
break;
|
|
|
|
case "$N_STATES":
|
|
n_states = int.Parse(sz_tokens[1].Trim());
|
|
break;
|
|
|
|
case "$N_BITS":
|
|
n_bits = int.Parse(sz_tokens[1].Trim());
|
|
break;
|
|
|
|
case "$BIT":
|
|
Bits.Add(sz_tokens[2].Trim().ToUpper());
|
|
break;
|
|
|
|
case "$STATE":
|
|
|
|
//States.Add(sz_tokens[2].Trim().ToUpper());
|
|
if (!StatesAll.ContainsKey(sz_tokens[2].Trim().ToUpper()))
|
|
{
|
|
StatesAll.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
break;
|
|
|
|
case "$EVENT":
|
|
if (!Events_to_send.ContainsValue(int.Parse(sz_tokens[1].Trim().ToUpper())))
|
|
{
|
|
Events_to_send.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
var newEvent = new AnagEventiModelTemp()
|
|
{
|
|
IdxTipo = int.Parse(sz_tokens[1].Trim().ToUpper()),
|
|
Nome = sz_tokens[2].Trim().ToUpper()
|
|
};
|
|
|
|
break;
|
|
|
|
case "$RULES":
|
|
b_rules_definition = true;
|
|
break;
|
|
|
|
case "$DO":
|
|
b_rules_definition = false;
|
|
var isOk = checkDirExist(procRootDir);
|
|
if (isOk)
|
|
{
|
|
var fileName = $"{currFile.origFileName.Split(".")[0]}.csv";
|
|
currFile.DLoadFileName = $"{Path.Combine(procRootDir, bitCsvPath, fileName)}";
|
|
currFile = await evalIn2Ev_transitions(currFile);
|
|
if (saveToDb)
|
|
{
|
|
//await AnagEventinInsert(events2Add);
|
|
|
|
await Task.Delay(1);
|
|
//await TranInInsert(TranInList2add, int.Parse(n_state_machine_index));
|
|
}
|
|
}
|
|
isProcActive = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
if (b_rules_definition)
|
|
{
|
|
var temp_rule = new RuleClass()
|
|
{
|
|
//id_state = StatesAll[sz_temp.Trim().ToUpper()],
|
|
state = sz_temp.Trim().ToUpper(),
|
|
expression = sz_tokens[1].Trim().ToUpper(),
|
|
next_state = sz_tokens[2].Trim().ToUpper(),
|
|
//id_next_state = StatesAll[sz_temp.Trim().ToUpper()],
|
|
event_to_send = sz_tokens[3].Trim().ToUpper(),
|
|
id_event_to_send = Events_to_send[sz_tokens[3].Trim().ToUpper()]
|
|
};
|
|
|
|
Rules.Add(temp_rule);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
evSt2Change = await modFile(currFile, false, doProcState);
|
|
|
|
if (evSt2Change.Count() == 0)
|
|
{
|
|
foreach (var ev in Events_to_send)
|
|
{
|
|
var rule2Ev = Rules.FirstOrDefault(x => x.event_to_send == ev.Key);
|
|
if (rule2Ev != null)
|
|
{
|
|
if (!evOk.ContainsKey(ev.Key) && !evOk.ContainsValue(ev.Value))
|
|
{
|
|
evOk.Add(ev.Key, ev.Value);
|
|
}
|
|
}
|
|
}
|
|
foreach (var item in evOk)
|
|
{
|
|
var newEvent = new AnagEventiModelTemp()
|
|
{
|
|
IdxTipo = item.Value,
|
|
Nome = item.Key.Trim().ToUpper()
|
|
};
|
|
var listElement = events2Add.FirstOrDefault(x => x.IdxTipo == newEvent.IdxTipo);
|
|
|
|
|
|
if (listElement != null && listElement.Nome != newEvent.Nome)
|
|
{
|
|
errMgs = $"L'evento '{newEvent.IdxTipo}: {newEvent.Nome}' non può essere importato perchè diverso da '{listElement.IdxTipo}: {listElement.Nome}' nel file {currFile.origFileName}.{Environment.NewLine}\n\n";
|
|
Log.Error(errMgs);
|
|
currFile.errorMsgs.Add(errMgs);
|
|
currFile.isOk = false;
|
|
|
|
currFile.calcRunning = false;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
}
|
|
else if (listElement == null)
|
|
{
|
|
events2Add.Add(newEvent);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in evSt2Change)
|
|
{
|
|
errMgs = $"{item.Value} {item.Key}: necessita di essere sistemato sul file originale perchè la descrizione non corrisponde al DB";
|
|
Log.Error(errMgs);
|
|
currFile.errorMsgs.Add(errMgs);
|
|
}
|
|
currFile.isOk = false;
|
|
|
|
currFile.calcRunning = false;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
errMgs = $"Eccezione durante la lettura del file {currFile.origFileName} alla riga {line}: {exc}{Environment.NewLine}";
|
|
currFile.errorMsgs.Add(errMgs);
|
|
currFile.isOk = false;
|
|
currFile.calcRunning = false;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
Log.Error(errMgs);
|
|
}
|
|
return currFile;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Modifica il file in oggetto
|
|
/// </summary>
|
|
/// <param name="file"></param>
|
|
/// <param name="doProc"></param>
|
|
/// <param name="doProcState">Necessaria modifica stati (x state machine stati)</param>
|
|
/// <returns></returns>
|
|
public async Task<Dictionary<string, string>> modFile(FilesClass file, bool doProc, bool doProcState)
|
|
{
|
|
Dictionary<string, string> evSt2Change = new Dictionary<string, string>();
|
|
|
|
Dictionary<int, string> eventsFromDb = await AnagEventiGetAll();
|
|
Dictionary<int, string> statesFromDb = await AnagStatiGetAll();
|
|
string filePath = file.tempFileName;
|
|
var lines = File.ReadLines(filePath);
|
|
var fileTxt = File.ReadAllText(filePath);
|
|
string errMsg = "";
|
|
int n = 0;
|
|
Log.Debug($"{n++:00}");
|
|
foreach (var line in lines)
|
|
{
|
|
if (line != "" && line.Contains(":"))
|
|
{
|
|
if (!line.StartsWith("$EVENT") && !line.StartsWith("#") && line.StartsWith("$STATE"))
|
|
{
|
|
if (doProcState)
|
|
{
|
|
var lineSplit = line.Split(":");
|
|
if (lineSplit.Count() >= 3)
|
|
{
|
|
if (!statesFromDb.ContainsKey(int.Parse(lineSplit[1].Trim())))
|
|
{
|
|
errMsg = $"Lo stato {lineSplit[1].Trim()}: {lineSplit[2].Trim()} non è presente in AnagraficaStati sul DB";
|
|
file.errorMsgs.Add(errMsg);
|
|
file.isOk = false;
|
|
}
|
|
else if (statesFromDb[int.Parse(lineSplit[1].Trim())] != lineSplit[2].Trim())
|
|
{
|
|
fileTxt = fileTxt.Replace(lineSplit[2].Trim(), statesFromDb[int.Parse(lineSplit[1].Trim())]);
|
|
evSt2Change.Add(lineSplit[2].Trim(), lineSplit[0].Trim());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (line.StartsWith("$EVENT") && !line.StartsWith("#") && !line.StartsWith("$STATE"))
|
|
{
|
|
var lineSplit = line.Split(":");
|
|
if (lineSplit.Count() >= 3)
|
|
{
|
|
if (!eventsFromDb.ContainsKey(int.Parse(lineSplit[1].Trim())))
|
|
{
|
|
errMsg = $"L'evento {lineSplit[1].Trim()}: {lineSplit[2].Trim()} non è presente in AnagraficaEventi sul DB";
|
|
file.errorMsgs.Add(errMsg);
|
|
file.isOk = false;
|
|
}
|
|
else if (eventsFromDb[int.Parse(lineSplit[1].Trim())] != lineSplit[2].Trim())
|
|
{
|
|
#if false
|
|
// definisco i token con spazi prima e dopo x evitare sostituzione token "esempio" ed "esempio_01"...
|
|
string sOrig = $" {lineSplit[2].Trim()} ";
|
|
string sDest = $" {eventsFromDb[int.Parse(lineSplit[1].Trim())]} ";
|
|
fileTxt = fileTxt.Replace(sOrig, sDest);
|
|
#endif
|
|
fileTxt = fileTxt.Replace(lineSplit[2].Trim(), eventsFromDb[int.Parse(lineSplit[1].Trim())]);
|
|
evSt2Change.Add(lineSplit[2].Trim(), lineSplit[0].Trim());
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Log.Debug($"{n++:00}");
|
|
if (doProc)
|
|
{
|
|
if (file.errorMsgs.Count() == 0)
|
|
{
|
|
var fileName = $"{file.origFileName.Split(".")[0]}.rul";
|
|
file.DLoadFileName = $"{Path.Combine(procRootDir, bitCsvPath, fileName)}";
|
|
file.isOk = true;
|
|
await FileUpdate(file.origFileName, file);
|
|
using (StreamWriter sw = new StreamWriter(file.DLoadFileName))
|
|
{
|
|
sw.Write(fileTxt);
|
|
}
|
|
}
|
|
Log.Debug($"T{n++:00}");
|
|
}
|
|
else
|
|
{
|
|
await FileUpdate(file.origFileName, file);
|
|
Log.Debug($"F{n++:00}");
|
|
}
|
|
return evSt2Change;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Valuta un file di ruoles x ingressi 2 Stati e restituisce esito
|
|
/// </summary>
|
|
/// <param name="currFile">Path file *.rul da processare</param>
|
|
/// <param name="saveToDb">Indica se salvare sul DB</param>
|
|
/// <param name="calcItself"></param>
|
|
/// <param name="calcEmptyState"></param>
|
|
/// <param name="orderType"></param>
|
|
/// <param name="doProcState">Indica se processare parte state (x state machine stati)</param>
|
|
/// <returns></returns>
|
|
public async Task<FilesClass> EvalIn2StateRuleFile(FilesClass currFile, bool saveToDb, bool calcItself, bool calcEmptyState, Core.Enum.ORDERTYPE orderType, bool doProcState)
|
|
{
|
|
await Task.Delay(1);
|
|
Dictionary<string, string> evSt2Change = new Dictionary<string, string>();
|
|
sz_state_machine_name = "";
|
|
n_state_machine_index = "";
|
|
n_states = 0;
|
|
n_bits = 0;
|
|
States.Clear();
|
|
Bits.Clear();
|
|
Events_to_send.Clear();
|
|
Rules.Clear();
|
|
StatesAll.Clear();
|
|
actStates2Chk.Clear();
|
|
nextStates2Chk.Clear();
|
|
// recupero nome file x partire
|
|
string filePath = currFile.tempFileName;
|
|
string line = "";
|
|
string errMsg = "";
|
|
|
|
try
|
|
{
|
|
var isProcActive = true;
|
|
if (isProcActive)
|
|
{
|
|
// stream lettura file
|
|
using (StreamReader sr = new StreamReader(filePath))
|
|
{
|
|
while ((line = await sr.ReadLineAsync().ConfigureAwait(false)) != null)
|
|
{
|
|
line = line.Replace("\t", " ").Trim();
|
|
|
|
if (!line.StartsWith("#") && !string.IsNullOrEmpty(line) && line.Length >= 3)
|
|
{
|
|
if (line.Contains("#"))
|
|
{
|
|
var lineSplit = line.Split("#");
|
|
line = lineSplit[0];
|
|
}
|
|
//else if (line.StartsWith("\t"))
|
|
//{
|
|
//}
|
|
|
|
var sz_tokens = line.Split(":");
|
|
|
|
var sz_temp = sz_tokens[0].Trim();
|
|
switch (sz_temp)
|
|
{
|
|
case "$DEFINITIONS":
|
|
b_rules_definition = false;
|
|
break;
|
|
|
|
case "$NAME":
|
|
sz_state_machine_name = sz_tokens[1].Trim();
|
|
break;
|
|
|
|
case "$IDX":
|
|
n_state_machine_index = sz_tokens[1].Trim();
|
|
break;
|
|
|
|
case "$STATE":
|
|
if (!StatesAll.ContainsKey(sz_tokens[2].Trim().ToUpper()))
|
|
{
|
|
StatesAll.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
break;
|
|
|
|
case "$EVENT":
|
|
if (!Events_to_send.ContainsValue(int.Parse(sz_tokens[1].Trim().ToUpper())))
|
|
{
|
|
Events_to_send.Add(sz_tokens[2].Trim().ToUpper(), int.Parse(sz_tokens[1].Trim().ToUpper()));
|
|
}
|
|
var newEvent = new AnagEventiModelTemp()
|
|
{
|
|
IdxTipo = int.Parse(sz_tokens[1].Trim().ToUpper()),
|
|
Nome = sz_tokens[2].Trim().ToUpper()
|
|
};
|
|
break;
|
|
|
|
case "$RULES":
|
|
b_rules_definition = true;
|
|
break;
|
|
|
|
case "$DO":
|
|
b_rules_definition = false;
|
|
var isOk = checkDirExist(Path.Combine(procRootDir, statiCsvPath));
|
|
if (isOk)
|
|
{
|
|
var fileName = $"{currFile.origFileName.Split(".")[0]}.csv";
|
|
currFile.DLoadFileName = $"{Path.Combine(procRootDir, statiCsvPath, fileName)}";
|
|
currFile = await evalIn2State_transitions(currFile, calcItself, calcEmptyState, orderType);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (b_rules_definition)
|
|
{
|
|
var state = sz_temp.Trim().ToUpper();
|
|
var event_to_send = sz_tokens[1].Trim().ToUpper();
|
|
var next_state = sz_tokens[2].Trim().ToUpper();
|
|
|
|
var temp_rule = new RuleClass()
|
|
{
|
|
state = state,
|
|
event_to_send = event_to_send,
|
|
next_state = next_state,
|
|
id_next_state = StatesAll[next_state],
|
|
id_event_to_send = Events_to_send[event_to_send]
|
|
};
|
|
Rules.Add(temp_rule);
|
|
States2Rules.Add(next_state);
|
|
|
|
if (state != "ALL_STATES" && state != "ND")
|
|
{
|
|
actStates2Chk.Add(state);
|
|
}
|
|
else if (state == "ALL_STATES" && state != "ND")
|
|
{
|
|
actStates2Chk.AddRange(StatesAll.Keys.Where(x => x != "ND"));
|
|
}
|
|
|
|
if (next_state != "ALL_STATES" && next_state != "ND")
|
|
{
|
|
foreach (var st in StatesAll)
|
|
{
|
|
|
|
if (st.Key != "ND")
|
|
{
|
|
nextStates2Chk.Add(st.Key);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione durante la lettura del file {currFile.origFileName} alla riga {line}: {exc}{Environment.NewLine}");
|
|
}
|
|
|
|
evSt2Change = await modFile(currFile, false, doProcState);
|
|
|
|
if (evSt2Change.Count() == 0)
|
|
{
|
|
foreach (var ev in Events_to_send)
|
|
{
|
|
var rule2Ev = Rules.FirstOrDefault(x => x.event_to_send == ev.Key);
|
|
if (rule2Ev != null)
|
|
{
|
|
if (!evOk.ContainsKey(ev.Key) && !evOk.ContainsValue(ev.Value))
|
|
{
|
|
evOk.Add(ev.Key, ev.Value);
|
|
}
|
|
}
|
|
}
|
|
foreach (var item in evOk)
|
|
{
|
|
var newEvent = new AnagEventiModelTemp()
|
|
{
|
|
IdxTipo = item.Value,
|
|
Nome = item.Key.Trim().ToUpper()
|
|
};
|
|
var listElement = events2Add.FirstOrDefault(x => x.IdxTipo == newEvent.IdxTipo);
|
|
|
|
if (listElement != null && listElement.Nome != newEvent.Nome)
|
|
{
|
|
errMsg = $"L'evento '{newEvent.IdxTipo}: {newEvent.Nome}' non può essere importato perchè diverso da '{listElement.IdxTipo}: {listElement.Nome}' nel file {currFile.origFileName}.{Environment.NewLine}";
|
|
Log.Error(errMsg);
|
|
currFile.errorMsgs.Add(errMsg);
|
|
currFile.isOk = false;
|
|
|
|
currFile.calcRunning = false;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
//return null;
|
|
}
|
|
else if (listElement == null)
|
|
{
|
|
events2Add.Add(newEvent);
|
|
}
|
|
}
|
|
foreach (var state2Chk in actStates2Chk.Distinct())
|
|
{
|
|
var nxtSt = nextStates2Chk.FirstOrDefault(x => x == state2Chk);
|
|
if (nxtSt == null)
|
|
{
|
|
errMsg = $"Nel file {currFile.origFileName} lo stato: {state2Chk} non risulta essere presente come stato di uscita.{Environment.NewLine}";
|
|
Log.Error(errMsg);
|
|
currFile.errorMsgs.Add(errMsg);
|
|
currFile.isOk = false;
|
|
|
|
currFile.calcRunning = false;
|
|
}
|
|
}
|
|
foreach (var nxtState in nextStates2Chk.Distinct())
|
|
{
|
|
var St = actStates2Chk.FirstOrDefault(x => x == nxtState);
|
|
if (St == null)
|
|
{
|
|
errMsg = $"Nel file {currFile.origFileName} lo stato: {nxtState} non risulta essere presente come stato di entrata.{Environment.NewLine}";
|
|
Log.Error(errMsg);
|
|
currFile.errorMsgs.Add(errMsg);
|
|
currFile.isOk = false;
|
|
|
|
currFile.calcRunning = false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in evSt2Change)
|
|
{
|
|
errMsg = $"{item.Value} {item.Key}: necessita di essere sistemato sul file originale perchè la descrizione non corrisponde al DB";
|
|
Log.Error(errMsg);
|
|
currFile.errorMsgs.Add(errMsg);
|
|
}
|
|
currFile.isOk = false;
|
|
|
|
currFile.calcRunning = false;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
}
|
|
|
|
return currFile;
|
|
}
|
|
/// <summary>
|
|
/// Valutazione schema macchina a stati x Ingressi --> Eventi
|
|
/// </summary>
|
|
/// <param name="currFile"></param>
|
|
/// <returns></returns>
|
|
protected async Task<FilesClass> evalIn2Ev_transitions(FilesClass currFile)
|
|
|
|
{
|
|
await Task.Delay(1);
|
|
StringBuilder sb = new StringBuilder();
|
|
TranInList2add.Clear();
|
|
if (File.Exists(currFile.DLoadFileName))
|
|
{
|
|
File.Delete(currFile.DLoadFileName);
|
|
}
|
|
sb.AppendLine("IdxFamigliaIngresso;IdxMicroStato;ValoreIngresso;IdxTipoEvento;next_IdxMicroStato");
|
|
string sz_actual_state = "";
|
|
string sz_actual_bit = "";
|
|
string sz_line = "";
|
|
//int i = 0;
|
|
int n_input = 0;
|
|
//int n = 0;
|
|
int n_mask = 0;
|
|
int n_bit = 0;
|
|
|
|
bool[] b_bit = new bool[20];
|
|
bool b_invert = false;
|
|
|
|
|
|
|
|
//ciclo negli stati
|
|
try
|
|
{
|
|
for (var i = 0; i <= n_states - 1; i++)
|
|
{
|
|
// verificare qui: non dovrebbe essere vente_to_send ma stati!!!!
|
|
//sz_actual_state = Events_to_send.FirstOrDefault(x => x.Value == i).Key;
|
|
sz_actual_state = StatesAll.FirstOrDefault(x => x.Value == i).Key;
|
|
|
|
//ciclo negli ingressi
|
|
for (n_input = 0; n_input <= (Math.Pow(2, n_bits) - 1); n_input++)
|
|
{
|
|
n_mask = 1;
|
|
for (var n = 0; n <= n_bits - 1; n++)
|
|
{
|
|
b_bit[n] = Convert.ToBoolean(n_input & n_mask);
|
|
n_mask = n_mask << 1;
|
|
}
|
|
|
|
var exitFor = false;
|
|
|
|
foreach (var act_rule in Rules)
|
|
{
|
|
n_bit = -1;
|
|
if ((act_rule.state == "ALL_STATES") || (act_rule.state == sz_actual_state))
|
|
{
|
|
//DA RESETTARE A FALSE (errore da principianti...)
|
|
b_invert = false;
|
|
|
|
sz_actual_bit = act_rule.expression;
|
|
|
|
//controllo se la riga contiene l'istruzione per negare il bit
|
|
if (sz_actual_bit.Trim().StartsWith("NOT"))
|
|
{
|
|
//inverto il bit
|
|
b_invert = true;
|
|
sz_actual_bit = sz_actual_bit.Replace("NOT ", "").Trim();
|
|
}
|
|
//cerca il nome del bit e ne trova l' indice da 0
|
|
n_bit = Bits.FindIndex(x => x == sz_actual_bit);
|
|
|
|
if (n_bit == -1)
|
|
{
|
|
exitFor = true;
|
|
}
|
|
|
|
int nextState = StatesAll[act_rule.next_state];
|
|
|
|
if (!exitFor)
|
|
{
|
|
if (((!b_invert) && b_bit[n_bit]) || (b_invert && (!b_bit[n_bit])))
|
|
{
|
|
sz_line = "";
|
|
//eseguo solo se diverso dallo stato corrente
|
|
if (StatesAll[act_rule.next_state] != i)
|
|
{
|
|
if (nextState < 0)
|
|
{
|
|
nextState = 0;
|
|
}
|
|
|
|
sz_line = $"{n_state_machine_index}" +
|
|
$";" +
|
|
$"{i}" +
|
|
$";" +
|
|
$"{n_input}" +
|
|
$";" +
|
|
$"{Events_to_send[act_rule.event_to_send]}" +
|
|
$";" +
|
|
$"{nextState}";
|
|
|
|
sb.AppendLine(sz_line);
|
|
|
|
#if false
|
|
var newTranIn = new TransizioneIngressiModelTemp()
|
|
{
|
|
IdxFamigliaIngresso = int.Parse(n_state_machine_index),
|
|
IdxMicroStato = i,
|
|
ValoreIngresso = n_input,
|
|
IdxTipoEvento = Events_to_send[act_rule.event_to_send],
|
|
next_IdxMicroStato = States.IndexOf(act_rule.next_state)
|
|
};
|
|
|
|
TranInList2add.Add(newTranIn);
|
|
#endif
|
|
}
|
|
exitFor = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
using (StreamWriter sw = new StreamWriter(currFile.DLoadFileName))
|
|
{
|
|
sw.Write(sb.ToString());
|
|
}
|
|
await Task.Delay(1);
|
|
currFile.isOk = true;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in evalIn2Ev_transitions{Environment.NewLine}{exc}");
|
|
}
|
|
return currFile;
|
|
}
|
|
/// <summary>
|
|
/// Valutazione schema macchina a stati x Ingressi --> stati
|
|
/// </summary>
|
|
/// <param name="currFile"></param>
|
|
/// <returns></returns>
|
|
protected async Task<FilesClass> evalIn2State_transitions(FilesClass currFile, bool calcItself, bool calcEmptyState, Core.Enum.ORDERTYPE orderType)
|
|
{
|
|
csvLines.Clear();
|
|
TranInList2add.Clear();
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
if (File.Exists(currFile.DLoadFileName))
|
|
{
|
|
File.Delete(currFile.DLoadFileName);
|
|
}
|
|
|
|
sb.AppendLine("IdxFamiglia;IdxStato;IdxTipo;next_IdxStato");
|
|
int sz_actual_state = 0;
|
|
string sz_line = "";
|
|
|
|
foreach (var item in States2Rules)
|
|
{
|
|
if (!StatesAll2.ContainsKey(item))
|
|
{
|
|
StatesAll2.Add(item, StatesAll[item]);
|
|
}
|
|
}
|
|
|
|
#if false
|
|
if (orderType == Core.Enum.ORDERTYPE.stateEvent)
|
|
{
|
|
Events_to_send = Events_to_send.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
|
|
Rules = Rules.OrderBy(x => x.id_event_to_send).ThenBy(x => x.id_next_state).ToList();
|
|
}
|
|
else if (orderType == Core.Enum.ORDERTYPE.eventState)
|
|
{
|
|
Events_to_send = Events_to_send.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
|
|
}
|
|
else if (orderType == Core.Enum.ORDERTYPE.eventNextState)
|
|
{
|
|
StatesAll2 = StatesAll2.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
|
|
Rules = Rules.OrderBy(x => x.id_event_to_send).ThenBy(x => x.id_next_state).ToList();
|
|
}
|
|
#endif
|
|
|
|
Events_to_send = Events_to_send.OrderBy(x => x.Value).ToDictionary(x => x.Key, x => x.Value);
|
|
Rules = Rules.OrderBy(x => x.id_event_to_send).ToList();
|
|
|
|
|
|
|
|
//ciclo negli stati
|
|
try
|
|
{
|
|
foreach (var item in StatesAll2)
|
|
{
|
|
sz_actual_state = item.Value;
|
|
|
|
foreach (var act_rule in Rules)
|
|
{
|
|
var exitFor = false;
|
|
if ((act_rule.state == "ALL_STATES") || (act_rule.state == StatesAll.Where(x => x.Value == sz_actual_state).FirstOrDefault().Key))
|
|
{
|
|
//DA RESETTARE A FALSE (errore da principianti...)
|
|
|
|
int nextState = StatesAll2[act_rule.next_state];
|
|
|
|
if (!exitFor)
|
|
{
|
|
sz_line = "";
|
|
//eseguo solo se diverso dallo stato corrente
|
|
// || calcItself
|
|
if (nextState != item.Value || calcItself)
|
|
{
|
|
if (nextState < 0)
|
|
{
|
|
nextState = 0;
|
|
}
|
|
|
|
if ((nextState == 0 && calcEmptyState) || (nextState > 0))
|
|
{
|
|
//sb.AppendLine(sz_line);
|
|
var newLine = new CsvClass()
|
|
{
|
|
IdxFamiglia = n_state_machine_index,
|
|
state = item.Value,
|
|
event_to_send = Events_to_send[act_rule.event_to_send],
|
|
next_state = nextState
|
|
};
|
|
csvLines.Add(newLine);
|
|
#if false
|
|
var newTranIn = new TransizioneIngressiModelTemp()
|
|
{
|
|
IdxFamigliaIngresso = int.Parse(n_state_machine_index),
|
|
IdxMicroStato = item.Value,
|
|
IdxTipoEvento = Events_to_send[act_rule.event_to_send],
|
|
next_IdxMicroStato = nextState
|
|
};
|
|
|
|
TranInList2add.Add(newTranIn);
|
|
#endif
|
|
}
|
|
}
|
|
exitFor = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//await SMGDService.AnagEventinInsert(events2Add);
|
|
if (orderType == Core.Enum.ORDERTYPE.stateEvent)
|
|
{
|
|
csvLines = csvLines.OrderBy(x => x.state).ThenBy(x => x.event_to_send).ToList();
|
|
}
|
|
else if (orderType == Core.Enum.ORDERTYPE.eventState)
|
|
{
|
|
csvLines = csvLines.OrderBy(x => x.event_to_send).ThenBy(x => x.state).ToList();
|
|
}
|
|
else if (orderType == Core.Enum.ORDERTYPE.eventNextState)
|
|
{
|
|
csvLines = csvLines.OrderBy(x => x.event_to_send).ThenBy(x => x.next_state).ToList();
|
|
}
|
|
|
|
|
|
foreach (var item in csvLines)
|
|
{
|
|
|
|
sz_line = $"{item.IdxFamiglia}" +
|
|
$";" +
|
|
$"{item.state}" +
|
|
$";" +
|
|
$"{item.event_to_send}" +
|
|
$";" +
|
|
$"{item.next_state}";
|
|
|
|
sb.AppendLine(sz_line);
|
|
}
|
|
|
|
using (StreamWriter sw = new StreamWriter(currFile.DLoadFileName))
|
|
{
|
|
sw.Write(sb.ToString());
|
|
}
|
|
await Task.Delay(1);
|
|
currFile.isOk = true;
|
|
|
|
await FileUpdate(currFile.origFileName, currFile);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Eccezione in evalIn2State_transitions{Environment.NewLine}{exc}");
|
|
}
|
|
return currFile;
|
|
}
|
|
private bool checkDirExist(string dir)
|
|
{
|
|
bool answ = Directory.Exists(dir);
|
|
if (!answ)
|
|
{
|
|
var dirCreate = Directory.CreateDirectory(dir);
|
|
answ = (dirCreate != null);
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Effettua upsert in HasList redis
|
|
/// </summary>
|
|
/// <param name="currKey">Chiave redis della Hashlist</param>
|
|
/// <param name="chiave">Chiave nella HashList</param>
|
|
/// <param name="valore">Valore da salvare</param>
|
|
/// <returns>Num record nella HashList</returns>
|
|
protected async Task<long> RedHashUpsert(RedisKey currKey, string chiave, string valore)
|
|
{
|
|
long numReq = 0;
|
|
Stopwatch stopWatch = new Stopwatch();
|
|
stopWatch.Start();
|
|
await redisDb.HashSetAsync(currKey, chiave, valore);
|
|
numReq = await redisDb.HashLengthAsync(currKey);
|
|
stopWatch.Stop();
|
|
TimeSpan ts = stopWatch.Elapsed;
|
|
Log.Trace($"RedHashUpsert | {currKey} | in: {ts.TotalMilliseconds} ms");
|
|
return numReq;
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Private Fields
|
|
|
|
private static IConfiguration _configuration = null!;
|
|
|
|
private static JsonSerializerSettings? JSSettings;
|
|
|
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
|
|
|
/// <summary>
|
|
/// Durata cache lunga IN SECONDI
|
|
/// </summary>
|
|
private int cacheTtlLong = 60 * 5;
|
|
|
|
/// <summary>
|
|
/// Durata cache breve IN SECONDI
|
|
/// </summary>
|
|
private int cacheTtlShort = 60 * 1;
|
|
|
|
/// <summary>
|
|
/// Oggetto per connessione a REDIS
|
|
/// </summary>
|
|
private IConnectionMultiplexer redisConn;
|
|
|
|
/// <summary>
|
|
/// Oggetto DB redis da impiegare x chiamate R/W
|
|
/// </summary>
|
|
private IDatabase redisDb = null!;
|
|
|
|
private Random rnd = new Random();
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Properties
|
|
|
|
/// <summary>
|
|
/// Durata cache breve (1 min circa + perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan FastCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlShort * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan LongCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlLong * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Durata cache molto breve (10 sec circa + perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan UltraFastCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlShort / 6 * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Durata cache lunga (+ perturbazione percentuale +/-10%)
|
|
/// </summary>
|
|
private TimeSpan UltraLongCache
|
|
{
|
|
get => TimeSpan.FromSeconds(cacheTtlLong * 10 * rnd.Next(900, 1100) / 1000);
|
|
}
|
|
|
|
#endregion Private Properties
|
|
}
|
|
} |