Files
egwcapp/EgwControlCenter.App/BlazorForm.cs
T
2025-03-25 16:01:51 +01:00

542 lines
18 KiB
C#

using EgwControlCenter.Core;
using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Win32;
using NLog;
using System.Diagnostics;
using System.IO.Compression;
using System.Reflection;
namespace EgwControlCenter.App
{
public partial class BlazorForm : Form
{
#region Public Constructors
public BlazorForm()
{
InitializeComponent();
CheckUnzip();
ServiceInit();
CleanOldTrayIcons();
InitBlazorView();
StartTimer();
StartLastAsync();
}
#endregion Public Constructors
#region Private Fields
private static bool forceClose = false;
/// <summary>
/// Classe logger
/// </summary>
private static Logger Log = LogManager.GetCurrentClassLogger();
private Size minSize = new Size(676, 409);
/// <summary>
/// Periodo di blocco invio nuove notifiche se ci sono + update...
/// </summary>
private int VetoNewNotifySec = 15;
#endregion Private Fields
#region Private Properties
private static AppControlService ACService { get; set; } = null!;
private string AppName => CurrAssembly.Name ?? "EgalWare ACC";
private System.Reflection.AssemblyName CurrAssembly { get; set; } = new System.Reflection.AssemblyName();
/// <summary>
/// Ultima visualizzazione messaggio...
/// </summary>
private DateTime lastMsqShown { get; set; } = DateTime.MinValue;
private Size lastSize { get; set; } = new Size(660, 480);
#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.Hidden;
#if DEBUG
startInfo.WindowStyle = ProcessWindowStyle.Normal;
#endif
startInfo.CreateNoWindow = true;
startInfo.FileName = extPath;
ACService.SendRebooted(true);
Process.Start(startInfo);
}
else
{
// NON eseguo...
forceClose = true;
Application.Restart();
Environment.Exit(0);
}
}
/// <summary>
/// Riavvio il timer...
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ACService_EA_ConfigUpdated()
{
timerCheck.Stop();
timerTask.Stop();
StartTimer();
}
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);
}
/// <summary>
/// Verifica se ci siano update da mostrare come notifica in tray
/// </summary>
/// <exception cref="NotImplementedException"></exception>
private void ACService_EA_StatusUpdated()
{
// notifica ballontip se ho aggiornamenti...
DateTime adesso = DateTime.Now;
// mostro se non ne ho ricevuti altri da almeno 10 sec...
if (WindowState != FormWindowState.Normal && adesso > lastMsqShown.AddSeconds(VetoNewNotifySec))
{
// salvo che ho mostrato msg
lastMsqShown = adesso;
notifyIcon1.BalloonTipTitle = "EgalWare's App Control Center";
notifyIcon1.BalloonTipText = "Update found!";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Warning;
notifyIcon1.BalloonTipClicked += NotifyIcon1_BalloonTipClicked;
// mostro notifica... SE abilitata
if (ACService.EnableNotify)
{
notifyIcon1.ShowBalloonTip(200);
}
}
}
private void BlazorForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (forceClose)
{
ACService.EA_StatusUpdated -= ACService_EA_StatusUpdated;
ACService.EA_ConfigUpdated -= ACService_EA_ConfigUpdated;
ACService.EA_RestartRequested -= ACService_EA_RestartRequested;
ACService.EA_ReloadRequested -= ACService_EA_ReloadRequested;
timerCheck.Stop();
timerCheck.Dispose();
timerTask.Stop();
timerTask.Dispose();
}
else
{
e.Cancel = true;
// reimposto size...
Size = lastSize;
SetPosition();
SendToTray();
}
}
/// <summary>
/// Evento completamento caricamento app
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void BlazorForm_Load(object sender, EventArgs e)
{
SetPosition();
// aspetto e poi mando a tray...
await Task.Delay(500);
SendToTray();
// eseguo task preliminari tipo invio reset effettuato + elenco conf...
await Task.Delay(100);
await ACService.SendRebootedAsync(false);
// ora invio info licenza (SE disponibili)
await Task.Delay(100);
await ACService.SendLicInfo();
// infine invio info conf (x editing successivo)
await Task.Delay(100);
await ACService.SendConfTarget();
// invio stats avvio
await Task.Delay(100);
await ACService.SendStats();
}
/// <summary>
/// Evento post resize
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BlazorForm_Resize(object sender, EventArgs e)
{
CheckFormVisibility();
}
/// <summary>
/// Verifica stato windows (minimized/normal) e visibilità con tray...
/// </summary>
private void CheckFormVisibility()
{
// controllo cosa devo mostrare...
if (WindowState == FormWindowState.Minimized)
{
SendToTray();
}
notifyIcon1.Visible = true;
}
private void CleanOldTrayIcons()
{
Assembly assembly = Assembly.GetExecutingAssembly();
string startDir = Path.GetDirectoryName(assembly.Location)!;
string appPath = assembly.ManifestModule.FullyQualifiedName.Replace("dll", "exe");
RegistryKey? key = Registry.CurrentUser.OpenSubKey(@"Control Panel\NotifyIconSettings", true);
if (key != null)
{
foreach (string subKeyName in key.GetSubKeyNames())
{
RegistryKey? subKey = key.OpenSubKey(subKeyName);
if (subKey != null)
{
string executablePath = subKey.GetValue("ExecutablePath") as string ?? "";
// cerco solo le chiavi di EgwControlCenter.App.exe
if (!string.IsNullOrEmpty(executablePath))
{
if (executablePath.EndsWith("EgwControlCenter.App.exe") || executablePath.Contains("EgwControlCenter"))
{
// se il path NON E' quello da cui sta girando il software -->
// elimino chiave registro...
if (!executablePath.Equals(appPath))
{
key.DeleteSubKey(subKeyName);
}
}
}
}
}
}
else
{
Console.WriteLine("NotifyIconSettings key not found.");
}
}
/// <summary>
/// crea menù tray x applicazione
/// </summary>
private void CreateTrayMenu()
{
// Fix testi menù tray...
trayMenu.Items.Clear();
// aggiungo azioni con tasto DX
trayMenu.Items.Add("Show EgalWare ACC");
trayMenu.Items.Add("Reload Config");
trayMenu.Items.Add("Restart And update");
trayMenu.Items.Add("Close EgalWare ACC");
}
private void DoDisplay()
{
Show();
WindowState = FormWindowState.Normal;
}
/// <summary>
/// Chiamata controllo status update
/// </summary>
private async Task ForceReload()
{
await ACService.DoFullCheckAsync(true);
await ACService.DoTaskCheckAsync(true);
}
private void InitBlazorView()
{
Stopwatch sw = new Stopwatch();
sw.Start();
#if false
CurrAssembly = Assembly.GetExecutingAssembly().GetName();
Log.Trace($"EgalWare's AppControlCenter Init, v.{CurrAssembly.Version}");
#endif
// sistemo grafica TRAY ICON
SetupTrayIcon();
CreateTrayMenu();
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);
Log.Trace($"Add AppControlService | {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 NotifyIcon1_BalloonTipClicked(object? sender, EventArgs e)
{
DoDisplay();
}
/// <summary>
/// doppio click su tray icon
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void notifyIcon1_DoubleClick(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
DoDisplay();
}
else
{
SendToTray();
}
}
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right)
{
try
{
if (WindowState == FormWindowState.Minimized)
{
DoDisplay();
}
else
{
SendToTray();
}
}
catch (Exception exc)
{
Log.Error($"Errore in notifyIcon1_MouseClick{Environment.NewLine}{exc}");
}
}
}
/// <summary>
/// Gestisce "andata nel tray" della form
/// </summary>
private void SendToTray()
{
// notifica ballontip se ho aggiornamenti...
DateTime adesso = DateTime.Now;
if (adesso > lastMsqShown.AddSeconds(VetoNewNotifySec))
{
// salvo che ho mostrato msg
lastMsqShown = adesso;
notifyIcon1.BalloonTipTitle = AppName;
notifyIcon1.BalloonTipText = $"{AppName} running on tray";
notifyIcon1.BalloonTipIcon = ToolTipIcon.Info;
notifyIcon1.BalloonTipClicked += NotifyIcon1_BalloonTipClicked;
notifyIcon1.Visible = true;
// mostro notifica... SE abilitata
if (ACService != null && ACService.EnableNotify)
{
notifyIcon1.ShowBalloonTip(100);
}
}
WindowState = FormWindowState.Minimized;
Hide();
}
/// <summary>
/// Esegue eventuale unzip file risorse www
/// </summary>
private void CheckUnzip()
{
CurrAssembly = Assembly.GetExecutingAssembly().GetName();
Log.Info($"EgalWare's AppControlCenter Init, v.{CurrAssembly.Version}");
string exePath = Assembly.GetExecutingAssembly().Location;
string appDir = Path.GetDirectoryName(exePath) ?? "";
if (!string.IsNullOrEmpty(appDir))
{
string srcZip = Path.Combine(appDir, "wwwroot.zip");
if ((File.Exists(srcZip)))
{
Log.Info($"Zip file found");
// decomprimo
ZipFile.ExtractToDirectory(srcZip, appDir, true);
Log.Info($"Zip file extracted");
// elimino zip
File.Delete(srcZip);
Log.Info($"Zip file removed");
}
}
}
private void ServiceInit()
{
//init preliminare servizio controllo
ACService = new AppControlService();
ACService.EA_StatusUpdated += ACService_EA_StatusUpdated;
ACService.EA_ConfigUpdated += ACService_EA_ConfigUpdated;
ACService.EA_RestartRequested += ACService_EA_RestartRequested;
ACService.EA_ReloadRequested += ACService_EA_ReloadRequested;
}
private void SetPosition()
{
// posiziono in basso a sx...
Rectangle workArea = Screen.GetWorkingArea(this);
this.Location = new Point(workArea.Right - lastSize.Width, workArea.Bottom - lastSize.Height);
}
private void SetupTrayIcon()
{
// fix icon!
notifyIcon1.Text = $"EgalWare's AppControlCenter | {CurrAssembly.Version}";
}
/// <summary>
/// init ultime attività async
/// </summary>
private void StartLastAsync()
{
var pUpd = Task.Run(async () =>
{
await ForceReload();
});
pUpd.Wait();
}
private void StartTimer()
{
// timer controlli da conf
timerCheck.Interval = (ACService.RefreshPeriod * 1000);
// timer statistiche a 30 min fisso x ora
#if DEBUG
timerStats.Interval = 1000 * 60 * 5;
#else
timerStats.Interval = 1000 * 60 * 30;
#endif
// avvio timer
timerCheck.Start();
timerTask.Start();
timerStats.Start();
}
/// <summary>
/// Esecuzione task di verifica stato app
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void timerCheck_Tick(object sender, EventArgs e)
{
// fermo task...
timerCheck.Stop();
// esegue controllo locale ed eventualmente remoto se scaduto...
await ACService.DoFullCheckAsync(false);
// riavvio task x evitare sovrapposizioni in debug
timerCheck.Start();
}
/// <summary>
/// Gestione timer statistiche
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void timerStats_Tick(object sender, EventArgs e)
{
// fermo task...
timerStats.Stop();
// esegue controllo task
await ACService.SendStats();
await ACService.SendLicInfo();
await ACService.SendConfTarget();
// riavvio task x evitare sovrapposizioni in debug
timerStats.Start();
}
/// <summary>
/// Timer task (1 sec base)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void timerTask_Tick(object sender, EventArgs e)
{
// fermo task...
timerTask.Stop();
// esegue controllo task
await ACService.DoTaskCheckAsync(false);
// riavvio task x evitare sovrapposizioni in debug
timerTask.Start();
}
/// <summary>
/// click su menù contestuale in tray
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void trayMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
if (e != null && e.ClickedItem != null && !string.IsNullOrEmpty(e.ClickedItem.Text))
{
if (e.ClickedItem.Text.StartsWith("Close"))
{
// chiudo!
forceClose = true;
Close();
}
else if (e.ClickedItem.Text.StartsWith("Restart"))
{
DoRestart(true);
}
else if (e.ClickedItem.Text.StartsWith("Reload"))
{
DoRestart(false);
}
else if (e.ClickedItem.Text.StartsWith("Show"))
{
Show();
WindowState = FormWindowState.Normal;
}
}
}
#endregion Private Methods
}
}