Files
mapo-iob-man/IOB-MAN/BlazorForm.cs
T
2025-07-11 17:49:34 +02:00

377 lines
12 KiB
C#

using IOB_MAN.Core.Services;
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;
using NLog;
using System.Diagnostics;
using System.Reflection;
namespace IOB_MAN
{
public partial class BlazorForm : Form
{
#region Public Constructors
public BlazorForm()
{
InitializeComponent();
ServiceInit();
ConfInit();
InitBlazorView();
StartTimer();
CheckMemory();
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Force restart application, with delay
/// </summary>
public static void RestartApplication(bool force)
{
if (force)
{
Log.Info($"Chiamata restart application forzato");
}
else
{
Log.Info($"Chiamata restart application x superamento soglia GC consecutivi");
}
string exePath = Application.ExecutablePath;
// fermo tutti i sw controllati...
ACService.DoCloseAll(false);
Log.Info($"Completata chiusura processi x restart");
// Use cmd.exe to delay start until current app exits
int restartDelay = 5;
ProcessStartInfo psi = new ProcessStartInfo("cmd.exe", $"/C timeout /t {restartDelay} & start \"\" \"{exePath}\"")
{
CreateNoWindow = true,
UseShellExecute = false
};
Process.Start(psi);
Log.Info($"Avviato task di riavvio post delay {restartDelay}sec");
// Now safely exit the current instance
Application.Exit();
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Dataora prossima scadenza riavvio automatico
/// </summary>
protected DateTime tOutAutocheck = DateTime.Now;
#endregion Protected Fields
#region Private Fields
/// <summary>
/// Classe logger
/// </summary>
private static Logger Log = LogManager.GetCurrentClassLogger();
private int currSeqGC = 0;
/// <summary>
/// Memoria dotNet allocata
/// </summary>
private long dotNetMemUsed = 0;
private DateTime LastForcedGC = DateTime.Now;
private int maxConsGC = 5;
/// <summary>
/// Max memoria consumabile (std 128Mb)
/// </summary>
private double maxMemoryLimitMb = 128.0;
/// <summary>
/// Memoria totale processo
/// </summary>
private long totalMemUsed = 0;
#endregion Private Fields
#region Private Properties
private static AppControlService ACService { get; set; } = null!;
private static FluxLogManService FLMService { get; set; } = null!;
private double dotNetMemUsedMb
{
get => dotNetMemUsed / 1024.0 / 1024.0;
}
private Size lastSize { get; set; } = new Size(1200, 700);
private double totalMemUsedMb
{
get => totalMemUsed / 1024.0 / 1024.0;
}
#endregion Private Properties
#region Private Methods
/// <summary>
/// Esecuzione del processo di restart
/// </summary>
private static void DoRestart(bool fullRestart)
{
// full restart usa sw esterno, altrimenti solo app che riparte SENZA check update esterno
if (fullRestart)
{
// uso restarter esterno...
Assembly assembly = Assembly.GetExecutingAssembly();
string startDir = Path.GetDirectoryName(assembly.Location)!;
string extPath = Path.Combine(startDir, "libs", "EgwAccRestarter.exe");
// uso processstartInfo x nascondere finestra
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.WindowStyle = ProcessWindowStyle.Normal;
startInfo.CreateNoWindow = true;
startInfo.FileName = extPath;
Process.Start(startInfo);
}
else
{
Application.Restart();
Environment.Exit(0);
}
}
/// <summary>
/// Riavvio il timer...
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ACService_EA_ConfigUpdated()
{
timerUI.Stop();
timerTask.Stop();
tOutAutocheck = ACService.VetoAutoCheck;
StartTimer();
}
private void ACService_EA_RebootRequested()
{
Log.Info("---------------------------------------");
Log.Info("Starting Reboot Request");
Log.Info("---------------------------------------");
timerUI.Stop();
timerUI.Dispose();
timerTask.Stop();
timerTask.Dispose();
ACService.DoCloseAll(false);
RestartApplication(true);
}
private void ACService_EA_ReloadRequested()
{
// effettua chiamata reload
DoRestart(false);
}
/// <summary>
/// Gestione evento restart applicazione
/// </summary>
private void ACService_EA_RestartRequested()
{
// effettua chiamata restart
DoRestart(true);
}
private void BlazorForm_FormClosing(object sender, FormClosingEventArgs e)
{
ACService.EA_ConfigUpdated -= ACService_EA_ConfigUpdated;
ACService.EA_RestartRequested -= ACService_EA_RestartRequested;
ACService.EA_ReloadRequested -= ACService_EA_ReloadRequested;
ACService.EA_RebootRequested -= ACService_EA_RebootRequested;
FLMService.EA_FluxLogReq -= FLMService_EA_FluxLogReq;
timerUI.Stop();
timerUI.Dispose();
timerTask.Stop();
timerTask.Dispose();
ACService.DoCloseAll(false);
}
/// <summary>
/// Evento completamento caricamento app
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BlazorForm_Load(object sender, EventArgs e)
{
SetPosition();
}
/// <summary>
/// effettua controllo memoria + log
/// se occupa più di maxMemoryLimitMb --> chiama GC
/// </summary>
private void CheckMemory()
{
dotNetMemUsed = GC.GetTotalMemory(false); // Pass 'true' to force a garbage collection first
Process currentProcess = Process.GetCurrentProcess();
totalMemUsed = currentProcess.PrivateMemorySize64;
Log.Info($"Memory Usage | {dotNetMemUsedMb:F2} / {totalMemUsedMb:F2} MB | Managed / Total");
if (dotNetMemUsedMb > maxMemoryLimitMb / 2 || totalMemUsedMb > maxMemoryLimitMb)
{
// chiamo GC forzatamente
currSeqGC++;
Log.Info($"Chiamato forzatamente GC.Collect per superamento limite memoria | count: {currSeqGC}");
GC.Collect();
// registro forced GC
LastForcedGC = DateTime.Now;
if (currSeqGC > maxConsGC)
{
Log.Info("---------------------------------------");
Log.Info($"Superato limite GC consecutivi | count: {currSeqGC}");
RestartApplication(false);
}
}
else if (DateTime.Now.Subtract(LastForcedGC).TotalHours > 1)
{
// chiamo GC forzatamente
Log.Info($"Chiamato forzatamente GC.Collect per scadenza periodo");
GC.Collect();
// registro forced GC
LastForcedGC = DateTime.Now;
}
else
{
if (currSeqGC > 0)
{
currSeqGC--;
Log.Info($"Riduzione contatore GC consecutivi | count: {currSeqGC}");
}
}
}
/// <summary>
/// Init conf accessorie
/// </summary>
private void ConfInit()
{
// recupero limite memoria prima del GC
maxMemoryLimitMb = ACService.MaxMemGc;
}
/// <summary>
/// Richiesta apertura nuova form x editing FluxLog: la implemento leggendo il codIOB e lo passo al controllo...
/// </summary>
/// <param name="codIOB"></param>
private void FLMService_EA_FluxLogReq(string codIOB)
{
// chiamo nuova form con parametro x CodIOB richiesto
FluxLogData FldForm = new FluxLogData(FLMService, codIOB);
FldForm.Show();
}
private void InitBlazorView()
{
Stopwatch sw = new Stopwatch();
sw.Start();
try
{
Log.Trace($"TrayMenu OK | {sw.ElapsedMilliseconds}ms");
var services = new ServiceCollection();
Log.Trace($"Add ServiceCollection | {sw.ElapsedMilliseconds}ms");
services.AddWindowsFormsBlazorWebView();
Log.Trace($"Add AddWindowsFormsBlazorWebView | {sw.ElapsedMilliseconds}ms");
services.AddSingleton<AppControlService>(ACService);
services.AddSingleton<FluxLogManService>(FLMService);
Log.Trace($"Add Singleton Services | {sw.ElapsedMilliseconds}ms");
blazorWebView1.HostPage = "wwwroot\\index.html";
blazorWebView1.Services = services.BuildServiceProvider();
blazorWebView1.RootComponents.Add<MainBlazor>("#app");
Log.Trace($"Add MainBlazor | {sw.ElapsedMilliseconds}ms");
}
catch (Exception exc)
{
Log.Error($"Exception during setartup{Environment.NewLine}{exc}");
}
}
private void ServiceInit()
{
//init preliminare servizio controllo
ACService = new AppControlService(true);
FLMService = new FluxLogManService();
ACService.EA_ConfigUpdated += ACService_EA_ConfigUpdated;
ACService.EA_RestartRequested += ACService_EA_RestartRequested;
ACService.EA_ReloadRequested += ACService_EA_ReloadRequested;
ACService.EA_RebootRequested += ACService_EA_RebootRequested;
FLMService.EA_FluxLogReq += FLMService_EA_FluxLogReq;
}
private void SetPosition()
{
// posiziono in basso a sx...
Rectangle workArea = Screen.GetWorkingArea(this);
this.Location = new Point((workArea.Right - lastSize.Width) / 2, (workArea.Bottom - lastSize.Height) / 2);
}
private void StartTimer()
{
// timer controlli da conf
timerUI.Interval = (ACService.RefreshPeriod);
timerTask.Interval = (ACService.CheckRestartPeriod);
timerMemCheck.Interval = (ACService.CheckMemoryPeriod);
// avvio timers
timerUI.Start();
Thread.Sleep(50);
timerTask.Start();
Thread.Sleep(50);
timerMemCheck.Start();
}
/// <summary>
/// Evento timer memory check periodico
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timerMemCheck_Tick(object sender, EventArgs e)
{
CheckMemory();
}
/// <summary>
/// Timer task x eventuale riavvio processi fermi SE abilitato...
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void timerTask_Tick(object sender, EventArgs e)
{
// fermo task...
timerTask.Stop();
// esegue controllo task x eventuale autorestart
ACService.DoAutoRestart(false);
// riavvio task x evitare sovrapposizioni in debug
timerTask.Start();
}
/// <summary>
/// Esecuzione task di verifica stato app
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void timerUI_Tick(object sender, EventArgs e)
{
// fermo task...
timerUI.Stop();
await ACService.DoScan();
// riavvio task x evitare sovrapposizioni in debug
timerUI.Start();
}
#endregion Private Methods
}
}