COmpletata fase update applicativi

This commit is contained in:
Samuele Locatelli
2024-12-27 12:23:48 +01:00
parent 017acd727c
commit d3d491d64b
8 changed files with 577 additions and 76 deletions
@@ -18,6 +18,7 @@
<i class="fa-solid fa-spinner fa-spin fs-4 text-success"></i> <span class="small px-1">updating</span>
</div>
}
<ProgressDisplay RefreshInterval="100" Title="@UpdateMsg" MaxVal="@maxVal" CurrVal="@currVal" NextVal="@nextVal" ExpTimeMSec="@expTimeMSec" DisplaySize="ProgressDisplay.ModalSize.Medium" ModalCss="card alert-primary" SlowLimit="0.4"></ProgressDisplay>
</div>
<div class="p-0 d-flex small">
<div class="px-1 input-group input-group-sm">
@@ -1,6 +1,7 @@
using EgwControlCenter.Core;
using EgwControlCenter.Core.DTO;
using Microsoft.AspNetCore.Components;
using System.Diagnostics;
namespace EgwControlCenter.App.Components.Compo
{
@@ -36,6 +37,7 @@ namespace EgwControlCenter.App.Components.Compo
set
{
showOnlyUpdate = value;
currPage = 1;
ForceReload();
}
}
@@ -63,25 +65,69 @@ namespace EgwControlCenter.App.Components.Compo
{
case CoreEnum.AppType.None:
break;
case CoreEnum.AppType.Cli:
break;
case CoreEnum.AppType.Machine:
break;
case CoreEnum.AppType.WebApp:
break;
case CoreEnum.AppType.WinApp:
// esegue update delle app Iob-*
await ACService.DoUpdateIobWin(ReqApp);
Stopwatch sw = new Stopwatch();
sw.Start();
UpdateMsg = "Backup Config";
currVal = 0;
nextVal = 60;
await InvokeAsync(StateHasChanged);
await ACService.IobWinUpdateStep(ReqApp, 1);
currStats.RecordExeData("Step01_Backup", sw.Elapsed);
sw.Restart();
UpdateMsg = "Download update";
currVal = 60;
nextVal = 90;
await InvokeAsync(StateHasChanged);
await ACService.IobWinUpdateStep(ReqApp, 2);
currStats.RecordExeData("Step02_Download", sw.Elapsed);
sw.Restart();
UpdateMsg = "Unzip software";
currVal = 90;
nextVal = 95;
await InvokeAsync(StateHasChanged);
await ACService.IobWinUpdateStep(ReqApp, 3);
currStats.RecordExeData("Step03_UnZip", sw.Elapsed);
sw.Restart();
UpdateMsg = "Config Restore";
currVal = 95;
nextVal = 100;
await InvokeAsync(StateHasChanged);
await ACService.IobWinUpdateStep(ReqApp, 4);
currStats.RecordExeData("Step04_Restore", sw.Elapsed);
currStats.SaveToDisk();
UpdateMsg = "Completed!";
currVal = 100;
await InvokeAsync(StateHasChanged);
break;
default:
break;
}
isUpdating = false;
await InvokeAsync(StateHasChanged);
await Task.Delay(50);
// check finale
await ACService.DoFullCheckAsync(true);
}
/// <summary>
/// Oggetto gestione statistiche
/// </summary>
private TaskRunStats currStats { get; set; } = new TaskRunStats();
protected async Task ForceCheck()
{
@@ -92,6 +138,7 @@ namespace EgwControlCenter.App.Components.Compo
{
ACService.EA_StatusUpdated += ACService_EA_StatusUpdated;
ACService.EA_RemoteCalling += ACService_EA_RemoteCalling;
currStats = new TaskRunStats(ACService.DataDir, "Stats.json");
}
protected override void OnParametersSet()
@@ -119,6 +166,16 @@ namespace EgwControlCenter.App.Components.Compo
#endregion Protected Methods
#region Private Fields
private int currVal = 100;
private int expTimeMSec = 6000;
private int maxVal = 100;
private int nextVal = 100;
private string UpdateMsg = "Updating...";
#endregion Private Fields
#region Private Properties
private int currPage { get; set; } = 1;
@@ -5,7 +5,7 @@
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
<Version>1.1.2412.2418</Version>
<Version>1.1.2412.2712</Version>
<Configurations>Debug;Release;DEBUG_Local</Configurations>
</PropertyGroup>
<ItemGroup>
@@ -4,8 +4,8 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<ApplicationRevision>2418</ApplicationRevision>
<ApplicationVersion>1.1.2412.2418</ApplicationVersion>
<ApplicationRevision>2712</ApplicationRevision>
<ApplicationVersion>1.1.2412.2712</ApplicationVersion>
<BootstrapperEnabled>True</BootstrapperEnabled>
<Configuration>Release</Configuration>
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
+197 -70
View File
@@ -146,6 +146,11 @@ namespace EgwControlCenter.Core
}
}
/// <summary>
/// Dir applicazione
/// </summary>
public string DataDir { get; set; } = "";
public List<VersStatusDTO> ListAppStatus
{
get => CurrCheck.ListAppStatus;
@@ -301,79 +306,35 @@ namespace EgwControlCenter.Core
}
/// <summary>
/// metodo update specifico x app IobWin
/// Metodo update specifico x app IobWin a step
/// </summary>
/// <param name="reqApp"></param>
/// <param name="step">Step richiesto: 1=backup conf, 2=download, 3=unzip, $=fix conf e close</param>
/// <returns></returns>
public async Task DoUpdateIobWin(VersStatusDTO reqApp)
public async Task IobWinUpdateStep(VersStatusDTO reqApp, int step)
{
// controllo di avere un file di riferimento...
string appDir = Path.GetDirectoryName(reqApp.LocalPath) ?? "";
if (!string.IsNullOrEmpty(appDir))
// eseguo step secondo richiesta...
switch (step)
{
// step 0: inserisce i file semaforo di segnalazione update in corso
using (FileStream fs = File.Create(updFilePath))
{
// File is created and access is released when the using block ends
}
case 1:
await IobWinDoBackup(reqApp);
break;
// step 1: backup configurazioni partendo da path applicazione...
string srcDir = Path.Combine(appDir, "DATA", "CONF");
string destDir = Path.Combine(backupDir, "Conf", reqApp.CodApp, "DATA", "CONF");
// se MAN uso folder "accorciata"
if (reqApp.CodApp == "IOB-MAN")
{
srcDir = Path.Combine(appDir, "CONF");
destDir = Path.Combine(backupDir, "Conf", reqApp.CodApp, "CONF");
}
CopyDirectory(srcDir, destDir);
case 2:
await IobWinDownload(reqApp);
break;
// step 2: kill processi
ForceKillByName(reqApp.CodApp);
case 3:
await IobWinUnzip(reqApp);
break;
// step 3: backup + zip intera folder applicativo
string tempZip = Path.Combine(tempDir, "FULL", reqApp.CodApp);
if (Directory.Exists(tempZip))
{
Directory.Delete(tempZip, true);
}
Directory.CreateDirectory(tempZip);
CopyDirectory(appDir, tempZip);
string zipPath = Path.Combine(backupDir, "Archive", reqApp.CodApp, $"{DateTime.Now:yyyyMMdd}_{DateTime.Now:HHmmss}.zip");
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
else
{
string zipDir = Path.GetDirectoryName(zipPath) ?? "";
if (!string.IsNullOrEmpty(zipDir))
{
if (!Directory.Exists(zipDir))
{
Directory.CreateDirectory(zipDir);
}
}
}
await Task.Run(() =>
{
ZipFile.CreateFromDirectory(tempZip, zipPath);
});
// FixMe - todo: separare in 3 step a questo punto : primo backup, poi download e infine install e mostrare update in pagina
// step 4: download
// step 5: unzip + overwrite
//// step 6: restore conf
//CopyDirectory(destDir, srcDir);
case 4:
await IobWinRestoreConf(reqApp);
break;
default:
break;
}
// step 7: rimozione file lock semaforo
File.Delete(updFilePath);
await Task.Delay(10);
}
public void ResetConf()
@@ -406,6 +367,14 @@ namespace EgwControlCenter.Core
#endregion Public Methods
#region Protected Fields
protected UpdateMan updateMan = new UpdateMan();
protected UpdateMan updateManAuth = new UpdateMan("SWDownloader", "viaD@nte16");
#endregion Protected Fields
#region Protected Properties
protected SubLicManager SubLicManager { get; set; } = new SubLicManager();
@@ -456,11 +425,6 @@ namespace EgwControlCenter.Core
/// </summary>
private string backupDir = @"C:\Steamware\backup";
/// <summary>
/// Directory temp di appoggio
/// </summary>
private string tempDir = @"C:\Steamware\temp";
/// <summary>
/// DataOra ultimo controllo effettuato
/// </summary>
@@ -476,6 +440,11 @@ namespace EgwControlCenter.Core
/// </summary>
private int refPMin = 1;
/// <summary>
/// Directory temp di appoggio
/// </summary>
private string tempDir = @"C:\Steamware\temp";
/// <summary>
/// File segnaposto x lock fasi di update
/// </summary>
@@ -506,12 +475,30 @@ namespace EgwControlCenter.Core
private ReleaseChecker CurrCheck { get; set; } = null!;
private string DataDir { get; set; } = "";
#endregion Private Properties
#region Private Methods
/// <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);
}
}
/// <summary>
/// Effettua un force kill dato nome processo
/// </summary>
@@ -556,6 +543,146 @@ namespace EgwControlCenter.Core
}
}
/// <summary>
/// Step preliminare di backup conf e app corrente
/// </summary>
/// <param name="reqApp"></param>
/// <returns></returns>
private async Task IobWinDoBackup(VersStatusDTO reqApp)
{
// controllo di avere un file di riferimento...
string appDir = Path.GetDirectoryName(reqApp.LocalPath) ?? "";
if (!string.IsNullOrEmpty(appDir))
{
string tempZip = Path.Combine(tempDir, "FULL", reqApp.CodApp);
// step 0: inserisce i file semaforo di segnalazione update in corso
using (FileStream fs = File.Create(updFilePath))
{
// File is created and access is released when the using block ends
}
// step 1: backup configurazioni partendo da path applicazione...
string srcDir = Path.Combine(appDir, "DATA", "CONF");
string destDir = Path.Combine(backupDir, "Conf", reqApp.CodApp, "DATA", "CONF");
// se MAN uso folder "accorciata"
if (reqApp.CodApp == "IOB-MAN")
{
srcDir = Path.Combine(appDir, "CONF");
destDir = Path.Combine(backupDir, "Conf", reqApp.CodApp, "CONF");
}
CopyDirectory(srcDir, destDir);
// step 2: kill processi
ForceKillByName(reqApp.CodApp);
// step 3: backup + zip intera folder applicativo
if (Directory.Exists(tempZip))
{
Directory.Delete(tempZip, true);
}
Directory.CreateDirectory(tempZip);
CopyDirectory(appDir, tempZip);
string zipPath = Path.Combine(backupDir, "Archive", reqApp.CodApp, $"{DateTime.Now:yyyyMMdd}_{DateTime.Now:HHmmss}.zip");
if (File.Exists(zipPath))
{
File.Delete(zipPath);
}
else
{
string zipDir = Path.GetDirectoryName(zipPath) ?? "";
if (!string.IsNullOrEmpty(zipDir))
{
if (!Directory.Exists(zipDir))
{
Directory.CreateDirectory(zipDir);
}
}
}
await Task.Run(() =>
{
ZipFile.CreateFromDirectory(tempZip, zipPath);
});
}
await Task.Delay(10);
}
/// <summary>
/// Step di download da remoto
/// </summary>
/// <param name="reqApp"></param>
/// <returns></returns>
private async Task IobWinDownload(VersStatusDTO reqApp)
{
// step 4: download // controllo di avere un file di riferimento...
string appDir = Path.GetDirectoryName(reqApp.LocalPath) ?? "";
if (!string.IsNullOrEmpty(appDir))
{
string installerDir = Path.Combine(backupDir, "installer", reqApp.CodApp);
// se il path fosse vuoto --> uso quello standard da nexus...
string urlDownload = reqApp.UrlDownload;
if (string.IsNullOrEmpty(urlDownload))
{
urlDownload = $"https://nexus.steamware.net/repository/utility/MAPO/{reqApp.CodApp}/stable/{reqApp.CodApp}.zip";
}
long size = updateMan.DownloadApp(urlDownload, installerDir, reqApp.CodApp, reqApp.VersNumLast);
// se non andata provo con auth...
if (size == 0)
{
size = updateManAuth.DownloadApp(urlDownload, installerDir, reqApp.CodApp, reqApp.VersNumLast);
}
}
await Task.Delay(10);
}
/// <summary>
/// Step di fix backup configurazioni + unlock file update run
/// </summary>
/// <param name="reqApp"></param>
/// <returns></returns>
private async Task IobWinRestoreConf(VersStatusDTO reqApp)
{
// step 6: restore conf
string appDir = Path.GetDirectoryName(reqApp.LocalPath) ?? "";
if (!string.IsNullOrEmpty(appDir))
{
string srcDir = Path.Combine(appDir, "DATA", "CONF");
string destDir = Path.Combine(backupDir, "Conf", reqApp.CodApp, "DATA", "CONF");
// se MAN uso folder "accorciata"
if (reqApp.CodApp == "IOB-MAN")
{
srcDir = Path.Combine(appDir, "CONF");
destDir = Path.Combine(backupDir, "Conf", reqApp.CodApp, "CONF");
}
CopyDirectory(destDir, srcDir);
}
// step 7: rimozione file lock semaforo
File.Delete(updFilePath);
await Task.Delay(10);
}
/// <summary>
/// Step di unzip file scaricato
/// </summary>
/// <param name="reqApp"></param>
/// <returns></returns>
private async Task IobWinUnzip(VersStatusDTO reqApp)
{
// step 5: unzip + overwrite
string appDir = Path.GetDirectoryName(reqApp.LocalPath) ?? "";
if (!string.IsNullOrEmpty(appDir))
{
string installerDir = Path.Combine(backupDir, "installer", reqApp.CodApp);
string srcZip = Path.Combine(installerDir, $"{reqApp.CodApp}.zip");
// svuoto la dir di destinazione preliminarmente...
DeleteDirectoryContents(appDir);
// esegue unzip
ZipFile.ExtractToDirectory(srcZip, appDir, true);
}
await Task.Delay(10);
}
private void ReportConfigUpd()
{
if (EA_ConfigUpdated != null)
+160
View File
@@ -0,0 +1,160 @@
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EgwControlCenter.Core
{
public class TaskRunStats
{
#region Public Constructors
/// <summary>
/// init da vuoto
/// </summary>
public TaskRunStats()
{
// init generico senza reload file
}
/// <summary>
/// Init classe con rilettura dati
/// </summary>
public TaskRunStats(string appDir, string confName)
{
AppDir = appDir;
ConfName = confName;
// inizio rileggendo (se presenti) dati conf da disco
tryReload();
}
#endregion Public Constructors
#region Public Properties
/// <summary>
/// Tempo medio complessivo registrato
/// </summary>
public TimeSpan AvgTotalTime
{
get
{
TimeSpan answ = new TimeSpan();
if (TaskData != null && TaskData.Count > 0)
{
foreach (var record in TaskData)
{
answ += record.Value.AvgTime;
}
}
return answ;
}
}
/// <summary>
/// nome del task registrato
/// </summary>
public Dictionary<string, TaskStat> TaskData { get; set; } = new Dictionary<string, TaskStat>();
#endregion Public Properties
#region Public Methods
/// <summary>
/// Tempo medio per un Task
/// </summary>
public TimeSpan AvgTaskTime(string taskName)
{
TimeSpan answ = new TimeSpan();
if (TaskData != null && TaskData.Count > 0)
{
if (TaskData.ContainsKey(taskName))
{
answ = TaskData[taskName].AvgTime;
}
}
return answ;
}
/// <summary>
/// Registro una singola esecuzione x effettuare valutazioni successive...
/// </summary>
/// <param name="taskName"></param>
/// <param name="duration"></param>
public void RecordExeData(string taskName, TimeSpan duration)
{
// cerco nel dizionario se presente
if (TaskData.ContainsKey(taskName))
{
TaskData[taskName].NumRun++;
TaskData[taskName].TotalTime += duration;
}
else
{
TaskData.Add(taskName, new TaskStat() { NumRun = 1, TotalTime = duration });
}
}
/// <summary>
/// Salva le statistiche su disco
/// </summary>
public void SaveToDisk()
{
var rawData = JsonConvert.SerializeObject(TaskData, Formatting.Indented);
if (rawData != null && rawData.Length > 2)
{
File.WriteAllText(StatsPath, rawData);
}
}
#endregion Public Methods
#region Private Fields
private static Logger Log = LogManager.GetCurrentClassLogger();
#endregion Private Fields
#region Private Properties
private string AppDir { get; set; } = "";
private string ConfName { get; set; } = "";
/// <summary>
/// Path file di conf check
/// </summary>
private string StatsPath
{
get => Path.Combine(AppDir, ConfName);
}
#endregion Private Properties
#region Private Methods
private void tryReload()
{
if (File.Exists(StatsPath))
{
string rawData = File.ReadAllText(StatsPath);
if (!string.IsNullOrEmpty(rawData) && rawData.Length > 2)
{
try
{
TaskData = JsonConvert.DeserializeObject<Dictionary<string, TaskStat>>(rawData);
}
catch (Exception exc)
{
Log.Error($"Eccezione in tryReload:{Environment.NewLine}{exc}");
}
}
}
}
#endregion Private Methods
}
}
+29
View File
@@ -0,0 +1,29 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace EgwControlCenter.Core
{
/// <summary>
/// Statistiche esecuzione task
/// </summary>
public class TaskStat
{
/// <summary>
/// num di esecuzioni registrate
/// </summary>
public long NumRun { get; set; } = 1;
/// <summary>
/// Tempo totale registrato
/// </summary>
public TimeSpan TotalTime { get; set; } = new TimeSpan();
/// <summary>
/// Timespan medio esecuzione
/// </summary>
[NotMapped]
public TimeSpan AvgTime
{
get => TotalTime / (NumRun > 1 ? NumRun : 1);
}
}
}
+127
View File
@@ -0,0 +1,127 @@
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace EgwControlCenter.Core
{
public class UpdateMan
{
#region Public Fields
/// <summary>
/// Init classe
/// </summary>
public static UpdateMan obj = new UpdateMan();
#endregion Public Fields
#region Public Constructors
/// <summary>
/// Init classe
/// </summary>
public UpdateMan()
{ }
/// <summary>
/// Init classe
/// </summary>
/// <param name="user"></param>
/// <param name="pwd"></param>
public UpdateMan(string user, string pwd)
{
userName = user;
passwd = pwd;
doAuth = !string.IsNullOrEmpty($"{userName}{passwd}");
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Effettua download specifica versione applicativo per install locale
/// </summary>
/// <param name="downloadUrl">url del file (tipicamente *.zip) da scaricare</param>
/// <param name="localDir">Cartella locale x salvataggio file</param>
/// <param name="packName">Nome applicativo con cui salvare</param>
/// <param name="version">Versione applicativo (per salvataggio storico versioni)</param>
public long DownloadApp(string downloadUrl, string localDir, string packName, string version)
{
long size = 0;
// verifico directory
if (!Directory.Exists(localDir))
{
Directory.CreateDirectory(localDir);
}
string localFile = "";
string localLast = "";
try
{
localFile = Path.Combine(localDir, $"{packName}_Build_{version}.zip");
localLast = Path.Combine(localDir, $"{packName}.zip");
// scarica file e salva in directory locale...
using (var http = new HttpClient())
{
if (doAuth)
{
//client.Credentials = new System.Net.NetworkCredential(userName, passwd);
http.DefaultRequestHeaders.Accept.Clear();
var byteArray = System.Text.ASCIIEncoding.UTF8.GetBytes($"{userName}:{passwd}");
http.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
}
// url da chiamare
http.BaseAddress = new Uri(downloadUrl);
// lettura
var data = http.GetAsync(downloadUrl).Result;
using (var myReader = data.Content.ReadAsStreamAsync())
{
//var myReader = data.Content.ReadAsStreamAsync();
if (data.StatusCode != HttpStatusCode.OK)
{
Log.Info($"Errore in chiamata DownloadApp per URL {downloadUrl}: status code: {data.StatusCode}");
}
else
{
using (Stream outStream = File.OpenWrite(localFile))
{
myReader.Result.CopyTo(outStream);
}
// ora lo copio come latest...
File.Copy(localFile, localLast, true);
// recupero dimensione file
var thisFile = new FileInfo(localLast);
size = thisFile.Length;
}
}
}
}
catch (Exception exc)
{
Log.Error($"Errore in fase di download installers | URL: {downloadUrl}{Environment.NewLine}{exc}");
}
return size;
}
#endregion Public Methods
#region Private Fields
private static Logger Log = LogManager.GetCurrentClassLogger();
private bool doAuth = false;
#endregion Private Fields
#region Private Properties
private string passwd { get; set; } = "";
private string userName { get; set; } = "";
#endregion Private Properties
}
}