1080 lines
36 KiB
C#
1080 lines
36 KiB
C#
using EgwCoreLib.Utils;
|
|
using IOB_MAN8.Core.Config;
|
|
using IOB_MAN8.Core.Data;
|
|
using IOB_MAN8.Core.DTO;
|
|
using IOB_MAN8.Core.Models;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using StackExchange.Redis;
|
|
using System.Collections.Concurrent;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using static IOB_MAN8.Core.CoreEnum;
|
|
|
|
namespace IOB_MAN8.Core.Services
|
|
{
|
|
public class AppControlService : IAppControlService, IDisposable
|
|
{
|
|
#region Public Constructors
|
|
|
|
/// <summary>
|
|
/// Init classe
|
|
/// </summary>
|
|
/// <param name="startProc">Se True avvia i processi gestiti</param>
|
|
public AppControlService(bool startProc)
|
|
{
|
|
LoadConfAndStart(startProc);
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Events
|
|
|
|
/// <summary>
|
|
/// Evento update configurazione
|
|
/// </summary>
|
|
public event Action EA_ConfigUpdated = null!;
|
|
|
|
/// <summary>
|
|
/// Evento richiesta reload applicazione
|
|
/// </summary>
|
|
public event Action EA_ReloadRequested = null!;
|
|
|
|
/// <summary>
|
|
/// Evento richiesta update applicazione (con check update app)
|
|
/// </summary>
|
|
public event Action EA_RestartRequested = null!;
|
|
|
|
/// <summary>
|
|
/// Evento update status controlli
|
|
/// </summary>
|
|
public event Action EA_StatusUpdated = null!;
|
|
|
|
#endregion Public Events
|
|
|
|
#region Public Properties
|
|
|
|
/// <summary>
|
|
/// Abilitazione autorestart
|
|
/// </summary>
|
|
public bool AutoRestartEnabled { get; set; } = true;
|
|
|
|
public int CheckRestartPeriod
|
|
{
|
|
get => currAppConf.TaskData.TimerCheckMSec;
|
|
set => currAppConf.TaskData.TimerCheckMSec = value;
|
|
}
|
|
|
|
public string ConfDirIob
|
|
{
|
|
get => confDirIob;
|
|
set => confDirIob = value;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Configurazione IOB in sola lettura
|
|
/// </summary>
|
|
public IobManConfig CurrIobConf
|
|
{
|
|
get => currIobConf;
|
|
}
|
|
|
|
public List<string> CurrIobType
|
|
{
|
|
get => currIobType;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ABilitazione glocale notifiche da conf
|
|
/// </summary>
|
|
public bool EnableNotify
|
|
{
|
|
get => currAppConf.EnableNotify;
|
|
}
|
|
|
|
public List<IobAdapt> ListIobAdapters { get; set; } = new List<IobAdapt>();
|
|
|
|
public LogLevelIob LogLevel
|
|
{
|
|
get => logLevel;
|
|
set
|
|
{
|
|
if (logLevel != value)
|
|
{
|
|
logLevel = value;
|
|
SetIobLogLevel($"{value}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Totale processi avviati
|
|
/// </summary>
|
|
public int NumProcConfig
|
|
{
|
|
get => numProcConfig;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Totale processi running
|
|
/// </summary>
|
|
public int NumProcRunning
|
|
{
|
|
get => numProcRunning;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Totale processi avviati
|
|
/// </summary>
|
|
public int NumProcStarted
|
|
{
|
|
get => numProcStarted;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Totale processi avviati
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dataora prox controlloriavvio automatico
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Se abilitato esegue riavvio e report processi variati
|
|
/// </summary>
|
|
/// <param name="doForce">se true esegue anche prima della scadenza veto</param>
|
|
public void DoAutoRestart(bool doForce)
|
|
{
|
|
if (AutoRestartEnabled || doForce)
|
|
{
|
|
DoReopenClosed();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Chiude tutti i child
|
|
/// </summary>
|
|
/// <param name="doReset">resetta elenco</param>
|
|
public void DoCloseAll(bool doReset)
|
|
{
|
|
isBusy = true;
|
|
CheckRunningchild();
|
|
// provo a chiudere tutti 1:1 per pID
|
|
var listPID = ListIobAdapters
|
|
.Where(x => x.isRunning)
|
|
.Select(x => x.pID)
|
|
.ToList();
|
|
#if true
|
|
Parallel.ForEach(listPID, pID =>
|
|
{
|
|
ForceKillByPID(pID);
|
|
});
|
|
#else
|
|
foreach(var pID in listPID)
|
|
{
|
|
ForceKillByPID(pID);
|
|
}
|
|
#endif
|
|
|
|
// chiudo per nome SE rimasti
|
|
var listNames = currIobConf
|
|
.ListTarget
|
|
.Select(x => x.Value.ExeName)
|
|
.Where(x => !string.IsNullOrEmpty(x))
|
|
.Distinct().ToList();
|
|
Parallel.ForEach(listNames, prgName =>
|
|
{
|
|
ForceKillByName(prgName);
|
|
});
|
|
// aspetto 100ms
|
|
// verifico nuovamente i processi
|
|
CheckRunningchild();
|
|
var stillRunList = ListIobAdapters
|
|
.Where(x => x.isRunning)
|
|
.ToList();
|
|
// eventuale chiusura
|
|
if (stillRunList != null && stillRunList.Count > 0)
|
|
{
|
|
foreach (var item in stillRunList)
|
|
{
|
|
ForceKillByPID(item.pID);
|
|
ForceKillByName(item.ExeName);
|
|
}
|
|
#if false
|
|
Parallel.ForEach(stillRunList, item =>
|
|
{
|
|
ForceKillByPID(item.pID);
|
|
ForceKillByName(item.ExeName);
|
|
});
|
|
#endif
|
|
}
|
|
|
|
// verifico se resettare
|
|
if (doReset)
|
|
{
|
|
// resetto elenco!
|
|
ListIobAdapters.Clear();
|
|
numProcStarted = 0;
|
|
}
|
|
// resetto
|
|
item2rem.Clear();
|
|
numProcRunning = 0;
|
|
isBusy = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apre il child selezionato
|
|
/// </summary>
|
|
public void DoCloseChild(IobAdapt childReq)
|
|
{
|
|
isBusy = true;
|
|
ForceKillByPID(childReq.pID);
|
|
CheckRunningchild();
|
|
|
|
ReportStatusUpd();
|
|
isBusy = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apre tutti i processi child e li registra...
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Apre il child selezionato
|
|
/// </summary>
|
|
public void DoOpenChildSel(IobAdapt childReq)
|
|
{
|
|
isBusy = true;
|
|
startChildProc(childReq.TgtName, childReq.CodIOB);
|
|
UpdateCounters();
|
|
ReportStatusUpd();
|
|
isBusy = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Legge il file di configurazione APP e poi quello degli IobAdaptConf
|
|
/// </summary>
|
|
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<AppSettings>(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<IobManConfig>(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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// riapro child chiusi
|
|
/// </summary>
|
|
public void DoReopenClosed()
|
|
{
|
|
var listClosed = ListIobAdapters.Where(x => !x.isRunning).ToList();
|
|
foreach (var item in listClosed)
|
|
{
|
|
DoOpenChildSel(item);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua scansione applicazioni, salva e solleva update
|
|
/// </summary>
|
|
public async Task DoScan()
|
|
{
|
|
CheckRunningchild();
|
|
await Task.Delay(1);
|
|
ReportStatusUpd();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce conf del target IOB dato nome
|
|
/// </summary>
|
|
/// <param name="codTarget"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Solleva evento richiesta restart
|
|
/// </summary>
|
|
public void RaiseRestartReq()
|
|
{
|
|
// sollevo evento
|
|
if (EA_RestartRequested != null)
|
|
{
|
|
EA_RestartRequested?.Invoke();
|
|
}
|
|
}
|
|
|
|
public void ReportStatusUpd()
|
|
{
|
|
if (EA_StatusUpdated != null)
|
|
{
|
|
EA_StatusUpdated?.Invoke();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Avvio di un child process da parametro ARG
|
|
/// </summary>
|
|
/// <param name="tgtName">Nome Target EXE</param>
|
|
/// <param name="codIob">Args da passare all'exe (IobAdaptConf name da caricare)</param>
|
|
/// <param name="indice">posizione (opzionale) in lista</param>
|
|
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
|
|
|
|
/// <summary>
|
|
/// elenco item da rimuovere x check andato male...
|
|
/// </summary>
|
|
protected static List<IobAdapt> item2rem = new List<IobAdapt>();
|
|
|
|
/// <summary>
|
|
/// Dataora prossima scadenza riavvio automatico
|
|
/// </summary>
|
|
protected DateTime _VetoAutoCheck = DateTime.Now;
|
|
|
|
protected string ConfDirBase = "";
|
|
protected List<string> currIobType = new List<string>();
|
|
protected string DeviceName = "";
|
|
protected int numProcConfig;
|
|
protected int numProcRunning;
|
|
protected int numProcStarted;
|
|
protected int numTypeConfig;
|
|
|
|
#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
|
|
|
|
/// <summary>
|
|
/// Helper copia directory + contenuto
|
|
/// </summary>
|
|
/// <param name="sourceDir"></param>
|
|
/// <param name="destDir"></param>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Classe logger
|
|
/// </summary>
|
|
private static Logger Log = LogManager.GetCurrentClassLogger();
|
|
|
|
private string AppConfName = "appsettings.json";
|
|
|
|
private string confDirIob = "";
|
|
|
|
/// <summary>
|
|
/// Path file di conf Applicazione
|
|
/// </summary>
|
|
private string ConfPathApp = "";
|
|
|
|
/// <summary>
|
|
/// Path file di conf IobAdaptConf
|
|
/// </summary>
|
|
private string ConfPathIob = "";
|
|
|
|
/// <summary>
|
|
/// semaforo impegno in fase avvio/chiusura...
|
|
/// </summary>
|
|
private bool isBusy = false;
|
|
|
|
private LogLevelIob logLevel = LogLevelIob.Info;
|
|
|
|
private int minDelayrestart = 30;
|
|
|
|
/// <summary>
|
|
/// Valore massimo ammesso refresh millisecondi
|
|
/// </summary>
|
|
private int refPMax = 10000;
|
|
|
|
/// <summary>
|
|
/// Valore minimo ammesso refresh millisecondi
|
|
/// </summary>
|
|
private int refPMin = 100;
|
|
|
|
/// <summary>
|
|
/// Dizionario applicazioni target da lanciare
|
|
/// </summary>
|
|
private Dictionary<string, TargetConfig> TargetIobList = new Dictionary<string, TargetConfig>();
|
|
|
|
/// <summary>
|
|
/// Ms di attesa x uscita processo (std)
|
|
/// </summary>
|
|
private int waitForExitMsec = 250;
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Private Properties
|
|
|
|
private bool cloudCallActive { get; set; } = false;
|
|
|
|
private string CodImpiego { get; set; } = "";
|
|
|
|
/// <summary>
|
|
/// multiplexer Redis
|
|
/// </summary>
|
|
private ConnectionMultiplexer redisConn { get; set; } = null!;
|
|
|
|
#endregion Private Properties
|
|
|
|
#region Private Methods
|
|
|
|
private bool checkIstance(IobAdapt item, List<Process> processList)
|
|
{
|
|
bool needRem = false;
|
|
if (!isBusy)
|
|
{
|
|
// 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...
|
|
try
|
|
{
|
|
if (processList.Count > 0)
|
|
{
|
|
Process p = processList.FirstOrDefault(pr => pr.Id == item.pID);
|
|
if (p != null)
|
|
{
|
|
needRem = p.HasExited;
|
|
}
|
|
else
|
|
{
|
|
needRem = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
needRem = true;
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
needRem = true;
|
|
}
|
|
if (needRem)
|
|
{
|
|
if (!item2rem.Contains(item))
|
|
{
|
|
item2rem.Add(item);
|
|
}
|
|
item.isRunning = false;
|
|
}
|
|
else
|
|
{
|
|
item.isRunning = true;
|
|
}
|
|
}
|
|
}
|
|
return needRem;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica se i proc child siano ancora in RUN
|
|
/// </summary>
|
|
private void CheckRunningchild()
|
|
{
|
|
bool needRem = false;
|
|
if (!isBusy)
|
|
{
|
|
// solo se ho qualocsa...
|
|
if (TargetIobList.Count > 0 && ListIobAdapters.Count > 0)
|
|
{
|
|
ConcurrentBag<Process> concList = new ConcurrentBag<Process>();
|
|
|
|
// 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
|
|
Parallel.ForEach(ListIobAdapters, item =>
|
|
{
|
|
needRem = checkIstance(item, concList.ToList());
|
|
}
|
|
);
|
|
}
|
|
}
|
|
}
|
|
UpdateCounters();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elimina contenuto directory
|
|
/// </summary>
|
|
/// <param name="directoryPath"></param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica target richiesti e configurati, con sistemazione file conf x mancanti eventuali...
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua un force kill dato nome processo
|
|
/// </summary>
|
|
/// <param name="nomeProc"></param>
|
|
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}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua chiusura processo da pID
|
|
/// </summary>
|
|
/// <param name="pID"></param>
|
|
private void ForceKillByPID(int pID)
|
|
{
|
|
try
|
|
{
|
|
int numTry = 5;
|
|
Process p = Process.GetProcessById(pID);
|
|
if (p != null && p.Responding)
|
|
{
|
|
p.WaitForExit(waitForExitMsec);
|
|
p.CloseMainWindow();
|
|
while (numTry > 0 && !p.HasExited && p.Responding)
|
|
{
|
|
Log.Info($"Process {p.Id} not exited, waiting for {waitForExitMsec}ms");
|
|
p.WaitForExit(waitForExitMsec);
|
|
numTry--;
|
|
//p = Process.GetProcessById(pID);
|
|
}
|
|
|
|
p = Process.GetProcessById(pID);
|
|
if (!p.HasExited && p.Responding)
|
|
{
|
|
Log.Error($"Process {p.Id} not exited, now calling p.Kill()");
|
|
p.Kill();
|
|
}
|
|
else
|
|
{
|
|
Log.Info($"Process {p.Id} closed");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Errore in fase di chiusura processo (pid: {pID} ) da elenco{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esecuzione init configurazione + restart globale (se richiesto)
|
|
/// </summary>
|
|
/// <param name="startProc"></param>
|
|
private void LoadConfAndStart(bool startProc)
|
|
{
|
|
try
|
|
{
|
|
string startDir = Path.GetDirectoryName(AppContext.BaseDirectory)!;
|
|
Log.Trace($"LoadConfAndStart starting | startDir: {startDir} | target Framework: {AppContext.TargetFrameworkName}");
|
|
ConfDirBase = startDir;
|
|
// init configurazioni
|
|
DoReloadConfig();
|
|
|
|
// init servizio Redis monitoring
|
|
DoSetupRedis();
|
|
Log.Trace($"Config setup done | ConfPathApp: {ConfPathApp} | ConfPathIob: {ConfPathIob}");
|
|
|
|
// sistemo log a INFO
|
|
SetIobLogLevel("INFO");
|
|
Log.Trace($"Log set to INFO");
|
|
|
|
if (startProc)
|
|
{
|
|
// avvio i processi...
|
|
DoOpenAllChild();
|
|
Log.Trace($"Child Opened");
|
|
|
|
// avvio timers e schedulazioni varie
|
|
StartScheduler();
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
Log.Error($"Error in AppControlService.init:{Environment.NewLine}{exc}");
|
|
}
|
|
}
|
|
|
|
private void ReportConfigUpd()
|
|
{
|
|
if (EA_ConfigUpdated != null)
|
|
{
|
|
EA_ConfigUpdated?.Invoke();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Esegue riscrittura file di conf da parametri correnti a json
|
|
/// </summary>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Imposta livello log nei file di conf degli IOB tramite procedura x riscrivere il file conf di NLog
|
|
/// </summary>
|
|
/// <param name="logReq"></param>
|
|
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 programma IOB-MAN
|
|
string nlogFPath = Path.Combine(ConfDirBase, "NLog.config");
|
|
File.WriteAllText(nlogFPath, rawData);
|
|
|
|
// 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 (!Directory.Exists(parentDir))
|
|
{
|
|
Directory.CreateDirectory(parentDir);
|
|
}
|
|
}
|
|
File.WriteAllText(item.Value.NLogPath, rawData);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Avvia schedulatore reboot
|
|
/// </summary>
|
|
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, () =>
|
|
{
|
|
LoadConfAndStart(true);
|
|
});
|
|
}
|
|
}
|
|
|
|
private void UpdateCounters()
|
|
{
|
|
numProcStarted = ListIobAdapters.Where(x => x.isRunning).Count();
|
|
numProcRunning = ListIobAdapters.Where(x => x.isRunning && x.plcOk && x.iobOnline).Count();
|
|
}
|
|
|
|
#endregion Private Methods
|
|
}
|
|
} |