Files
Mapo-IOB-WIN/IOB-MAN/IOBManPanel.cs
T
2020-12-09 15:32:32 +01:00

1257 lines
42 KiB
C#

using Newtonsoft.Json;
using Steamware.Scheduler;
using SteamWare.IO;
using SteamWare.Logger;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace IOB_MAN
{
public partial class IOBManPanel : Form
{
#region Private Fields
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_SHOWMINIMIZED = 2;
private const int SW_SHOWNORMAL = 1;
/// <summary>
/// Context x sync thread
/// </summary>
private readonly SynchronizationContext synchronizationContext;
/// <summary>
/// Oggetto semaforico di lock
/// </summary>
private SemaphoreSlim _sync = new SemaphoreSlim(1);
/// <summary>
/// Binding source degli elementi gestiti..
/// </summary>
private BindingSource ElencoIOB = new BindingSource();
#endregion Private Fields
#region Protected Fields
/// <summary>
/// elenco item da rimuovere x check andato male...
/// </summary>
protected static List<iobAdapt> item2rem = new List<iobAdapt>();
/// <summary>
/// Ramo applicazione (x update)
/// </summary>
protected string branchName = "master";
/// <summary>
/// Counter del timer di base
/// </summary>
protected int checkPeriod = 2000;
/// <summary>
/// semaforo check...
/// </summary>
protected bool checkRunning = false;
/// <summary>
/// Counter del timer di forceCheck (60 sec, era 5 sec)
/// </summary>
protected int forceCheckPeriodMult = 30;
/// <summary>
/// Indica ultimo stato del check di restart...
/// </summary>
protected bool lastHlRestart = false;
/// <summary>
/// Totale processi avviati - ULTIMO dato mostrato
/// </summary>
protected int lastNumProcAvviati = 0;
/// <summary>
/// Totale processi running - ULTIMO dato mostrato
/// </summary>
protected int lastNumProcRunning = 0;
/// <summary>
/// Numero di Lock effettuati con successo
/// </summary>
protected int numLockFail = 0;
/// <summary>
/// Numero di lock falliti
/// </summary>
protected int numLockSuccess = 0;
/// <summary>
/// Totale processi avviati
/// </summary>
protected int numProcAvviati;
/// <summary>
/// Totale processi running
/// </summary>
protected int numProcRunning;
/// <summary>
/// Path dell'exe da chiamare
/// </summary>
protected string TargetExe = "";
/// <summary>
/// Name dell'exe da chiamare
/// </summary>
protected string TargetName = "";
/// <summary>
/// Dataora prossima scadenza riavvio automatico
/// </summary>
protected DateTime tOutAutocheck = DateTime.Now;
/// <summary>
/// Counter del timer UI
/// </summary>
protected int uiPeriod = 250;
/// <summary>
/// Ms di attesa x uscita processo (std)
/// </summary>
protected int waitForExitMsec = 250;
#endregion Protected Fields
#region Public Fields
/// <summary>
/// Elenco ARGS (uno per child da avviare)
/// </summary>
public List<string> ArgsList = new List<string>();
#endregion Public Fields
#region Public Constructors
/// <summary>
/// Init classe
/// </summary>
public IOBManPanel()
{
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
preInit();
loadConfig();
initTimers();
initControls();
updateStatus();
}
#endregion Public Constructors
#region Protected Properties
/// <summary>
/// URL stringa di UPDATE...
/// </summary>
protected string updateUrl
{
get
{
return string.Format("http://seriate.steamware.net:8083/SWS/MAPO/IOB-MAN/{0}/manifest.xml", branchName);
}
}
#endregion Protected Properties
#region Private Methods
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
/// <summary>
/// Apro un child x ogni args specificato
/// </summary>
private void apriChild()
{
// preventivamente CHIUDO TUTTO
forceKillByName(TargetName);
//closeAllChild(true);
Thread.Sleep(250);
// avvio i child
foreach (var item in ArgsList)
{
startChildProc(item);
}
numProcAvviati = ArgsList.Count;
updateNumRunning();
}
private void apriChildSel()
{
// SOLO SE selezionato in dgv...
if (dgvManagedItems.SelectedRows.Count > 0)
{
// ciclo su row selezionate
foreach (DataGridViewRow riga in dgvManagedItems.SelectedRows)
{
// verifico che sia già chiuso...
if (((iobAdapt)ElencoIOB[riga.Index]).isRunning == false)
{
startChildProc(((iobAdapt)ElencoIOB[riga.Index]).CodIOB, riga.Index);
// rimuovo vecchia riga...
ElencoIOB.RemoveAt(riga.Index);
}
}
}
updateNumRunning();
updateStatus();
}
/// <summary>
/// Apro un child x fare update con parametro che impedisca avvio IOB
/// </summary>
private void apriOneUpdate()
{
ProcessStartInfo psi = null;
// da testare x aprire chiudere risorsa...
psi = new ProcessStartInfo
{
FileName = TargetExe,
Arguments = "MODE=UPD IOB=NONE",
WindowStyle = ProcessWindowStyle.Normal
};
// avvio processo con using...
using (Process p = Process.Start(psi))
{
p.WaitForExit();
// ora chiudo current... SE configurato
if (utils.CRB("closeOnChildUpdate"))
{
this.Close();
}
}
updateNumRunning();
}
private void AutoUpdater_ApplicationExitEvent()
{
utils.lgInfo("Chiusura IOB-WIN");
Thread.Sleep(100);
// chiudo tutto
closeAllChild(true);
Thread.Sleep(1000);
utils.lgInfo("Chiusura Applicazione");
// attendo 1 sec...
Thread.Sleep(1000);
// ESCO!
Application.Exit();
}
/// <summary>
/// Chiudo primo processo child (se ce ne sono)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnClose_Click(object sender, EventArgs e)
{
chiudiChildSel();
}
private void btnCloseAll_Click(object sender, EventArgs e)
{
// chiude tutto
closeAllChild(false);
//apriChild();
updateNumRunning();
updateStatus();
}
private void btnMaximixeAll_Click(object sender, EventArgs e)
{
foreach (iobAdapt item in ElencoIOB.List)
{
if (item.isRunning)
{
try
{
Process p = Process.GetProcessById(item.pID);
// cerco e chiudo quelli che mi interessano...
var windowsHandle = p.MainWindowHandle;
ShowWindowAsync(windowsHandle, SW_SHOWNORMAL);
}
catch (Exception exc)
{
// errore era già chiuso..
utils.lgError($"Errore in SHOW windows:{Environment.NewLine}{exc}");
}
}
}
}
private void btnMinimizeAll_Click(object sender, EventArgs e)
{
foreach (iobAdapt item in ElencoIOB.List)
{
if (item.isRunning)
{
try
{
Process p = Process.GetProcessById(item.pID);
// cerco e chiudo quelli che mi interessano...
var windowsHandle = p.MainWindowHandle;
ShowWindowAsync(windowsHandle, SW_SHOWMINIMIZED);
}
catch (Exception exc)
{
// errore era già chiuso..
utils.lgError($"Errore in HIDE windows:{Environment.NewLine}{exc}");
}
}
}
}
private void btnMoreTOut_Click(object sender, EventArgs e)
{
tOutAutocheck = tOutAutocheck.AddMinutes(utils.CRI("autoRestartTimeoutMin"));
}
private void btnOpenAll_Click(object sender, EventArgs e)
{
// per iscurezza chiudo tutto
closeAllChild(true);
Thread.Sleep(1000);
// lettura conf file...
loadConfig();
// apertura
apriChild();
updateNumRunning();
updateStatus();
}
private void btnRestartAll_Click(object sender, EventArgs e)
{
// chiude tutto
closeAllChild(true);
apriChild();
updateNumRunning();
updateStatus();
}
private void btnStartSel_Click(object sender, EventArgs e)
{
// riapro child (SOLO SE non era già aperto...)
apriChildSel();
}
/// <summary>
/// verifica buttons attivi data selezione su gridview...
/// </summary>
private void checkButtons()
{
bool selected = (dgvManagedItems.SelectedRows.Count > 0);
btnClose.Enabled = selected;
}
private bool checkIstance(iobAdapt item, Process[] processList)
{
bool needRem;
// verifico se non sia già stato segnato x rimozione...)
if (item2rem.Find(x => x.pID == item.pID) != null)
{
needRem = true;
}
else
{
// verifico se esista il processo...
try
{
if (processList.Length > 0)
{
Process p = myGetProcByID(processList, 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>
/// Controllo periodico dei processi attivi
/// </summary>
private async Task checkProcessStatusAsync()
{
await _sync.WaitAsync();
if (!checkRunning)
{
// reset variabili appoggio
checkRunning = true;
// eseguo task!
await Task.Run(() => checkRunningchild()).ConfigureAwait(false);
updateStatus();
checkRunning = false;
}
else
{
utils.lgInfo($"Error: checkRunning: {checkRunning}");
}
_sync.Release();
}
/// <summary>
/// Verifica se i proc child siano ancora in RUN
/// </summary>
private void checkRunningchild()
{
IList<iobAdapt> allItems = (IList<iobAdapt>)ElencoIOB.List;
bool needRem = false;
// 2020.02.01 passato chiamata specifica x leggere in 1 sola volta TUTTO elenco processi (x nome)...
Process[] processList = Process.GetProcessesByName(TargetName);
// ciclo
Parallel.ForEach(allItems, item =>
{
needRem = checkIstance(item, processList);
}
);
// aggiorno datagrid!
dgvManagedItems.Invalidate();
}
/// <summary>
/// Controllo periodico dei processi DA RIATTIVARE
/// </summary>
private void checkWatchdog()
{
processAutoRestart();
// aggiorno datagrid!
dgvManagedItems.Invalidate();
}
private void chiudiChildSel()
{
int pid = -1;
// SOLO SE selezionato in dgv...
if (dgvManagedItems.SelectedRows.Count > 0)
{
foreach (DataGridViewRow riga in dgvManagedItems.SelectedRows)
{
// chiudo!
_ = int.TryParse(riga.Cells["pID"].Value.ToString(), out pid);
if (pid >= 0)
{
// provo a vedere SE ci sia il processo e di conseguenza lo chiudo...
try
{
Process p = Process.GetProcessById(pid);
// cerco e chiudo quelli che mi interessano...
p.CloseMainWindow();
}
catch
{
// errore era già chiuso..
}
// indico NON running su datasource
((iobAdapt)ElencoIOB[riga.Index]).isRunning = false;
}
}
}
updateNumRunning();
updateStatus();
}
private void chkAutoRestart_CheckedChanged(object sender, EventArgs e)
{
// se tolgo autorestart --> imposto NUOVA scadenza x forzare check
tOutAutocheck = DateTime.Now.AddMinutes(utils.CRI("autoRestartTimeoutMin"));
txtTOutAutoCheck.Visible = !chkAutoRestart.Checked;
btnMoreTOut.Visible = !chkAutoRestart.Checked;
// fa subito controllo riavvio...
processAutoRestart();
}
/// <summary>
/// Chiude tutti i child
/// </summary>
/// <param name="doReset">resetta elenco</param>
private void closeAllChild(bool doReset)
{
item2rem.Clear();
foreach (iobAdapt item in ElencoIOB.List)
{
item2rem.Add(item);
}
// processod a elenco noto
foreach (var item in item2rem)
{
if (item.isRunning)
{
try
{
Process p = Process.GetProcessById(item.pID);
p.CloseMainWindow();
p.WaitForExit(waitForExitMsec);
if (!p.HasExited)
{
utils.lgError($"Process not exited, now calling p.Kill()");
p.Kill();
}
// indico NON running su datasource
if (doReset)
{
ElencoIOB.Remove(item);
}
else
{
item.isRunning = false;
}
}
catch (Exception exc)
{
Logging.Instance.Error($"Errore in fase di chiusura processo (pid: {item.pID} ) da elenco {exc}");
}
}
}
if (item2rem.Count > 0)
{ // attendo 2*waitForExitMsec che i processi possano chiudersi gracefully...
Thread.Sleep(waitForExitMsec * 2);
forceKillByName(TargetName);
// ripeto seconda volta x sicurezza
Thread.Sleep(waitForExitMsec * 4);
forceKillByName(TargetName);
}
// verifico se resettare
if (doReset)
{
// resetto elenco!
ElencoIOB.Clear();
numProcAvviati = 0;
}
// resetto
item2rem.Clear();
numProcRunning = 0;
// update!
updateStatus();
}
/// <summary>
/// Chiude il PID selezionato
/// </summary>
/// <param name="Item">Chiude item richiesto</param>
private void closeSingleChild(iobAdapt item)
{
utils.lgInfo($"Chiusura processo | IOB: {item.CodIOB} | pid: {item.pID}");
// rimuovo item
ElencoIOB.Remove(item);
try
{
Process p = Process.GetProcessById(item.pID);
p.CloseMainWindow();
}
catch
{ }
updateNumRunning();
}
private void closeTimers()
{
MainTimer.Dispose();
forceCheckTimer.Dispose();
UI_Timer.Dispose();
}
private void dgvManagedItems_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
// seleziono riga...
int pid = -1;
if (e.RowIndex >= 0)
{
dgvManagedItems.Rows[e.RowIndex].Selected = true;
using (var riga = dgvManagedItems.Rows[e.RowIndex])
{
int.TryParse(riga.Cells["pID"].Value.ToString(), out pid);
if (pid >= 0)
{
// provo a vedere SE ci sia il processo e di conseguenza lo chiudo...
try
{
Process p = Process.GetProcessById(pid);
// cerco e chiudo quelli che mi interessano...
var windowsHandle = p.MainWindowHandle;
ShowWindowAsync(windowsHandle, SW_SHOWNORMAL);
}
catch
{
// errore era già chiuso..
}
}
}
}
}
private void dgvManagedItems_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (this.dgvManagedItems.Columns[e.ColumnIndex].Name == "iobOnline")
{
if (e.Value != null)
{
bool isOk = false;
bool.TryParse(e.Value.ToString(), out isOk);
e.CellStyle.BackColor = isOk ? Color.White : Color.Red;
}
}
else if (this.dgvManagedItems.Columns[e.ColumnIndex].Name == "lastPlcRead")
{
if (e.Value != null)
{
DateTime adesso = DateTime.Now;
DateTime lastRead = adesso.AddMinutes(-60);
DateTime.TryParse(e.Value.ToString(), out lastRead);
if (Math.Abs(adesso.Subtract(lastRead).TotalSeconds) > 180)
{
e.CellStyle.BackColor = Color.Red;
}
else if (Math.Abs(adesso.Subtract(lastRead).TotalSeconds) > 120)
{
e.CellStyle.BackColor = Color.OrangeRed;
}
else if (Math.Abs(adesso.Subtract(lastRead).TotalSeconds) > 60)
{
e.CellStyle.BackColor = Color.Yellow;
}
else if (Math.Abs(adesso.Subtract(lastRead).TotalSeconds) > 15)
{
e.CellStyle.BackColor = Color.YellowGreen;
}
else
{
e.CellStyle.BackColor = Color.White;
}
}
}
else if (this.dgvManagedItems.Columns[e.ColumnIndex].Name.StartsWith("queueElLen"))
{
if (e.Value != null)
{
int coda = 0;
int.TryParse(e.Value.ToString(), out coda);
e.CellStyle.ForeColor = (coda > 0) ? Color.Red : Color.Green;
}
}
else if (this.dgvManagedItems.Columns[e.ColumnIndex].Name == "isRunning")
{
if (e.Value != null)
{
bool isOk = false;
bool.TryParse(e.Value.ToString(), out isOk);
if (!isOk)
{
e.CellStyle.ForeColor = Color.Red;
DataGridViewCellStyle currstyle = dgvManagedItems[0, e.RowIndex].Style;
currstyle.ForeColor = Color.Red;
dgvManagedItems[1, e.RowIndex].Style = currstyle;
dgvManagedItems[2, e.RowIndex].Style = currstyle;
dgvManagedItems[3, e.RowIndex].Style = currstyle;
}
}
}
}
private void dgvManagedItems_SelectionChanged(object sender, EventArgs e)
{
checkButtons();
}
private void ElencoIOB_AddingNew(object sender, System.ComponentModel.AddingNewEventArgs e)
{
}
private void ElencoIOB_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
{
updateNumRunning();
}
private void forceCheckTimer_Tick(object sender, EventArgs e)
{
if (!checkRunning)
{
try
{
Task result = Task.Run(() => checkProcessStatusAsync().ConfigureAwait(false));
result.Wait();
}
catch (Exception exc)
{
Logging.Instance.Error($"forceCheckTimer_Tick {exc}");
}
}
checkWatchdog();
// riavvio i timer x sicurezza...
UI_Timer.Stop();
UI_Timer.Start();
MainTimer.Stop();
MainTimer.Start();
}
private void forceCloseALLToolStripMenuItem_Click(object sender, EventArgs e)
{
// per iscurezza chiudo tutto
closeAllChild(true);
Thread.Sleep(1000);
updateStatus();
}
/// <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)
{
p.Kill();
p.WaitForExit(waitForExitMsec);
}
if (!p.HasExited)
{
utils.lgError($"Process not Killed, 2nd try p.kill()");
p.Kill();
p.WaitForExit(waitForExitMsec * 2);
}
if (!p.HasExited)
{
utils.lgError($"Process not Killed, 3th try p.kill()");
p.Kill();
}
}
}
catch (Exception exc)
{
Logging.Instance.Error($"Errore in fase di kill processo da nome {exc}");
}
}
}
}
}
private void initControls()
{
// gestione eventi binding source
ElencoIOB.AddingNew += ElencoIOB_AddingNew;
ElencoIOB.ListChanged += ElencoIOB_ListChanged;
// collego tab a binding
dgvManagedItems.DataSource = ElencoIOB;
utils.lgInfo("Timer started");
if (utils.CRB("autoStartProc"))
{
apriChild();
utils.lgInfo("Start processi effettuato");
}
}
/// <summary>
/// Inizializzazione timers
/// </summary>
private void initTimers()
{
MainTimer.Interval = checkPeriod;
MainTimer.Start();
UI_Timer.Interval = uiPeriod;
UI_Timer.Start();
forceCheckTimer.Interval = checkPeriod * forceCheckPeriodMult;
forceCheckTimer.Start();
// avvio il task con apposita classe Steamware... da 00:30
int fullRestartHour = memLayer.ML.CRI("fullRestartHour");
int fullRestartMinute = memLayer.ML.CRI("fullRestartMinute");
int fullRestartIntervMin = memLayer.ML.CRI("fullRestartIntervMin");
TaskSched.IntervalInMinutes(fullRestartHour, fullRestartMinute, fullRestartIntervMin, () =>
{
// eseguo nel contesto di sincronizzazione
synchronizationContext.Post(new SendOrPostCallback(o =>
{
// effettuo reload conf e restart
reloadConfAndRestart();
}), "");
});
}
private void IOBManPanel_FormClosing(object sender, FormClosingEventArgs e)
{
closeAllChild(true);
Thread.Sleep(500);
closeAllChild(true);
closeTimers();
}
private void loadArgList()
{
// in primis cerco SE ESISTA il file json di configuraizone parametri avvio
string fileName = utils.CRS("ArgsConfFile");
string jsonFileName = $"{Application.StartupPath}{fileName}";
// verifico se esista il file richeisto
if (File.Exists(jsonFileName))
{
// leggo il file json
StreamReader reader = new StreamReader(jsonFileName);
string jsonData = reader.ReadToEnd();
if (!string.IsNullOrEmpty(jsonData))
{
ArgsList = JsonConvert.DeserializeObject<List<string>>(jsonData);
}
}
else
{
// se non lo trovassi --> uso la chaive in web.config e GENERO un nuovo file x prox avvio...
string ArgsString = utils.CRS("ArgsList");
utils.lgInfo($"Args found: {ArgsString}");
if (string.IsNullOrEmpty(ArgsString))
{
var rand = new Random();
// ne creo rand (5-15) di default...
for (int i = 0; i < rand.Next(5, 10); i++)
{
ArgsList.Add($"127.0.0.{i + 1}");
}
}
else
{
var elenco = ArgsString.Split(',');
foreach (var item in elenco)
{
ArgsList.Add(item);
}
}
// serializzo e salvo file!
string jsonData = JsonConvert.SerializeObject(ArgsList);
File.WriteAllText(jsonFileName, jsonData);
}
}
/// <summary>
/// Caricamento configurazione
/// </summary>
private void loadConfig()
{
ArgsList.Clear();
waitForExitMsec = utils.CRI("waitForExitMsec");
checkPeriod = utils.CRI("checkPeriod");
uiPeriod = utils.CRI("uiPeriod");
forceCheckPeriodMult = utils.CRI("forceCheckPeriodMult");
TargetExe = utils.CRS("targetExe");
TargetName = utils.CRS("appNameExt");
if (string.IsNullOrEmpty(TargetExe))
{
//TargetExe = string.Format(@"{0}\Resources\Test.bat", Application.StartupPath);
TargetExe = $@"{Application.StartupPath}\Resources\Test.bat";
}
utils.lgInfo($"Target exe: {TargetExe}");
// caricamento configurazione argomenti di avvio processi
loadArgList();
}
private void loadConfToolStripMenuItem_Click(object sender, EventArgs e)
{
// per iscurezza chiudo tutto
closeAllChild(true);
Thread.Sleep(1000);
// lettura conf file...
loadConfig();
// apertura
apriChild();
updateStatus();
}
/// <summary>
/// Effettua tutte le verifiche periodiche a timer...
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainTimer_Tick(object sender, EventArgs e)
{
if (!checkRunning)
{
try
{
//Task result = checkProcessStatusAsync();
//result.Wait();
Task result = Task.Run(() => checkProcessStatusAsync().ConfigureAwait(false));
result.Wait();
}
catch (Exception exc)
{
Logging.Instance.Error($"MainTimer_Tick {exc}");
}
}
}
/// <summary>
/// Chiama apertura + update status...
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void openALLToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void performBarAdvance()
{
synchronizationContext.Post(new SendOrPostCallback(o =>
{
tsProgBar.PerformStep();
if (tsProgBar.Value >= tsProgBar.Maximum)
{
tsProgBar.Value = 0;
}
tsProgBar.Invalidate();
}), "");
}
private void preInit()
{
utils.lgInfo("Starting App");
lblApp.Text = $"{ConfigurationManager.AppSettings.Get("appName")}";
lblVers.Text = $" v.{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version}";
// init prog bar
tsProgBar.Maximum = 100;
tsProgBar.Step = 4;
}
/// <summary>
/// Effettua processing autorestart
/// </summary>
private void processAutoRestart()
{
// verifico se ci siano processi (da ARGS LIST) NON running --> li riavvio!
Dictionary<int, iobAdapt> proc2restart = new Dictionary<int, iobAdapt>();
Dictionary<int, iobAdapt> proc2close = new Dictionary<int, iobAdapt>();
int indice = 0;
foreach (iobAdapt item in ElencoIOB.List)
{
// se NON E' running
if (!item.isRunning)
{
// segno da eliminare e riavviare
proc2restart.Add(indice, item);
utils.lgInfo($"Processo non in running | IOB: {item.CodIOB} | pid: {item.pID}");
}
// se NON comunica da troppo (ultima comunicazione è > 5 minuti fa...)
else if (!item.plcOk)
{
proc2close.Add(indice, item);
utils.lgInfo($"Processo non in PLC-Online | IOB: {item.CodIOB} | pid: {item.pID}");
}
indice++;
}
// SE abilitato autorestart...
if (chkAutoRestart.Checked)
{
var allProcess = proc2close.Concat(proc2restart).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.First().Value);
foreach (var item in allProcess)
{
ElencoIOB.Remove(item);
// chiudo!
closeSingleChild(item.Value);
}
foreach (var item in allProcess)
{
// riavvio!
startChildProc(item.Value.CodIOB, item.Key);
}
#if false
// in primis processo quelli che non comunicano e mi limito a chiuderli...
foreach (var item in proc2close)
{
ElencoIOB.Remove(item);
utils.lgInfo($"Chiusura processo non in PLC-Online | IOB: {item.Value.CodIOB} | pid: {item.Value.pID}");
// chiudo!
closeSingleChild(item.Value);
}
foreach (var item in proc2close)
{
// riavvio!
startChildProc(item.Value.CodIOB, item.Key);
}
// se ho da riavviare... elimino!
foreach (var dictVal in proc2restart)
{
ElencoIOB.Remove(dictVal.Value);
utils.lgInfo($"Chiusura processo non in running | IOB: {dictVal.Value.CodIOB} | pid: {dictVal.Value.pID}");
}
// li faccio ripartire!
foreach (var item in proc2restart)
{
startChildProc(item.Value.CodIOB, item.Key);
}
#endif
// update!
updateStatus();
}
else
{
// se autorestart scaduto e NON checked --> lo imposto
if (tOutAutocheck < DateTime.Now)
{
// lo riattivo
chkAutoRestart.Checked = true;
}
}
}
/// <summary>
/// Effettua chiusura completa + rilettura conf + riavvio
/// </summary>
private void reloadConfAndRestart()
{
utils.lgInfo("Call reloadConfAndRestart: start full reload");
// per sicurezza chiudo tutto
closeAllChild(true);
Thread.Sleep(1000);
updateStatus();
// rileggo conf
loadConfig();
Thread.Sleep(500);
// riapro
apriChild();
utils.lgInfo("Call reloadConfAndRestart: completed full reload");
}
private void reloadConfRestartToolStripMenuItem_Click(object sender, EventArgs e)
{
reloadConfAndRestart();
}
/// <summary>
/// Chiama Restart (close/start) + update status...
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void restartALLToolStripMenuItem_Click(object sender, EventArgs e)
{
// chiude tutto
closeAllChild(false);
apriChild();
updateStatus();
}
/// <summary>
/// Avvio di un child process da parametro ARG
/// </summary>
/// <param name="procArg"></param>
/// <param name="indice"></param>
private void startChildProc(string procArg, int indice = -1)
{
ProcessStartInfo psi = null;
// da testare x aprire chiudere risorsa...
psi = new ProcessStartInfo
{
FileName = TargetExe,
Arguments = $"{utils.CRS("BaseArg")}{procArg}",
WindowStyle = ProcessWindowStyle.Minimized
};
//childProc.StartInfo = psi;
Process p = Process.Start(psi);
// accodo nuovo IOB...
iobAdapt newIob = new iobAdapt();
DateTime adesso = DateTime.Now;
newIob.redisMan = new RedisIobCache("", procArg);
newIob.CodIOB = procArg;
newIob.startTime = adesso;
newIob.pID = p.Id;
newIob.isRunning = true;
// aggiungo a datasource, se indice -1 aggiungendo e basta, altrimenti alla posizione richiesta...
if (indice == -1)
{
ElencoIOB.Add(newIob);
}
else
{
ElencoIOB.Insert(indice, newIob);
}
utils.lgInfo($"Avviato child process per {procArg} | pid: {p.Id}");
}
private void txtTOutAutoCheck_TextChanged(object sender, EventArgs e)
{
}
private void UI_Timer_Tick(object sender, EventArgs e)
{
Task result = updateProgBarAsync();
result.Wait();
}
private void updateIOBWINToolStripMenuItem_Click(object sender, EventArgs e)
{
// chiude tutte
closeAllChild(true);
Thread.Sleep(1000);
updateStatus();
// apre solo 1 con conf "fake" x condurre update...
apriOneUpdate();
}
private void updateModeToolStripMenuItem_Click(object sender, EventArgs e)
{
// chiude tutte
closeAllChild(true);
Thread.Sleep(1000);
updateStatus();
// apre solo 1 con conf "fake" x condurre update...
apriOneUpdate();
}
private void updateNumRunning()
{
// ricalcolo running...
numProcRunning = 0;
// ciclo su row selezionate
foreach (DataGridViewRow riga in dgvManagedItems.Rows)
{
// verifico che sia già chiuso...
if (((iobAdapt)ElencoIOB[riga.Index]).isRunning)
{
numProcRunning++;
}
}
}
private async Task updateProgBarAsync()
{
await Task.Run(() => performBarAdvance()).ConfigureAwait(false);
}
private void updateStatus()
{
synchronizationContext.Post(new SendOrPostCallback(o =>
{
// aggiorno SOLO SE sono variati...
if (lastNumProcAvviati != numProcAvviati || lastNumProcRunning != numProcRunning)
{
// aggiorno labels
tsslNumProc.Text = $"Configurati {ArgsList.Count} processi | Avviati: {numProcAvviati} | Attivi: {numProcRunning}";
lastNumProcAvviati = numProcAvviati;
lastNumProcRunning = numProcRunning;
}
bool hlRestart = false;
// colore da num proc...
if (numProcRunning == ArgsList.Count)
{
tsslNumProc.ForeColor = Color.Green;
}
else if (numProcAvviati < ArgsList.Count)
{
tsslNumProc.ForeColor = Color.DarkRed;
hlRestart = true;
}
else
{
tsslNumProc.ForeColor = Color.OrangeRed;
hlRestart = true;
}
// se NON checked aggiorno contatore...
if (!chkAutoRestart.Checked)
{
txtTOutAutoCheck.Text = $"{tOutAutocheck.Subtract(DateTime.Now).TotalSeconds:N0}";
}
// se è variato...
if (hlRestart != lastHlRestart)
{
tOutAutocheck = DateTime.Now.AddMinutes(utils.CRI("autoRestartTimeoutMin"));
lastHlRestart = hlRestart;
// fix autorestart...
if (hlRestart)
{
chkAutoRestart.ForeColor = System.Drawing.Color.Red;
chkAutoRestart.Text = "Auto Restart!!!";
}
else
{
chkAutoRestart.ForeColor = DefaultForeColor;
chkAutoRestart.Text = "Auto Restart";
}
txtTOutAutoCheck.Visible = !chkAutoRestart.Checked;
btnMoreTOut.Visible = !chkAutoRestart.Checked;
}
}), "");
}
#endregion Private Methods
#region Public Methods
/// <summary>
/// Cerca nell'elenco il processo corrente
/// </summary>
/// <param name="processlist"></param>
/// <param name="id"></param>
/// <returns></returns>
public static Process myGetProcByID(Process[] processlist, int id)
{
return processlist.FirstOrDefault(pr => pr.Id == id);
}
#endregion Public Methods
}
}