Files
mapo-mono/MP.MONO.SIM/Program.cs

445 lines
13 KiB
C#

// See https://aka.ms/new-console-template for more information
using MachineSim;
using Microsoft.Extensions.Configuration;
using MP.MONO.Core;
using MP.MONO.Core.CONF;
using MP.MONO.Core.DTO;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
// init parte config, vedere https://blog.hildenco.com/2020/05/configuration-in-net-core-console.html
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var builder = new ConfigurationBuilder()
.AddJsonFile($"appsettings.json", true, true)
.AddJsonFile($"appsettings.{env}.json", true, true)
.AddEnvironmentVariables();
var config = builder.Build();
// imposto variabili di base
string lineSep = "---------------------------------------------";
string redisConf = config.GetConnectionString("Redis");
string confPath = Path.Combine(Directory.GetCurrentDirectory(), "conf");
Logger Log = LogManager.GetCurrentClassLogger();
Random rand = new Random();
List<MachineStatus>? statusList = new List<MachineStatus>();
List<MachineMode>? modeList = new List<MachineMode>();
// fix numero minimo dei thread pool x evitare collasso chiamate redis
ThreadPool.SetMinThreads(10, 10);
Dictionary<string, int> LogSimulator = new Dictionary<string, int>();
Dictionary<string, DateTime> LastSend = new Dictionary<string, DateTime>();
DateTime lastLog = DateTime.Now.AddMinutes(-1);
bool verboseLog = false;
bool logWriting = false;
logInfo(lineSep, true, true);
logInfo($"Starting Machine SIM", true, true);
logInfo($"Redis server param: {redisConf.Substring(0, 20)}...", false, true);
logInfo(lineSep, true, true);
logInfo("", true, true);
logInfo("Running - press CTRL-C to stop SIM", false, true);
logInfo("", false, true);
// Setup REDIS
ConnectionMultiplexer.SetFeatureFlag("preventthreadtheft", true);
ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(redisConf);
ISubscriber sub = redis.GetSubscriber();
IDatabase? redisDb = redis.GetDatabase();
// preparo oggetti da configurare
List<BaseAlarmConf>? alarmsConf = new List<BaseAlarmConf>();
List<MachineMode>? machineModeConf = new List<MachineMode>();
List<MachineStatus>? machineStatusConf = new List<MachineStatus>();
// salvo configurazioni in redis
setupConf();
var currSimGen = new Simulator(confPath, modeList.Count, statusList.Count);
// preparo la lista dei contatori invio...
LogSimulator.Add(Constants.ACT_LOG_M_QUEUE, 0);
LogSimulator.Add(Constants.ALARM_M_QUEUE, 0);
LogSimulator.Add(Constants.EVENT_LOG_M_QUEUE, 0);
LogSimulator.Add(Constants.PARAMS_M_QUEUE, 0);
LogSimulator.Add(Constants.PROD_M_QUEUE, 0);
LogSimulator.Add(Constants.MACH_STATS_M_QUEUE, 0);
LogSimulator.Add(Constants.MAINT_STATS_M_QUEUE, 0);
LogSimulator.Add(Constants.TOOLS_M_QUEUE, 0);
// avvio tutti i thread...
Thread threadStatus = new Thread(simStatus);
Thread threadAlarms = new Thread(simAlarms);
Thread threadParams = new Thread(simParameters);
Thread threadProd = new Thread(simProd);
Thread threadMachStat = new Thread(simMachStat);
Thread threadMaint = new Thread(simMaint);
Thread threadTools = new Thread(simTools);
Thread threadEvHistory = new Thread(simEvents);
Thread threadActLog = new Thread(simActivityLog);
threadStatus.Start();
threadAlarms.Start();
threadParams.Start();
threadProd.Start();
threadMachStat.Start();
threadMaint.Start();
threadTools.Start();
threadEvHistory.Start();
threadActLog.Start();
/// <summary>
/// verifica esistenza file oppure lo crea...
/// </summary>
void checkFilePresent(string filePath)
{
// verific presenza file log...
if (!File.Exists(filePath))
{
File.WriteAllText(filePath, $"{filePath} created!");
}
}
/// <summary>
/// Setup e salvataggio redis delle conf (es modi/stati)
/// </summary>
void setupConf()
{
#if false
// leggo e salvo conf stati
string fullPath = Path.Combine(confPath, "StatusList.json");
if (File.Exists(fullPath))
{
var rawData = File.ReadAllText(fullPath);
if (!string.IsNullOrEmpty(rawData))
{
machineStatusConf = JsonConvert.DeserializeObject<List<MachineStatus>>(rawData);
// salvo in redis!
redisDb.StringSetAsync(Constants.STATUS_CONF_KEY, JsonConvert.SerializeObject(machineStatusConf));
}
}
// leggo e salvo conf modi
fullPath = Path.Combine(confPath, "ModeList.json");
if (File.Exists(fullPath))
{
var rawData = File.ReadAllText(fullPath);
if (!string.IsNullOrEmpty(rawData))
{
machineModeConf = JsonConvert.DeserializeObject<List<MachineMode>>(rawData);
// salvo in redis!
redisDb.StringSetAsync(Constants.MODE_CONF_KEY, JsonConvert.SerializeObject(machineModeConf));
}
}
// leggo e salvo conf allarmi
fullPath = Path.Combine(confPath, "AlarmList.json");
if (File.Exists(fullPath))
{
var rawData = File.ReadAllText(fullPath);
if (!string.IsNullOrEmpty(rawData))
{
alarmsConf = JsonConvert.DeserializeObject<List<BaseAlarmConf>>(rawData);
if (alarmsConf != null)
{
// sistemo allarmi
foreach (var item in alarmsConf)
{
item.setupData();
// loggo
logInfo($"Decodifica aree alarmMap: {item.description} | {item.memAddr} x {item.size} byte | {item.messages.Count} messaggi allarme", true, true);
}
}
// salvo in redis!
redisDb.StringSetAsync(Constants.ALARMS_CONF_KEY, JsonConvert.SerializeObject(alarmsConf));
}
}
// leggo e salvo conf parametri
fullPath = Path.Combine(confPath, "ParamList.json");
if (File.Exists(fullPath))
{
var rawData = File.ReadAllText(fullPath);
if (!string.IsNullOrEmpty(rawData))
{
var localObj = JsonConvert.DeserializeObject<List<DisplayDataDTO>>(rawData);
// salvo in redis!
redisDb.StringSetAsync(Constants.PARAMS_CONF_KEY, JsonConvert.SerializeObject(localObj));
}
}
#endif
ConfigManager configManager = new ConfigManager(redisConf, confPath);
alarmsConf = configManager.getAlarmsConf();
machineModeConf= configManager.getMachineModeConf();
machineStatusConf = configManager.getMachineStatusConf();
_ = configManager.getParamsConf();
}
/// <summary>
/// Effettua log INFO su file e se richiesto su console
/// </summary>
void logInfo(string msg, bool log2file = true, bool log2console = false)
{
if (log2console)
{
Console.WriteLine(msg);
}
if (log2file)
{
Log.Info(msg);
}
}
/// <summary>
/// Effettua log ERROR su file e se richiesto su console
/// </summary>
void logError(string msg, bool log2file = true, bool log2console = false)
{
if (log2console)
{
Console.WriteLine(msg);
}
if (log2file)
{
Log.Error(msg);
}
}
void saveAndSendMessage(string memKey, string notifyChannel, string message)
{
// effettuo la scrittura nell'area di memoria indicata SE passato intervallo minimo
bool doSend = true;
if (LastSend.ContainsKey(memKey))
{
if (DateTime.Now.Subtract(LastSend[memKey]).TotalSeconds < 60)
{
doSend = false;
}
}
else
{
LastSend.Add(memKey, DateTime.Now);
}
if (doSend)
{
redisDb.StringSetAsync(memKey, message);
LastSend[memKey] = DateTime.Now;
logInfo($"Redis Cache Key: {memKey}");
}
// invio notifica tramite il canale richiesto
sub.Publish(notifyChannel, message);
if (verboseLog)
{
logInfo($"[{notifyChannel}] key: {memKey} | val/message: {message}");
}
else
{
try
{
if (!logWriting)
{
if (LogSimulator.ContainsKey(notifyChannel))
{
LogSimulator[notifyChannel]++;
}
else
{
LogSimulator.Add(notifyChannel, 1);
}
logWriting = true;
// vedo se loggare...
DateTime adesso = DateTime.Now;
if (adesso.Subtract(lastLog).TotalSeconds > 15)
{
lastLog = adesso;
logInfo(lineSep);
// lavoro su copia...
var LogSimulatorCopy = new Dictionary<string, int>(LogSimulator);
foreach (var item in LogSimulatorCopy)
{
logInfo($"Redis mQueue {item.Key,-20}{item.Value,12}");
}
logInfo(lineSep);
}
logWriting = false;
}
}
catch (Exception ex)
{
logError($"ERROR{Environment.NewLine}{ex}");
}
}
}
void simAlarms()
{
int minPeriod = 3000;
int maxPeriod = 9000;
int percAllarmi = config.GetValue<int>("percAllarmi");
do
{
Dictionary<string, uint> currAlarmsVal = new Dictionary<string, uint>();
uint alarmCode = 0;
bool hasAlarm;
// ciclo x numero banchi da config...
foreach (var item in alarmsConf)
{
// limito allarmi al percAllarmi/100 dei casi
hasAlarm = rand.Next(0, 100) <= percAllarmi;
// allarme libero SE in condizione allarme
alarmCode = hasAlarm ? (uint)rand.Next(0, 65535) : 0;
currAlarmsVal.Add(item.memAddr, alarmCode);
}
string rawDataVal = JsonConvert.SerializeObject(currAlarmsVal);
saveAndSendMessage(Constants.ALARM_ACT_KEY, Constants.ALARM_ACT_QUEUE, rawDataVal);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simParameters()
{
int minPeriod = 150;
int maxPeriod = 500;
do
{
#if false
// da eliminare quando gestita da decoder
var newParams = currSimGen.getParameters();
string rawData = JsonConvert.SerializeObject(newParams);
saveAndSendMessage(Constants.PARAMS_CURR_KEY, Constants.PARAMS_M_QUEUE, rawData);
#endif
// gestione SIM dictionary
var paramDict = currSimGen.getParamsVal();
string rawData = JsonConvert.SerializeObject(paramDict);
saveAndSendMessage(Constants.PARAMS_ACT_KEY, Constants.PARAMS_ACT_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simStatus()
{
int minPeriod = 1000;
int maxPeriod = 5000;
do
{
// recupero uno stato simulato
var newStatus = currSimGen.getStatus();
string rawData = JsonConvert.SerializeObject(newStatus);
saveAndSendMessage(Constants.STATUS_CURR_KEY, Constants.STATUS_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simProd()
{
int minPeriod = 3000;
int maxPeriod = 10000;
do
{
// recupero uno stato simulato
var newStatus = currSimGen.getProd();
string rawData = JsonConvert.SerializeObject(newStatus);
saveAndSendMessage(Constants.PROD_CURR_KEY, Constants.PROD_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simMachStat()
{
int minPeriod = 5000;
int maxPeriod = 15000;
do
{
// recupero uno stato simulato
var newVal = currSimGen.getProdStats();
string rawData = JsonConvert.SerializeObject(newVal);
saveAndSendMessage(Constants.MACH_STATS_CURR_KEY, Constants.MACH_STATS_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simMaint()
{
int minPeriod = 10000;
int maxPeriod = 20000;
do
{
// recupero uno stato simulato
var newVal = currSimGen.getMaint();
string rawData = JsonConvert.SerializeObject(newVal);
saveAndSendMessage(Constants.MAINT_STATS_CURR_KEY, Constants.MAINT_STATS_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simTools()
{
int minPeriod = 3000;
int maxPeriod = 10000;
do
{
// recupero uno stato simulato
var newVal = currSimGen.getTools();
string rawData = JsonConvert.SerializeObject(newVal);
saveAndSendMessage(Constants.TOOLS_CURR_KEY, Constants.TOOLS_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simEvents()
{
int minPeriod = 200;
int maxPeriod = 800;
do
{
// recupero uno stato simulato
var newVal = currSimGen.getEvents();
string rawData = JsonConvert.SerializeObject(newVal);
saveAndSendMessage(Constants.EVENT_LOG_CURR_KEY, Constants.EVENT_LOG_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}
void simActivityLog()
{
int minPeriod = 15000;
int maxPeriod = 30000;
do
{
// recupero uno stato simulato
var newVal = currSimGen.getActLog();
string rawData = JsonConvert.SerializeObject(newVal);
saveAndSendMessage(Constants.ACT_LOG_CURR_KEY, Constants.ACT_LOG_M_QUEUE, rawData);
// attesa random
Thread.Sleep(rand.Next(minPeriod, maxPeriod));
} while (true);
}