using EgwCoreLib.Utils;
using IOB_MAN.Core.Config;
using IOB_MAN.Core.Data;
using IOB_MAN.Core.Models;
using Newtonsoft.Json;
using NLog;
using StackExchange.Redis;
using System.Collections.Concurrent;
using System.Diagnostics;
using static IOB_MAN.Core.CoreEnum;
namespace IOB_MAN.Core.Services
{
public class AppControlService : IAppControlService, IDisposable
{
#region Public Constructors
///
/// Init classe
///
/// Se True avvia i processi gestiti
public AppControlService(bool startProc)
{
LoadConfAndStart(startProc);
}
#endregion Public Constructors
#region Public Events
///
/// Evento update configurazione
///
public event Action EA_ConfigUpdated = null!;
///
/// Evento richiesta reboot completo applicazione
///
public event Action EA_RebootRequested = null!;
///
/// Evento update status controlli
///
public event Action EA_StatusUpdated = null!;
#endregion Public Events
#region Public Properties
///
/// Abilitazione autorestart
///
public bool AutoRestartEnabled { get; set; } = true;
///
/// Periodo controllo memoria in msec
///
public int CheckMemoryPeriod
{
get => currAppConf.TaskData.TimerMemSec * 1000;
}
public int CheckRestartPeriod
{
get => currAppConf.TaskData.TimerCheckMSec;
set => currAppConf.TaskData.TimerCheckMSec = value;
}
public string ConfDirIob
{
get => confDirIob;
set => confDirIob = value;
}
///
/// Configurazione IOB in sola lettura
///
public IobManConfig CurrIobConf
{
get => currIobConf;
}
public List CurrIobType
{
get => currIobType;
}
///
/// Abilitazione glocale notifiche da conf
///
public bool EnableNotify
{
get => currAppConf.EnableNotify;
}
public List ListIobAdapters { get; set; } = new List();
public LogLevelIob LogLevel
{
get => logLevel;
set
{
if (logLevel != value)
{
logLevel = value;
SetIobLogLevel($"{value}");
}
}
}
///
/// Massimo consumo di memoria da conf prima di invocare GC esplicito
///
public double MaxMemGc
{
get => currAppConf.TaskData.MaxMemoryGC;
}
///
/// Totale processi avviati
///
public int NumProcConfig
{
get => numProcConfig;
}
///
/// Totale processi running
///
public int NumProcRunning
{
get => numProcRunning;
}
///
/// Totale processi avviati
///
public int NumProcStarted
{
get => numProcStarted;
}
///
/// Totale processi avviati
///
public int NumTypeConfig
{
get => numTypeConfig;
}
public int RefreshPeriod
{
get => currAppConf.TaskData.TimerFastMSec;
set
{
if (currAppConf.TaskData.TimerFastMSec != value)
{
// verifico ammissibilità
currAppConf.TaskData.TimerFastMSec = value < refPMin ? refPMin : value > refPMax ? refPMax : value;
ReportConfigUpd();
}
}
}
///
/// Tempo totale esecuzione ultimo scan
///
public double RoundTrip
{
get => roundTripElaps;
}
///
/// Dataora prox controlloriavvio automatico
///
public DateTime VetoAutoCheck
{
get => _VetoAutoCheck;
}
#endregion Public Properties
#region Public Methods
public void DelayRestart(bool doReset)
{
_VetoAutoCheck = _VetoAutoCheck < DateTime.Now || doReset ? DateTime.Now : VetoAutoCheck;
_VetoAutoCheck = _VetoAutoCheck.AddMinutes(minDelayrestart);
ReportConfigUpd();
}
public void Dispose()
{
DoCloseAll(true);
}
///
/// Se abilitato esegue riavvio e report processi variati
///
/// se true esegue anche prima della scadenza veto
public void DoAutoRestart(bool doForce)
{
if (AutoRestartEnabled || doForce)
{
DoRestartPlcKo();
DoReopenClosed();
}
}
///
/// Chiude tutti i child
///
/// resetta elenco
public void DoCloseAll(bool doReset)
{
CheckRunningChild();
isBusy = true;
if (ListIobAdapters.Count > 0)
{
List listPID = new List();
try
{
// provo a chiudere tutti 1:1 per pID
listPID = ListIobAdapters
.Where(x => x.isRunning)
.Select(x => x.pID)
.ToList();
}
catch (Exception exc)
{
Log.Error($"Eccezione DoCloseAll.01:{Environment.NewLine}{exc}");
}
if (listPID.Count > 0)
{
Parallel.ForEach(listPID, pID =>
{
ForceKillByPID(pID);
});
// aspetto 100ms
Task.Delay(100);
}
List listNames = ListIobNames();
if (listNames.Count > 0)
{
Parallel.ForEach(listNames, prgName =>
{
ForceKillByName(prgName);
});
}
}
isBusy = false;
// verifico nuovamente i processi
CheckRunningChild();
isBusy = true;
List stillRunList = new List();
if (ListIobAdapters.Count > 0)
{
try
{
stillRunList = ListIobAdapters
.Where(x => x.isRunning)
.ToList();
}
catch (Exception exc)
{
Log.Error($"Eccezione DoCloseAll.03:{Environment.NewLine}{exc}");
}
}
// eventuale chiusura
if (stillRunList != null && stillRunList.Count > 0)
{
foreach (var item in stillRunList)
{
ForceKillByPID(item.pID);
ForceKillByName(item.ExeName);
}
}
// verifico se resettare
if (doReset)
{
// resetto elenco!
ListIobAdapters.Clear();
numProcStarted = 0;
}
// resetto
item2rem.Clear();
numProcRunning = 0;
isBusy = false;
}
///
/// Elenco degli EXE Names degli IOB gestiti (x chiamate di cleanup/chiusura)
///
///
private List ListIobNames()
{
List listNames = new List();
if (currIobConf != null && currIobConf.ListTarget != null && currIobConf.ListTarget.Count > 0)
{
// chiudo per nome SE rimasti
listNames = currIobConf
.ListTarget
.Select(x => x.Value.ExeName)
.Where(x => !string.IsNullOrEmpty(x))
.Distinct().ToList();
#if false
try
{
}
catch (Exception exc)
{
Log.Error($"Eccezione DoCloseAll.02:{Environment.NewLine}{exc}");
}
#endif
}
return listNames;
}
///
/// Apre il child selezionato
///
public void DoCloseChild(IobAdapt childReq)
{
isBusy = true;
ForceKillByPID(childReq.pID);
isBusy = false;
CheckRunningChild();
ReportStatusUpd();
}
///
/// Apre tutti i processi child e li registra...
///
public void DoOpenAllChild()
{
isBusy = true;
// preventivamente CHIUDO TUTTO per i programmi configurati...
var listNames = currIobConf
.ListTarget
.Select(x => x.Value.ExeName)
.Where(x => !string.IsNullOrEmpty(x))
.Distinct().ToList();
Parallel.ForEach(listNames, prgName =>
{
ForceKillByName(prgName);
});
Thread.Sleep(100);
// avvio i child
//Parallel.ForEach(currIobConf.ListIOB, item =>
//{
// startChildProc(item.Value, item.Key);
//});
foreach (var item in currIobConf.ListIOB)
{
startChildProc(item.Value, item.Key);
// attesa tra ogni avvio..
Thread.Sleep(100);
}
UpdateCounters();
ReportStatusUpd();
isBusy = false;
}
///
/// Apre il child selezionato
///
public void DoOpenChildSel(IobAdapt childReq)
{
isBusy = true;
startChildProc(childReq.TgtName, childReq.CodIOB);
UpdateCounters();
ReportStatusUpd();
isBusy = false;
}
///
/// Legge il file di configurazione APP e poi quello degli IobAdaptConf
///
public void DoReloadConfig()
{
ConfPathApp = Path.Combine(ConfDirBase, AppConfName);
if (File.Exists(ConfPathApp))
{
string rawData = File.ReadAllText(ConfPathApp);
if (!string.IsNullOrEmpty(rawData))
{
try
{
currAppConf = JsonConvert.DeserializeObject(rawData) ?? new AppSettings();
}
catch { }
}
}
// sistemo conf IobAdaptConf da gestire
if (currAppConf.IobAdapt != null && !string.IsNullOrEmpty(currAppConf.IobAdapt.ConfFile))
{
ConfDirIob = Path.Combine(ConfDirBase, currAppConf.IobAdapt.ConfDir);
ConfPathIob = Path.Combine(ConfDirIob, currAppConf.IobAdapt.ConfFile);
if (File.Exists(ConfPathIob))
{
string rawData = File.ReadAllText(ConfPathIob);
if (!string.IsNullOrEmpty(rawData))
{
try
{
currIobConf = JsonConvert.DeserializeObject(rawData) ?? new IobManConfig();
TargetIobList = currIobConf.ListTarget;
}
catch { }
}
// fix eventuale mancanza BaseArgs nel file raw di conf
if (!rawData.Contains("BaseArgs"))
{
RewriteConfFile();
}
}
// sistemo eventuali conf x target mancanti...
FixMissingTargets();
}
currIobType = currIobConf.ListIOB.Select(x => x.Value).Distinct().ToList();
numTypeConfig = currIobType.Count();
numProcConfig = currIobConf.ListIOB.Count();
// leggo altri valori
minDelayrestart = currAppConf.GetKVP_Int("DelayTimerRestart", 20);
}
///
/// Chiudo child che NON comunicano col PLC...
///
public void DoRestartPlcKo()
{
var listNotOk = ListIobAdapters.Where(x => !(x.plcOk)).ToList();
foreach (var item in listNotOk)
{
DoCloseChild(item);
}
// ora riapro!
foreach (var item in listNotOk)
{
DoOpenChildSel(item);
}
}
///
/// Riapro child chiusi
///
public void DoReopenClosed()
{
var listClosed = ListIobAdapters.Where(x => !(x.isRunning)).ToList();
foreach (var item in listClosed)
{
DoOpenChildSel(item);
}
}
///
/// Effettua scansione applicazioni, salva e solleva update
///
public async Task DoScan()
{
Stopwatch sw = new Stopwatch();
sw.Start();
await CheckRunningChildAsync();
ReportStatusUpd();
sw.Stop();
StatCollector.RecordExeData("ACService.DoScan", sw.Elapsed);
}
///
/// Restituisce conf del target IOB dato nome
///
///
///
public TargetConfig GetTargetConf(string codTarget)
{
TargetConfig answ = new TargetConfig();
if (currIobConf.ListTarget.ContainsKey(codTarget))
{
answ = currIobConf.ListTarget[codTarget];
}
return answ;
}
public string IobTgtPath(string codIOB)
{
string answ = "";
if (!string.IsNullOrEmpty(codIOB))
{
if (currIobConf.ListIOB.ContainsKey(codIOB))
{
string iobType = currIobConf.ListIOB[codIOB];
if (currIobConf.ListTarget.ContainsKey(iobType))
{
var exeName = currIobConf.ListTarget[iobType].ExePath;
answ = Path.GetDirectoryName(exeName) ?? exeName;
}
}
}
return answ;
}
public string IobType(string codIOB)
{
string answ = "";
if (!string.IsNullOrEmpty(codIOB))
{
if (currIobConf.ListIOB.ContainsKey(codIOB))
{
answ = currIobConf.ListIOB[codIOB];
}
}
return answ;
}
///
/// Display di tutte le statistiche collezionate
///
public void PrintStats()
{
foreach (var item in StatCollector.TaskData)
{
Log.Info($"Exec Stats | {item.Key} x {item.Value.NumRun} | {item.Value.AvgTime.TotalMilliseconds:N3}ms | total: {item.Value.TotalTime.TotalSeconds}s");
}
// reset
StatCollector.ForceReset();
}
///
/// Solleva evento richiesta reboot
///
public void RaiseRebootReq()
{
// sollevo evento
if (EA_RebootRequested != null)
{
EA_RebootRequested?.Invoke();
}
}
public void ReportStatusUpd()
{
if (EA_StatusUpdated != null)
{
EA_StatusUpdated?.Invoke();
}
}
///
/// Avvio di un child process da parametro ARG
///
/// Nome Target EXE
/// Args da passare all'exe (IobAdaptConf name da caricare)
/// posizione (opzionale) in lista
public void startChildProc(string tgtName, string codIob, int indice = -1)
{
Stopwatch sw = Stopwatch.StartNew();
// da testare x aprire chiudere risorsa...
string targetExe = @"C:\Steamware\IOB-WIN-NEXT\IOB-WIN-NEXT.exe";// utils.CRS("targetExe");
if (string.IsNullOrEmpty(targetExe))
{
targetExe = Path.Combine(AppContext.BaseDirectory, "Resources", "IOB-WIN-FACADE.exe");
}
string currTgtExe = targetExe;
string startArg = "MODE=MAN IOB=";// $"{utils.CRS("BaseArg")}{codIob}";
if (TargetIobList.Count > 0)
{
if (TargetIobList.ContainsKey(tgtName))
{
currTgtExe = TargetIobList[tgtName].ExePath;
startArg = $"{TargetIobList[tgtName].BaseArgs}{codIob}";
}
}
// verifico esistenza exe, altrimenti crea copia da IOB-WIN-FACADE
if (!File.Exists(currTgtExe))
{
// creo folder
if (!string.IsNullOrEmpty(currTgtExe))
{
string baseExeDir = Path.GetDirectoryName(currTgtExe) ?? "";
if (!string.IsNullOrEmpty(baseExeDir))
{
Directory.CreateDirectory(baseExeDir);
// creo folder conf..
Directory.CreateDirectory(Path.Combine(baseExeDir, "DATA", "CONF"));
// creo file exe!
string srcPath = Path.Combine(AppContext.BaseDirectory, "Resources", "IOB-WIN-FACADE.exe");
File.Copy(srcPath, currTgtExe);
}
}
}
// avvio processo
ProcessStartInfo psi = new ProcessStartInfo
{
//FileName = targetExe,
FileName = currTgtExe,
Arguments = startArg,
WindowStyle = ProcessWindowStyle.Minimized
};
try
{
//childProc.StartInfo = psi;
var p = Process.Start(psi);
if (p != null)
{
// accodo nuovo IobAdaptConf...
DateTime adesso = DateTime.Now;
var exeName = FileVersionInfo.GetVersionInfo(currTgtExe).FileDescription ?? p.ProcessName;
IobAdapt newIob = new IobAdapt(redisConn, codIob, p.Id, exeName, tgtName);
// cerco IOB tra quelli esistenti x calcolo posizione...
var prevRec = ListIobAdapters.FirstOrDefault(x => x.CodIOB == codIob);
if (prevRec != null)
{
indice = ListIobAdapters.IndexOf(prevRec);
}
// aggiungo a datasource, se indice -1 aggiungendo e basta, altrimenti alla posizione richiesta...
if (indice == -1)
{
ListIobAdapters.Add(newIob);
}
else
{
// rimuovo il vecchio
ListIobAdapters.RemoveAt(indice);
// inserisco il nuovo...
ListIobAdapters.Insert(indice, newIob);
}
sw.Stop();
Log.Info($"Avviato child process per {codIob} | pid: {p.Id} | {sw.ElapsedMilliseconds}ms");
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in startChildProc | codIOB: {codIob} | tgtName: {tgtName}{Environment.NewLine}{exc}");
}
}
#endregion Public Methods
#region Protected Fields
///
/// elenco item da rimuovere x check andato male...
///
protected static List item2rem = new List();
///
/// Dataora prossima scadenza riavvio automatico
///
protected DateTime _VetoAutoCheck = DateTime.Now;
protected string ConfDirBase = "";
protected List currIobType = new List();
protected string DeviceName = "";
protected int numProcConfig;
protected int numProcRunning;
protected int numProcStarted;
protected int numTypeConfig;
protected double roundTripElaps;
///
/// OBj x collezione statistiche
///
protected TaskRunStats StatCollector = new TaskRunStats();
#endregion Protected Fields
#region Protected Properties
protected AppSettings currAppConf { get; set; } = new AppSettings();
protected AppSettings CurrAppConf
{
get => currAppConf;
}
protected IobManConfig currIobConf { get; set; } = new IobManConfig();
protected SubLicManager SubLicManager { get; set; } = new SubLicManager();
#endregion Protected Properties
#region Protected Methods
///
/// Helper copia directory + contenuto
///
///
///
protected void CopyDirectory(string sourceDir, string destDir)
{
// Create the destination directory if it doesn't exist
if (!Directory.Exists(destDir))
{
Directory.CreateDirectory(destDir);
}
// copio SOLO SE ho la dir di partenza
if (Directory.Exists(sourceDir))
{
// Copy all files
foreach (var file in Directory.GetFiles(sourceDir))
{
string destFile = Path.Combine(destDir, Path.GetFileName(file));
File.Copy(file, destFile, true);
}
// Copy all subdirectories
foreach (var dir in Directory.GetDirectories(sourceDir))
{
string destSubDir = Path.Combine(destDir, Path.GetFileName(dir));
CopyDirectory(dir, destSubDir);
}
}
}
#endregion Protected Methods
#region Private Fields
///
/// Classe logger
///
private static Logger Log = LogManager.GetCurrentClassLogger();
private string AppConfName = "appsettings.json";
private string confDirIob = "";
///
/// Path file di conf Applicazione
///
private string ConfPathApp = "";
///
/// Path file di conf IobAdaptConf
///
private string ConfPathIob = "";
///
/// semaforo impegno in fase avvio/chiusura...
///
private bool isBusy = false;
private LogLevelIob logLevel = LogLevelIob.Info;
private int minDelayrestart = 30;
///
/// Valore massimo ammesso refresh millisecondi
///
private int refPMax = 10000;
///
/// Valore minimo ammesso refresh millisecondi
///
private int refPMin = 100;
///
/// Dizionario applicazioni target da lanciare
///
private Dictionary TargetIobList = new Dictionary();
///
/// Ms di attesa x uscita processo (std)
///
private int waitForExitMsec = 500;
#endregion Private Fields
#region Private Properties
private bool cloudCallActive { get; set; } = false;
private string CodImpiego { get; set; } = "";
///
/// multiplexer Redis
///
private ConnectionMultiplexer redisConn { get; set; } = null!;
#endregion Private Properties
#region Private Methods
private bool checkInstance(IobAdapt item, List processList)
{
bool needRem = false;
if (!isBusy)
{
try
{
// verifico se non sia già stato segnato x rimozione...)
if (item2rem.Find(x => x != null && x.pID == item.pID) != null)
{
needRem = true;
}
else
{
// verifico se esista il processo...
if (processList.Count > 0)
{
var p = processList.FirstOrDefault(pr => pr.Id == item.pID);
if (p != null)
{
needRem = p.HasExited;
}
else
{
needRem = true;
}
}
else
{
needRem = true;
}
if (needRem)
{
if (!item2rem.Contains(item))
{
item2rem.Add(item);
}
item.isRunning = false;
}
else
{
item.isRunning = true;
}
}
}
catch
{
needRem = true;
}
}
return needRem;
}
///
/// Verifica se i proc child siano ancora in RUN
///
private void CheckRunningChild()
{
bool needRem = false;
if (!isBusy)
{
Stopwatch sw = Stopwatch.StartNew();
// solo se ho qualocsa...
if (TargetIobList.Count > 0 && ListIobAdapters.Count > 0)
{
ConcurrentBag concList = new ConcurrentBag();
// effettua ricerca 1 proc alla volta
bool checkSingle = false;
if (checkSingle)
{
// 2024.12.16 chiamata parallela controllo processi
// chiamo in parallelo la ricerca di tutti i TIPI di EXE gestiti...
Parallel.ForEach(TargetIobList, item =>
{
// 2020.02.01 passato chiamata specifica x leggere in 1 sola volta elenco processi da nome
var tempProcList = Process.GetProcessesByName(item.Key);
foreach (var sProc in tempProcList)
{
concList.Add(sProc);
}
}
);
}
else
{
// 2025.06.04 recupero tutti i processi in un colpo solo
var allProcList = Process.GetProcesses();
// ...poi chiamata parallela controllo processi da tutti i TIPI di EXE gestiti...
Parallel.ForEach(TargetIobList, item =>
{
// ricerco x nome della targetlist...
var tempProcList = allProcList.Where(x => x.ProcessName == item.Key).ToList();
foreach (var sProc in tempProcList)
{
concList.Add(sProc);
}
}
);
// ciclo controllo
var list2check = concList.ToList();
if (list2check != null && list2check.Count > 0)
{
Parallel.ForEach(ListIobAdapters, item =>
{
needRem = checkInstance(item, list2check);
}
);
}
// li segno spenti...
else
{
foreach (var item in ListIobAdapters)
{
item.isRunning = false;
}
}
}
}
sw.Stop();
roundTripElaps = sw.Elapsed.TotalMilliseconds;
}
UpdateCounters();
}
///
/// Verifica se i proc child siano ancora in RUN
///
private async Task CheckRunningChildAsync()
{
bool needRem = false;
if (!isBusy)
{
Stopwatch sw = Stopwatch.StartNew();
// solo se ho qualocsa...
if (TargetIobList.Count > 0 && ListIobAdapters.Count > 0)
{
ConcurrentBag concList = new ConcurrentBag();
// effettua ricerca 1 proc alla volta
bool checkSingle = false;
if (checkSingle)
{
// 2024.12.16 chiamata parallela controllo processi
// chiamo in parallelo la ricerca di tutti i TIPI di EXE gestiti...
Parallel.ForEach(TargetIobList, item =>
{
// 2020.02.01 passato chiamata specifica x leggere in 1 sola volta elenco processi da nome
var tempProcList = Process.GetProcessesByName(item.Key);
foreach (var sProc in tempProcList)
{
concList.Add(sProc);
}
}
);
}
else
{
//// 2025.06.04 recupero tutti i processi in un colpo solo
//var allProcList = Process.GetProcesses();
// 2025.11.26: tutti i processi ma in modalità asincrona su altro thread
var allProcList = await Task.Run(() => Process.GetProcesses());
// ...poi chiamata parallela controllo processi da tutti i TIPI di EXE gestiti...
Parallel.ForEach(TargetIobList, item =>
{
// ricerco x nome della targetlist...
var tempProcList = allProcList.Where(x => x.ProcessName == item.Key).ToList();
foreach (var sProc in tempProcList)
{
concList.Add(sProc);
}
}
);
// ciclo controllo
var list2check = concList.ToList();
if (list2check != null && list2check.Count > 0)
{
Parallel.ForEach(ListIobAdapters, item =>
{
needRem = checkInstance(item, list2check);
}
);
}
}
}
sw.Stop();
roundTripElaps = sw.Elapsed.TotalMilliseconds;
StatCollector.RecordExeData("RoundTrip", sw.Elapsed);
}
UpdateCounters();
}
///
/// Elimina contenuto directory
///
///
private void DeleteDirectoryContents(string directoryPath)
{
// recupero info dir
DirectoryInfo directory = new DirectoryInfo(directoryPath);
// elimina file
foreach (FileInfo file in directory.GetFiles())
{
file.Delete();
}
// elimina ulteriori directory
foreach (DirectoryInfo subDirectory in directory.GetDirectories())
{
subDirectory.Delete(true);
}
}
private void DoSetupRedis()
{
string redisConnStr = currAppConf.Redis;
redisConn = ConnectionMultiplexer.Connect(redisConnStr);
}
///
/// Verifica target richiesti e configurati, con sistemazione file conf x mancanti eventuali...
///
private void FixMissingTargets()
{
bool needWrite = false;
string baseArgs = currAppConf.GetKVP("BaseArgs");
// verifico tutti i target IOB...
foreach (var sIob in currIobConf.ListIOB)
{
// se mancasse il target lo aggiungo...
if (!TargetIobList.ContainsKey(sIob.Value))
{
// prendo il primo target list
var sTarget = TargetIobList.FirstOrDefault();
// ...e sostituisco...
TargetConfig defTgt = new TargetConfig()
{
ExeName = sIob.Value,
ExePath = sTarget.Value.ExePath.Replace(sTarget.Key, sIob.Value),
LogDir = sTarget.Value.LogDir.Replace(sTarget.Key, sIob.Value),
ConfDir = sTarget.Value.ConfDir.Replace(sTarget.Key, sIob.Value),
NLogPath = sTarget.Value.NLogPath.Replace(sTarget.Key, sIob.Value),
BaseArgs = baseArgs
};
TargetIobList.Add(sIob.Value, defTgt);
needWrite = true;
}
}
// 2025.01.08: salvo il file aggiornato...
if (needWrite)
{
RewriteConfFile();
}
}
///
/// Effettua un force kill dato nome processo
///
///
private void ForceKillByName(string nomeProc)
{
Process[] stillRunningProc = Process.GetProcessesByName(nomeProc);
if (stillRunningProc != null)
{
if (stillRunningProc.Length > 0)
{
foreach (var item in stillRunningProc)
{
try
{
Process p = Process.GetProcessById(item.Id);
{
if (!p.HasExited)
{
int closeWaitTime = waitForExitMsec * 8;
// se è MAN --> aspetto + a lungo...
if (nomeProc.Contains("IOB-MAN"))
{
closeWaitTime = closeWaitTime * 4;
}
p.CloseMainWindow();
p.WaitForExit(closeWaitTime);
}
if (!p.HasExited)
{
Log.Error($"Process not Exited, 2nd try p.kill()");
p.Kill();
p.WaitForExit(waitForExitMsec);
}
if (!p.HasExited)
{
Log.Error($"Process not Killed, 3nd try p.kill()");
p.Kill();
p.WaitForExit(waitForExitMsec * 2);
}
if (!p.HasExited)
{
Log.Error($"Process not Killed, 4th try p.kill()");
p.Kill();
}
}
}
catch (Exception exc)
{
Log.Error($"Errore in fase di kill processo da nome {exc}");
}
}
}
}
}
///
/// Effettua chiusura processo da pID
///
///
private void ForceKillByPID(int pID)
{
try
{
using (Process p = Process.GetProcessById(pID))
{
int numTry = 5;
if (!p.HasExited)
{
p.CloseMainWindow(); // prova a chiudere gentilmente
while (numTry > 0 && !p.HasExited)
{
Log.Info($"Process {p.Id} not exited, waiting for {waitForExitMsec}ms");
p.WaitForExit(waitForExitMsec);
numTry--;
}
if (!p.HasExited)
{
Log.Error($"Process {p.Id} not exited, now calling p.Kill()");
p.Kill();
}
else
{
Log.Info("-----------------------------------");
Log.Info($"Process {p.Id} closed!!!");
Log.Info("-----------------------------------");
}
}
}
}
catch (ArgumentException)
{
Log.Warn($"Process with PID {pID} does not exist anymore.");
}
catch (Exception exc)
{
Log.Error($"Errore in fase di chiusura processo (pid: {pID}){Environment.NewLine}{exc}");
}
}
///
/// Esecuzione init configurazione + restart globale (se richiesto)
///
///
private void LoadConfAndStart(bool startProc)
{
int stepLoad = 0;
try
{
Log.Info($"LoadConfAndStart | {stepLoad++:00}");
string startDir = Path.GetDirectoryName(AppContext.BaseDirectory)!;
Log.Trace($"LoadConfAndStart starting | startDir: {startDir} | target Framework: {AppContext.TargetFrameworkName}");
ConfDirBase = startDir;
// init configurazioni
DoReloadConfig();
Log.Info($"LoadConfAndStart | {stepLoad++:00}");
// init servizio Redis monitoring
DoSetupRedis();
Log.Trace($"Config setup done | ConfPathApp: {ConfPathApp} | ConfPathIob: {ConfPathIob}");
Log.Info($"LoadConfAndStart | {stepLoad++:00}");
// sistemo log a INFO
SetIobLogLevel("INFO");
Log.Trace($"Log set to INFO");
Log.Info($"LoadConfAndStart | {stepLoad++:00}");
if (startProc)
{
// chiudo eventuali processi in RUN
DoCloseAll(false);
Log.Info($"LoadConfAndStart | StartProc | {stepLoad++:00}");
// forzo chiusura processi "like" se configurato
DoForceCloseByName();
Log.Info($"LoadConfAndStart | StartProc | {stepLoad++:00}");
// avvio i processi...
DoOpenAllChild();
Log.Trace($"Child Opened");
Log.Info($"LoadConfAndStart | StartProc | {stepLoad++:00}");
// avvio timers e schedulazioni varie
StartScheduler();
Log.Info($"LoadConfAndStart | StartProc | {stepLoad++:00}");
}
}
catch (Exception exc)
{
Log.Error($"Error in AppControlService.init:{Environment.NewLine}{exc}");
}
Log.Info($"LoadConfAndStart | DONE! | {stepLoad++:00}");
}
private void DoForceCloseByName()
{
if (currAppConf.TaskData.ForceKillName.Count > 0)
{
ConcurrentBag concList = new ConcurrentBag();
// effettua ricerca processi like se configurato
// Get all processes running on the machine
Process[] allProcesses = Process.GetProcesses();
foreach (var procName in currAppConf.TaskData.ForceKillName)
{
// Filter processes whose name starts with "Test"
var testProcesses = allProcesses
.Where(p => p.ProcessName.StartsWith(procName, StringComparison.OrdinalIgnoreCase))
.ToList();
foreach (var item in testProcesses)
{
ForceKillByPID(item.Id);
}
}
}
}
private void ReportConfigUpd()
{
if (EA_ConfigUpdated != null)
{
EA_ConfigUpdated?.Invoke();
}
}
///
/// Esegue riscrittura file di conf da parametri correnti a json
///
private void RewriteConfFile()
{
IobManConfig currIobManConf = new IobManConfig()
{
ListIOB = currIobConf.ListIOB,
ListTarget = TargetIobList
};
// serializzo e salvo file!
string jsonData = JsonConvert.SerializeObject(currIobManConf, Formatting.Indented);
File.WriteAllText(ConfPathIob, jsonData);
}
///
/// Imposta livello log nei file di conf degli IOB tramite procedura x riscrivere il file conf di NLog
///
///
private void SetIobLogLevel(string logReq)
{
// leggo il file loglevel in resources
string tplPath = Path.Combine(ConfDirBase, "Resources", "NLog.template.config");
string rawData = File.ReadAllText(tplPath);
// sostituzione livello minimo da selezione
rawData = rawData.Replace("{{minLevel}}", logReq);
// scrivo conf x SW gestiti
foreach (var item in TargetIobList)
{
if (!File.Exists(item.Value.NLogPath))
{
// verifico folder parent...
string parentDir = Path.GetDirectoryName(item.Value.NLogPath) ?? "";
if (!string.IsNullOrEmpty(parentDir) && !Directory.Exists(parentDir))
{
Directory.CreateDirectory(parentDir);
}
}
File.WriteAllText(item.Value.NLogPath, rawData);
}
// elimino riferimento al codIOB dalla conf...
rawData = rawData.Replace(@"/${var:codIOB:default=0000}", "");
// scrivo conf x programma IOB-MAN
string nlogFPath = Path.Combine(ConfDirBase, "NLog.config");
File.WriteAllText(nlogFPath, rawData);
}
///
/// Avvia schedulatore reboot
///
private void StartScheduler()
{
// avvio lo schedulatore, se abilitato...
if (currAppConf.TaskData.AutoRebootEnabled)
{
var dtReq = currAppConf.TaskData.AutoRebootTSpan;
TaskSchedulerService.IntervalInMinutes(dtReq.Hours, dtReq.Minutes, currAppConf.TaskData.AutoRebootMinutes, () =>
{
#if false
// vecchia versione reload
LoadConfAndStart(true);
#endif
// esecuzione reboot come da button Reboot
RaiseRebootReq();
});
}
}
private void UpdateCounters()
{
try
{
if (ListIobAdapters != null && ListIobAdapters.Count > 0)
{
numProcStarted = ListIobAdapters.Where(x => x.isRunning).Count();
numProcRunning = ListIobAdapters.Where(x => x.isRunning && x.plcOk && x.iobOnline).Count();
}
else
{
numProcStarted = 0;
numProcRunning = 0;
}
}
catch (Exception exc)
{
Log.Error($"Eccezione in UpdateCounters{Environment.NewLine}{exc}");
}
}
#endregion Private Methods
}
}