Last-Modified: Mon, 13 Jul 2026 22:10:32 GMT
Expires: Thu, 10 Jul 2036 22:10:32 GMT
using FluentFTP;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.BL;
using Tango.BL.Entities;
using Tango.Core;
using Tango.Core.DB;
using Tango.Core.ExtensionMethods;
using Tango.Core.Helpers;
using Tango.Core.IO;
using Tango.Integration.Operation;
using Tango.Integration.Upgrade;
using Tango.Logging;
using Tango.PMR.Synchronization;
using Tango.PPC.Common.Application;
using Tango.PPC.Common.Connection;
using Tango.PPC.Common.Navigation;
using Tango.PPC.Common.Publish;
using Tango.PPC.Common.UpdatePackages;
using Tango.PPC.Common.Web;
using Tango.Settings;
using Tango.SharedUI.Helpers;
using Tango.SQLExaminer;
using Tango.Transport.Web;
using System.Data.Entity;
namespace Tango.PPC.Common.MachineUpdate
{
public class MachineUpdateManager : ExtendedObject, IMachineUpdateManager
{
private IPPCApplicationManager _app_manager;
private IMachineProvider _machineProvider;
private IPackageRunner _packageRunner;
private PPCWebClient _client;
private List<LogItemBase> _logs;
private System.Timers.Timer _checkForUpdateTimer;
private bool _isUpdating;
private PPCSettings _settings;
private DateTime _updateStartDate;
#region Events
/// <summary>
/// Occurs when an application update is available.
/// </summary>
public event EventHandler<CheckForUpdateResponse> UpdateAvailable;
/// <summary>
/// Occurs when there is a text log message available.
/// </summary>
public event EventHandler<string> ProgressLog;
/// <summary>
/// Occurs when the update has made some progress.
/// </summary>
public event EventHandler<MachineUpdateProgress> Progress;
#endregion
#region Properties
private MachineUpdateProgress _status;
/// <summary>
/// Gets the current machine update progress status.
/// </summary>
public MachineUpdateProgress Status
{
get { return _status; }
private set { _status = value; RaisePropertyChangedAuto(); }
}
private bool _autoCheckForUpdates;
/// <summary>
/// Gets or sets a value indicating whether to automatically check for new application updates.
/// </summary>
public bool EnableAutoCheckForUpdates
{
get { return _autoCheckForUpdates; }
set { _autoCheckForUpdates = value; RaisePropertyChangedAuto(); }
}
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="MachineUpdateManager"/> class.
/// </summary>
/// <param name="applicationManager">The application manager.</param>
public MachineUpdateManager(PPCWebClient ppcWebClient, IPPCApplicationManager applicationManager, IMachineProvider machineProvider, IPackageRunner packageRunner)
{
_client = ppcWebClient;
_machineProvider = machineProvider;
_app_manager = applicationManager;
_packageRunner = packageRunner;
_packageRunner.PackageProgress += _packageRunner_PackageProgress;
_logs = new List<LogItemBase>();
LogManager.NewLog += LogManager_NewLog;
_checkForUpdateTimer = new System.Timers.Timer(TimeSpan.FromMinutes(1).TotalMilliseconds);
_checkForUpdateTimer.Elapsed += _checkForUpdateTimer_Elapsed;
_checkForUpdateTimer.Start();
_settings = SettingsManager.Default.GetOrCreate<PPCSettings>();
}
#endregion
#region Event Handlers
private void _packageRunner_PackageProgress(object sender, PackageProgressEventArgs e)
{
UpdateProgress(e.PackageName, e.Message, e.IsIntermediate, e.Progress, e.Total);
}
private void LogManager_NewLog(object sender, LogItemBase e)
{
if (_isUpdating)
{
_logs.Add(e);
}
}
#endregion
#region Private Methods
private Task Login(String serialNumber)
{
return _client.Login(new LoginRequest()
{
Mode = LoginMode.Machine,
SerialNumber = serialNumber,
});
}
private async void OnFailed(Exception ex, TaskCompletionSource<MachineUpdateResult> completionSource, DownloadUpdateResponse response, bool performDatabaseRollback, String dbBackupFile, String backupsFolder, String tempDbName, Tango.Core.DataSource localDataSource, String tempUpdatePackageFolder = null, PublishInfo tupPublishInfo = null)
{
LogManager.Log(ex, "An error occurred in machine update.");
await Task.Factory.StartNew(() =>
{
if (performDatabaseRollback)
{
LogManager.Log("Rolling back database changes...");
using (DbManager db = DbManager.FromDataSource(localDataSource))
{
try
{
UpdateProgress("Rollback", "Rolling back database changes...");
db.Restore(localDataSource.Catalog, dbBackupFile);
LogManager.Log("Database restored successfully.");
}
catch (Exception e)
{
LogManager.Log(e, "Could not rollback the database.");
}
finally
{
try
{
File.Delete(dbBackupFile);
}
catch { }
}
}
}
if (tempDbName != null)
{
try
{
LogManager.Log($"Removing temporary database '{tempDbName}'...");
using (DbManager dbManager = DbManager.FromDataSource(localDataSource))
{
dbManager.SetOffline(tempDbName);
dbManager.SetOnline(tempDbName);
dbManager.Delete(tempDbName);
}
}
catch (Exception exx)
{
LogManager.Log(exx, "Error removing temporary database.");
}
}
try
{
Directory.Delete(backupsFolder, true);
}
catch (Exception ee)
{
LogManager.Log(ee, $"Error deleting backups folder '{backupsFolder}'.");
}
if (tempUpdatePackageFolder != null)
{
try
{
Directory.Delete(tempUpdatePackageFolder, true);
}
catch (Exception eee)
{
LogManager.Log(eee, "Error removing temporary package folder.");
}
}
});
completionSource.SetException(ex);
String logs = GetLogsStringAndClear();
if (response != null)
{
try
{
var result = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Token = response.NotifyCompletedToken,
Status = BL.Enumerations.TangoUpdateStatuses.UpdateFailed,
FailedReason = ex.FlattenMessage(),
FailedLog = logs,
});
}
catch (Exception xx)
{
LogManager.Log(xx, "Error notifying update failed.");
}
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = response.Version;
update.FirmwareVersion = response.FirmwareVersion;
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.UpdateFailed;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
update.FailedReason = ex.FlattenMessage();
update.FailedLog = logs;
db.TangoUpdates.Add(update);
await db.SaveChangesAsync();
}
}
catch (Exception xxx)
{
LogManager.Log(xxx, "Error saving tango update information to database.");
}
}
if (tupPublishInfo != null)
{
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = tupPublishInfo.ApplicationVersion;
update.FirmwareVersion = tupPublishInfo.GetFirmwareVersion();
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineUpdateFailed;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
update.FailedReason = ex.FlattenMessage();
update.FailedLog = logs;
db.TangoUpdates.Add(update);
await db.SaveChangesAsync();
}
}
catch (Exception xxx)
{
LogManager.Log(xxx, "Error saving tango offline update information to database.");
}
}
_isUpdating = false;
}
private async void OnCompleted(MachineUpdateResult result, TaskCompletionSource<MachineUpdateResult> completionSource, DownloadUpdateResponse response, String tempDbName, String backupsFolder, Core.DataSource localDataSource, PublishInfo tupPublishInfo = null)
{
await Task.Factory.StartNew(() =>
{
if (tempDbName != null)
{
try
{
LogManager.Log($"Removing temporary database '{tempDbName}'...");
using (DbManager dbManager = DbManager.FromDataSource(localDataSource))
{
dbManager.SetOffline(tempDbName);
dbManager.SetOnline(tempDbName);
dbManager.Delete(tempDbName);
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error removing temporary database.");
}
}
try
{
Directory.Delete(backupsFolder, true);
}
catch (Exception ex)
{
LogManager.Log(ex, $"Error deleting backups folder '{backupsFolder}'.");
}
if (!result.RequiresBinariesUpdate)
{
try
{
Directory.Delete(result.UpdatePackagePath, true);
}
catch (Exception ex)
{
LogManager.Log(ex, "Error removing temporary package folder.");
}
}
});
completionSource.SetResult(result);
if (response != null)
{
try
{
var r = await _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Token = response.NotifyCompletedToken,
Status = BL.Enumerations.TangoUpdateStatuses.UpdateCompleted,
});
}
catch (Exception ex)
{
LogManager.Log(ex, "Error notifying update completed.");
}
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = response.Version;
update.FirmwareVersion = response.FirmwareVersion;
update.MachineGuid = (await db.Machines.FirstAsync()).Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.UpdateCompleted;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
db.TangoUpdates.Add(update);
await db.SaveChangesAsync();
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error saving tango update information to database.");
}
}
if (tupPublishInfo != null)
{
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = tupPublishInfo.ApplicationVersion;
update.FirmwareVersion = tupPublishInfo.GetFirmwareVersion();
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineUpdateCompleted;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
db.TangoUpdates.Add(update);
await db.SaveChangesAsync();
}
}
catch (Exception xxx)
{
LogManager.Log(xxx, "Error saving tango offline update information to database.");
}
}
_isUpdating = false;
}
private void OnFailed(Exception ex, UpdateDBResponse response, bool performDatabaseRollback, String dbBackupFile, Tango.Core.DataSource localDataSource)
{
LogManager.Log(ex, "An error occurred in database update.");
if (performDatabaseRollback)
{
LogManager.Log("Rolling back database changes...");
using (DbManager db = DbManager.FromDataSource(localDataSource))
{
try
{
UpdateProgress("Rollback", "Rolling back database changes...");
db.Restore(localDataSource.Catalog, dbBackupFile);
LogManager.Log("Database restored successfully.");
}
catch (Exception e)
{
LogManager.Log(e, "Could not rollback the database.");
throw ex;
}
finally
{
try
{
File.Delete(dbBackupFile);
}
catch { }
}
}
}
String logs = GetLogsStringAndClear();
if (response != null)
{
try
{
var r = _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Token = response.NotifyCompletedToken,
Status = BL.Enumerations.TangoUpdateStatuses.DatabaseFailed,
FailedReason = ex.FlattenMessage(),
FailedLog = logs,
}).Result;
}
catch (Exception xx)
{
LogManager.Log(xx, "Error notifying database failed.");
}
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = _app_manager.Version.ToString();
update.FirmwareVersion = _app_manager.FirmwareVersion.ToString();
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.DatabaseFailed;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
update.FailedReason = ex.FlattenMessage();
update.FailedLog = logs;
db.TangoUpdates.Add(update);
db.SaveChanges();
}
}
catch (Exception exx)
{
LogManager.Log(exx, "Error saving database update information to database.");
}
}
_isUpdating = false;
}
private void OnCompleted(UpdateDBResponse response, bool completedWithNoDifferences = false)
{
if (response != null)
{
try
{
var r = _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest()
{
Token = response.NotifyCompletedToken,
Status = BL.Enumerations.TangoUpdateStatuses.DatabaseCompleted,
ReportsAboutDbCheckNoDifferences = completedWithNoDifferences,
}).Result;
}
catch (Exception ex)
{
LogManager.Log(ex, "Error notifying database completed.");
}
if (!completedWithNoDifferences)
{
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = _app_manager.Version.ToString();
update.FirmwareVersion = _app_manager.FirmwareVersion.ToString();
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.DatabaseCompleted;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
db.TangoUpdates.Add(update);
db.SaveChanges();
}
}
catch (Exception ex)
{
LogManager.Log(ex, "Error saving database update information to database.");
}
}
}
_isUpdating = false;
}
private void OnFailed(Exception ex, TaskCompletionSource<object> completionSource, String firmwareVersion)
{
LogManager.Log(ex, "An error occurred in firmware upgrade.");
completionSource.SetException(ex);
String logs = GetLogsStringAndClear();
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = _app_manager.Version.ToString();
update.FirmwareVersion = firmwareVersion;
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineFirmwareUpgradeFailed;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
update.FailedReason = ex.FlattenMessage();
update.FailedLog = logs;
db.TangoUpdates.Add(update);
db.SaveChanges();
}
}
catch (Exception exx)
{
LogManager.Log(exx, "Error saving firmware upgrade information to database.");
}
_isUpdating = false;
}
private void OnCompleted(TaskCompletionSource<object> completionSource, String firmwareVersion)
{
LogManager.Log("Firmware upgrade completed successfully.");
completionSource.SetResult(true);
try
{
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
TangoUpdate update = new TangoUpdate();
update.ApplicationVersion = _app_manager.Version.ToString();
update.FirmwareVersion = firmwareVersion;
update.MachineGuid = _machineProvider.Machine.Guid;
update.UpdateStatus = BL.Enumerations.TangoUpdateStatuses.OfflineFirmwareUpgradeCompleted;
update.StartDate = _updateStartDate;
update.EndDate = DateTime.UtcNow;
db.TangoUpdates.Add(update);
db.SaveChanges();
}
}
catch (Exception exx)
{
LogManager.Log(exx, "Error saving firmware upgrade information to database.");
}
_isUpdating = false;
}
private String GetLogsStringAndClear()
{
String logsString = String.Join(Environment.NewLine, _logs.ToList().Select(x => x.ToString()));
_logs.Clear();
return logsString;
}
#endregion
#region Public Methods
/// <summary>
/// Performs a machine update using the specified serial number and machine service address.
/// </summary>
/// <param name="serialNumber">The serial number.</param>
/// <param name="setupFirmware">if set to <c>true</c> updates the embedded device firmware.</param>
/// <param name="setupFPGA">if set to <c>true</c> updates the embedded device FPGA version and other parameters.</param>
/// <returns></returns>
/// <exception cref="System.InvalidOperationException">
/// Could not perform an update while the machine is not connected.
/// or
/// or
/// </exception>
/// <exception cref="System.InvalidProgramException">Database tango does not exists.</exception>
public async Task<MachineUpdateResult> Update(bool setupFirmware, bool setupFPGA)
{
_updateStartDate = DateTime.UtcNow;
_logs.Clear();
TaskCompletionSource<MachineUpdateResult> result = new TaskCompletionSource<MachineUpdateResult>();
var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
bool performDatabaseRollback = false;
String dbBackupFile = null;
DownloadUpdateResponse update_response = null;
String backupsFolder = "C:\\Backups";
//Create temporary folders for packages.
var _newPackageTempFolder = TemporaryManager.CreateFolder();
_newPackageTempFolder.Persist = true;
String serialNumber = _machineProvider.Machine.SerialNumber;
try
{
_isUpdating = true;
var machineServiceAddress = _settings.GetMachineServiceAddress();
LogManager.Log($"Starting machine update for serial number {serialNumber}...");
//Connecting to machine...
LogManager.Log("Verifying machine connection and state...");
UpdateProgress("Verifying machine state", "Initializing...");
await Task.Delay(1000);
IMachineOperator op = _machineProvider.MachineOperator;
if (setupFirmware)
{
LogManager.Log("Machine is configured to update firmware...");
if (op.State != Transport.TransportComponentState.Connected)
{
throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected."));
}
if (!op.CanPrint)
{
throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status."));
}
}
//Connect to machine service and get matching packages for this machine.
UpdateProgress("Downloading software package", "Connecting to machine service...");
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
await Login(serialNumber);
DownloadUpdateRequest request = new DownloadUpdateRequest();
request.SerialNumber = serialNumber;
update_response = await _client.MachineUpdate(request);
LogManager.Log($"Machine update response received: {Environment.NewLine}{update_response.ToJsonString()}");
LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}.");
//Download software package.
var tempFile = TemporaryManager.CreateFile(".zip");
LogManager.Log($"Temporary package zip file created: {tempFile}.");
LogManager.Log("Downloading software package...");
UpdateProgress("Downloading software package", "Downloading...", false);
using (AutoFileDownloader downloader = new AutoFileDownloader(update_response.BlobAddress, update_response.CdnAddress, tempFile))
{
await downloader.ResolveMode();
if (downloader.Mode == AutoFileDownloader.DownloadMode.Standard)
{
LogManager.Log($"Connecting to storage CDN with address {downloader.Address}");
}
else
{
LogManager.Log($"Connecting to storage blob with address {downloader.Address}");
}
downloader.Progress += (x, e) =>
{
UpdateProgress("Downloading software package", "Downloading...", false, e.Current, e.Total);
};
var size = await downloader.GetFileSize();
LogManager.Log("Download size: " + size + " bytes.");
LogManager.Log("Starting file download...");
await downloader.Download();
}
UpdateProgress("Downloading software package", "Extracting package...");
LogManager.Log("Extracting downloaded zip file...");
await Task.Factory.StartNew(() =>
{
//Extract software package.
ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder);
});
LogManager.Log("Copying latest updater utility to application path...");
//Copy new updater utility to app path.
File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true);
//Run pre-update packages.
try
{
UpdateProgress("Preparing", "Running update packages...");
LogManager.Log("Running pre-update packages...");
var packagesFolder = Path.Combine(_newPackageTempFolder, "Packages");
Version updateVersion = new Version(1, 0, 0, 0);
try
{
updateVersion = Version.Parse(update_response.Version);
}
catch (Exception ex)
{
LogManager.Log(ex, "Error parsing new version string for package runner.");
}
await _packageRunner.Run(PackageType.Pre, updateVersion, packagesFolder);
}
catch (Exception ex)
{
LogManager.Log(ex, "Error running pre-update packages...");
}
//Synchronize database
UpdateProgress("Updating Database", "Initializing...");
LogManager.Log($"Synchronizing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
UpdateProgress("Updating Database", "Connecting to local database...");
LogManager.Log("Initializing database manager...");
DbManager db = DbManager.FromDataSource(localDataSource);
LogManager.Log("Checking Tango database exists on the local machine...");
if (!db.Exists(localDataSource.Catalog))
{
throw new InvalidProgramException("Database tango does not exists.");
}
UpdateProgress("Updating Database", "Creating database backup...");
//Create Database Backup
try
{
Directory.CreateDirectory(backupsFolder);
dbBackupFile = $"{backupsFolder}\\{Path.GetRandomFileName()}.bak";
LogManager.Log($"Creating database backup to '{dbBackupFile}'...");
await Task.Factory.StartNew(() => db.Backup(localDataSource.Catalog, dbBackupFile));
performDatabaseRollback = true;
LogManager.Log("Database backup created successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Update manager error while trying to create a database backup.");
}
LogManager.Log("Disposing database manager.");
db.Dispose();
LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}...");
UpdateProgress("Updating Database", "Initializing update sequence...");
ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner(
Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"),
Path.Combine(_newPackageTempFolder, "Update Scripts"),
update_response.DataSource,
localDataSource,
serialNumber);
runner.Log += (x, msg) =>
{
LogManager.Log(msg);
ProgressLog?.Invoke(this, msg);
};
runner.ScriptExecuting += (x, item) =>
{
LogManager.Log($"Executing script {item.ToString()}...");
UpdateProgress("Updating Database", item.Name + "...");
};
LogManager.Log("Starting synchronization process...");
try
{
await runner.Run();
LogManager.Log("Synchronization completed successfully!");
UpdateProgress("Updating Database", "Database synchronization completed successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Update manager error while trying to synchronize database.");
}
//Updating firmware
if (setupFirmware)
{
UpdateProgress("Updating Firmware", "Connecting to firmware device...");
LogManager.Log("");
LogManager.Log("-------------------------------------------------------------------------");
LogManager.Log("Updating Firmware...");
UpdateProgress("Updating Firmware", "Loading firmware package...");
var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp");
var stream = new FileStream(tfpPath, FileMode.Open);
if (!_machineProvider.Machine.IsDemo)
{
if (setupFPGA)
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE;
}
else
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU;
}
}
else
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.TFP_PACKAGE;
}
var handler = await op.UpgradeFirmware(stream);
handler.Failed += (_, ex) =>
{
stream.Dispose();
OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder);
};
handler.Completed += (_, __) =>
{
UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
stream.Dispose();
OnCompleted(new MachineUpdateResult()
{
UpdatePackagePath = _newPackageTempFolder,
}, result, update_response, null, backupsFolder, localDataSource);
};
handler.Canceled += (_, __) =>
{
stream.Dispose();
OnFailed(new Exception("The operation has been canceled."), result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder);
};
handler.Progress += (_, e) =>
{
UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total);
};
}
else
{
OnCompleted(new MachineUpdateResult()
{
UpdatePackagePath = _newPackageTempFolder,
}, result, update_response, null, backupsFolder, localDataSource);
}
}
catch (Exception ex)
{
OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder);
}
return await result.Task;
}
/// <summary>
/// Checks if any update are available for the specified machine serial number.
/// </summary>
/// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
public Task<CheckForUpdateResponse> CheckForUpdate(string serialNumber)
{
return Task.Factory.StartNew<CheckForUpdateResponse>(() =>
{
_isUpdating = true;
var machineServiceAddress = _settings.GetMachineServiceAddress();
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
Login(serialNumber).GetAwaiter().GetResult();
LogManager.Log($"Checking if updates available...");
CheckForUpdateRequest request = new CheckForUpdateRequest();
request.SerialNumber = serialNumber;
request.Version = _app_manager.Version.ToString();
try
{
request.MachineLastUpdated = _machineProvider.Machine.LastUpdated;
using (ObservablesContext db = ObservablesContext.CreateDefault())
{
request.Rmls = db.Rmls.ToList().Select(x => new UpdatedEntity(x)).ToList();
request.HardwareVersions = db.HardwareVersions.ToList().Select(x => new UpdatedEntity(x)).ToList();
request.Catalogs = db.ColorCatalogs.ToList().Select(x => new UpdatedEntity(x)).ToList();
request.UsedRmlsGuids = db.Jobs.Select(x => x.RmlGuid).Distinct().ToList();
}
}
catch (Exception ex)
{
LogManager.Log(ex, "An error occurred while trying to fill the existing database entities before checking for updates.");
}
CheckForUpdateResponse update_response = null;
update_response = _client.CheckForUpdates(request).Result;
LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}");
_isUpdating = false;
return update_response;
});
}
/// <summary>
/// Updates all the "overwrite-able" database tables.
/// </summary>
/// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
public Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber)
{
_updateStartDate = DateTime.UtcNow;
_logs.Clear();
return Task.Factory.StartNew(() =>
{
_isUpdating = true;
UpdateDBResponse update_response = null;
var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
bool performDatabaseRollback = false;
String dbBackupFile = null;
try
{
LogManager.Log("Starting database update...");
UpdateProgress("Updating Database", "Initializing...");
LogManager.Log("Looking for update scripts configuration on application path...");
String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml");
if (!File.Exists(config_file))
{
throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder."));
}
update_response = dbCompareResult.UpdateDBResponse;
LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
UpdateProgress("Updating Database", "Initializing update sequence...");
ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file);
UpdateProgress("Updating Database", "Connecting to local database...");
LogManager.Log("Initializing database manager...");
DbManager db = DbManager.FromDataSource(localDataSource);
LogManager.Log("Checking Tango database exists on the local machine...");
if (!db.Exists(localDataSource.Catalog))
{
throw new InvalidProgramException("Database tango does not exists.");
}
UpdateProgress("Updating Database", "Creating database backup...");
//Create Database Backup
try
{
Directory.CreateDirectory("C:\\Backups");
dbBackupFile = $"C:\\Backups\\{Path.GetRandomFileName()}.bak";
LogManager.Log($"Creating database backup to '{dbBackupFile}'...");
db.Backup(localDataSource.Catalog, dbBackupFile);
performDatabaseRollback = true;
LogManager.Log("Database backup created successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Update manager error while trying to create a database backup.");
}
LogManager.Log("Disposing database manager.");
db.Dispose();
foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data || update_response.PerformSchemaUpdate).OrderBy(x => x.Index))
{
LogManager.Log($"Executing update script '{item.FileName}...'");
ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName));
builder.SetSource(update_response.DataSource);
builder.SetTarget(localDataSource);
if (item.RequiresSerialNumber)
{
builder.SetMachineSerialNumber(serialNumber);
}
builder.Synchronize();
var config = builder.Build();
ExaminerProcess process = new ExaminerProcess(config, item.Type == ExaminerSequenceItemType.Data ? ExaminerProcessType.Data : ExaminerProcessType.Schema);
process.Progress += (x, msg) =>
{
LogManager.Log(msg);
};
try
{
UpdateProgress("Updating Database", item.Name + "...");
var result = process.Execute().Result;
if (result.ExitCode != ExaminerProcessExitCode.Success)
{
throw LogManager.Log(new InvalidDataException($"{item.FileName} script has terminated with exit code '{result.ExitCode}'."));
}
LogManager.Log("Script executed successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Upudate manager error while trying to update the database.");
}
}
UpdateProgress("Updating Database", "Database synchronization completed successfully.");
LogManager.Log("Update completed successfully.");
OnCompleted(update_response);
}
catch (Exception ex)
{
OnFailed(ex, update_response, performDatabaseRollback, dbBackupFile, localDataSource);
throw ex;
}
});
}
/// <summary>
/// Checks whether it is necessary to updates all the "overwrite-able" database tables.
/// </summary>
/// <param name="serialNumber">The serial number.</param>
/// <param name="machineServiceAddress">The machine service address.</param>
/// <returns></returns>
public Task<DbCompareResult> UpdateDBCheck(string serialNumber)
{
return Task.Factory.StartNew<DbCompareResult>(() =>
{
var machineServiceAddress = _settings.GetMachineServiceAddress();
LogManager.Log($"Checking if database update is required for serial number {serialNumber}...");
LogManager.Log("Looking for update scripts configuration on application path...");
String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml");
if (!File.Exists(config_file))
{
throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder."));
}
LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");
Login(serialNumber).Wait();
UpdateDBRequest request = new UpdateDBRequest();
request.SerialNumber = serialNumber;
request.ApplicationVersion = _app_manager.Version.ToString();
request.FirmwareVersion = _app_manager.FirmwareVersion.ToString();
UpdateDBResponse update_response = null;
update_response = _client.UpdateDB(request).Result;
LogManager.Log($"Update DB response received: {Environment.NewLine}{update_response.ToJsonString()}");
var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
LogManager.Log($"Comparing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");
var report_file = TemporaryManager.CreateFile(".xml");
ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file);
bool has_differences = false;
foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data).OrderBy(x => x.Index))
{
LogManager.Log($"Executing update script '{item.FileName}...'");
ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName));
builder.SetSource(update_response.DataSource);
builder.SetTarget(localDataSource);
builder.SetReportFile(report_file);
if (item.RequiresSerialNumber)
{
builder.SetMachineSerialNumber(serialNumber);
}
var config = builder.Build();
ExaminerProcess process = new ExaminerProcess(config, ExaminerProcessType.Data);
process.Progress += (x, msg) =>
{
LogManager.Log(msg);
};
LogManager.Log("Starting comparison process...");
LogManager.Log("Generating report on " + report_file);
try
{
var result = process.Execute().Result;
if (result.ExitCode != ExaminerProcessExitCode.Success)
{
throw LogManager.Log(new InvalidDataException(String.Format("Update script has terminated with exit code '{0}'.", result.ExitCode)));
}
LogManager.Log("Comparison completed successfully!");
LogManager.Log("Loading report file...");
ExaminerDataReport report = ExaminerDataReport.FromFile(report_file);
report_file.Delete();
LogManager.Log("Comparison summary: \n" + report.Totals.ToJsonString());
if (report.HasDifferences)
{
has_differences = true;
break;
}
}
catch (Exception ex)
{
OnFailed(ex, update_response, false, null, null);
throw LogManager.Log(ex, "Update manager error while trying to compare the database.");
}
}
LogManager.Log("Comparison completed successfully.");
if (!has_differences)
{
OnCompleted(update_response, true);
}
return new DbCompareResult()
{
RequiresUpdate = has_differences,
UpdateDBResponse = update_response,
};
});
}
/// <summary>
/// Performs a machine update using the specified software update package path.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <returns></returns>
public async Task<MachineUpdateResult> UpdateFromTUP(string fileName, bool setupFirmware, bool setupFPGA)
{
_updateStartDate = DateTime.UtcNow;
_logs.Clear();
TaskCompletionSource<MachineUpdateResult> result = new TaskCompletionSource<MachineUpdateResult>();
var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;
bool performDatabaseRollback = false;
String dbBackupFile = null;
String tempDbName = "Tango_TUP";
String tempDbFileName = tempDbName + ".bak";
String backupsFolder = "C:\\Backups";
bool replaceBinaries = false;
PublishInfo publishInfo = null;
String serialNumber = _machineProvider.Machine.SerialNumber;
//Create temporary folders for packages.
var _newPackageTempFolder = TemporaryManager.CreateFolder();
_newPackageTempFolder.Persist = true;
try
{
_isUpdating = true;
LogManager.Log($"Starting machine update for serial number {serialNumber}...");
//Connecting to machine...
LogManager.Log("Verifying machine connection and state...");
UpdateProgress("Verifying machine state", "Initializing...");
await Task.Delay(1000);
IMachineOperator op = _machineProvider.MachineOperator;
if (setupFirmware)
{
LogManager.Log("Machine is configured to update firmware...");
if (op.State != Transport.TransportComponentState.Connected)
{
throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected."));
}
if (!op.CanPrint)
{
throw LogManager.Log(new InvalidOperationException($"Could not perform an update while the machine is in {op.Status} status."));
}
}
UpdateProgress("Exploring package", "Extracting...");
LogManager.Log("Extracting package...");
LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}.");
await Task.Factory.StartNew(() =>
{
//Extract software package.
ZipFile.ExtractToDirectory(fileName, _newPackageTempFolder);
});
//Extracting publish info
UpdateProgress("Exploring package", "Verifying...");
publishInfo = PublishInfo.FromJson(File.ReadAllText(Path.Combine(_newPackageTempFolder, "version.json")));
if (!publishInfo.IsMachineTupPackage)
{
throw new InvalidOperationException("The specified tup file is invalid. Updating a machine from a tup file requires a custom generated package.");
}
if (publishInfo.MachineSerialNumber != serialNumber)
{
throw new InvalidOperationException("The specified tup file is invalid. The package was generated for a different machine.");
}
if (publishInfo.MachineDeploymentSlot != _settings.DeploymentSlot)
{
throw new InvalidOperationException("The specified tup file is invalid. The package was generated on a different environment.");
}
replaceBinaries = _app_manager.Version.ToString() != publishInfo.ApplicationVersion;
LogManager.Log("Copying latest updater utility to application path...");
//Copy new updater utility to app path.
File.Copy(Path.Combine(_newPackageTempFolder, "Tango.PPC.Updater.exe"), Path.Combine(PathHelper.GetStartupPath(), "Tango.PPC.Updater.exe"), true);
//Run pre-update packages.
try
{
UpdateProgress("Preparing", "Running update packages...");
LogManager.Log("Running pre-update packages...");
var packagesFolder = Path.Combine(_newPackageTempFolder, "Packages");
Version updateVersion = new Version(1, 0, 0, 0);
try
{
updateVersion = Version.Parse(publishInfo.ApplicationVersion);
}
catch (Exception ex)
{
LogManager.Log(ex, "Error parsing new version string for package runner.");
}
await _packageRunner.Run(PackageType.Pre, updateVersion, packagesFolder);
}
catch (Exception ex)
{
LogManager.Log(ex, "Error running pre-update packages...");
}
//Synchronize database
UpdateProgress("Updating Database", "Initializing...");
UpdateProgress("Updating Database", "Connecting to local database...");
LogManager.Log("Initializing database manager...");
DbManager db = DbManager.FromDataSource(localDataSource);
LogManager.Log("Checking Tango database exists on the local machine...");
if (!db.Exists(localDataSource.Catalog))
{
throw new InvalidProgramException("Database tango does not exists.");
}
UpdateProgress("Updating Database", "Creating database backup...");
//Create Database Backup
try
{
Directory.CreateDirectory(backupsFolder);
dbBackupFile = $"{backupsFolder}\\{Path.GetRandomFileName()}.bak";
LogManager.Log($"Creating database backup to '{dbBackupFile}'...");
await Task.Factory.StartNew(() => db.Backup(localDataSource.Catalog, dbBackupFile));
performDatabaseRollback = true;
LogManager.Log("Database backup created successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Update manager error while trying to create a database backup.");
}
LogManager.Log("Extracting database file from package...");
File.Copy(Path.Combine(_newPackageTempFolder, tempDbFileName), Path.Combine(backupsFolder, tempDbFileName));
LogManager.Log("Restoring package database as a new database...");
db.RestoreAsNew(tempDbName, Path.Combine(backupsFolder, tempDbFileName), backupsFolder);
Core.DataSource tempDbDataSource = new Core.DataSource();
tempDbDataSource.Address = localDataSource.Address;
tempDbDataSource.IntegratedSecurity = localDataSource.IntegratedSecurity;
tempDbDataSource.Type = localDataSource.Type;
tempDbDataSource.Catalog = tempDbName;
LogManager.Log("Disposing database manager.");
db.Dispose();
LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}...");
UpdateProgress("Updating Database", "Initializing update sequence...");
ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner(
Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"),
Path.Combine(_newPackageTempFolder, "Update Scripts"),
tempDbDataSource,
localDataSource,
serialNumber);
runner.Log += (x, msg) =>
{
LogManager.Log(msg);
ProgressLog?.Invoke(this, msg);
};
runner.ScriptExecuting += (x, item) =>
{
LogManager.Log($"Executing script {item.ToString()}...");
UpdateProgress("Updating Database", item.Name + "...");
};
LogManager.Log("Starting synchronization process...");
try
{
await runner.Run();
LogManager.Log("Synchronization completed successfully!");
UpdateProgress("Updating Database", "Database synchronization completed successfully.");
}
catch (Exception ex)
{
throw LogManager.Log(ex, "Update manager error while trying to synchronize database.");
}
LogManager.Log("Getting setup firmware/fpga directly from db..");
using (var dbManager = DbManager.FromDataSource(localDataSource))
{
try
{
String firmware = dbManager.GetValue($"SELECT TOP 1 * FROM MACHINES WHERE SERIAL_NUMBER = '{serialNumber}'", "SETUP_FIRMWARE");
String fpga = dbManager.GetValue($"SELECT TOP 1 * FROM MACHINES WHERE SERIAL_NUMBER = '{serialNumber}'", "SETUP_FPGA");
setupFirmware = bool.Parse(firmware);
setupFPGA = bool.Parse(fpga);
}
catch (Exception ex)
{
LogManager.Log(ex, "Error getting new values of SETUP_FIRMWARE and SETUP_FPGA.");
}
}
//Updating firmware
if (setupFirmware)
{
UpdateProgress("Updating Firmware", "Connecting to firmware device...");
LogManager.Log("");
LogManager.Log("-------------------------------------------------------------------------");
LogManager.Log("Updating Firmware...");
UpdateProgress("Updating Firmware", "Loading firmware package...");
var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp");
var stream = new FileStream(tfpPath, FileMode.Open);
if (!_machineProvider.Machine.IsDemo)
{
if (setupFPGA)
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE;
}
else
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU;
}
}
else
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.TFP_PACKAGE;
}
var handler = await op.UpgradeFirmware(stream);
handler.Failed += (_, ex) =>
{
stream.Dispose();
OnFailed(ex, result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo);
};
handler.Completed += (_, __) =>
{
UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
stream.Dispose();
OnCompleted(new MachineUpdateResult()
{
UpdatePackagePath = _newPackageTempFolder,
RequiresBinariesUpdate = replaceBinaries,
}, result, null, tempDbName, backupsFolder, localDataSource, publishInfo);
};
handler.Canceled += (_, __) =>
{
stream.Dispose();
OnFailed(new Exception("The operation has been canceled."), result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo);
};
handler.Progress += (_, e) =>
{
UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total);
};
}
else
{
OnCompleted(new MachineUpdateResult()
{
UpdatePackagePath = _newPackageTempFolder,
RequiresBinariesUpdate = replaceBinaries,
}, result, null, tempDbName, backupsFolder, localDataSource, publishInfo);
}
}
catch (Exception ex)
{
OnFailed(ex, result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo);
}
return await result.Task;
}
/// <summary>
/// Performs a firmware upgrade from the specified TFP file.
/// </summary>
/// <param name="fileName">Name of the file.</param>
/// <returns></returns>
/// <exception cref="InvalidOperationException">
/// Could not perform a firmware upgrade while the machine is not connected.
/// or
/// </exception>
public async Task UpdateFromTFP(String fileName)
{
_updateStartDate = DateTime.UtcNow;
_logs.Clear();
TaskCompletionSource<object> result = new TaskCompletionSource<object>();
String version = String.Empty;
Stream stream = null;
try
{
_isUpdating = true;
IMachineOperator op = _machineProvider.MachineOperator;
UpdateProgress("Updating Firmware", "Loading firmware package...");
stream = new FileStream(fileName, FileMode.Open);
var packageInfo = await op.GetFirmwarePackageInfo(stream);
stream.Position = 0;
version = packageInfo.FileDescriptors.FirstOrDefault(x => x.Destination == PMR.FirmwareUpgrade.VersionFileDestination.Mcu)?.Version;
LogManager.Log("Verifying machine connection and state...");
UpdateProgress("Verifying machine state", "Initializing...");
await Task.Delay(1000);
if (op.State != Transport.TransportComponentState.Connected)
{
throw LogManager.Log(new InvalidOperationException("Could not perform a firmware upgrade while the machine is not connected."));
}
if (!op.CanPrint)
{
throw LogManager.Log(new InvalidOperationException($"Could not perform a firmware upgrade while the machine is in {op.Status} status."));
}
UpdateProgress("Updating Firmware", "Connecting to firmware device...");
LogManager.Log("");
LogManager.Log("-------------------------------------------------------------------------");
LogManager.Log("Updating Firmware...");
if (!_machineProvider.Machine.IsDemo)
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE;
}
else
{
op.FirmwareUpgradeMode = FirmwareUpgradeModes.TFP_PACKAGE;
}
var handler = await op.UpgradeFirmware(stream);
handler.Failed += (_, ex) =>
{
stream.Dispose();
OnFailed(ex, result, version);
};
handler.Completed += (_, __) =>
{
UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
stream.Dispose();
OnCompleted(result, version);
};
handler.Canceled += (_, __) =>
{
stream.Dispose();
OnFailed(new Exception("The operation has been canceled."), result, version);
};
handler.Progress += (_, e) =>
{
UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total);
};
}
catch (Exception ex)
{
try
{
if (stream != null)
{
stream.Dispose();
}
}
catch { }
OnFailed(ex, result, version);
}
await result.Task;
}
/// <summary>
/// Gets the update package file information.
/// </summary>
/// <param name="filePath">The file path.</param>
/// <returns></returns>
public Task<PublishInfo> GetUpdatePackageFileInfo(string filePath)
{
return Task.Factory.StartNew<PublishInfo>(() =>
{
using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(filePath))
{
var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "version.json");
var reader = appEntry.OpenReader();
using (StreamReader stReader = new StreamReader(reader))
{
String json = stReader.ReadToEnd();
reader.Dispose();
return PublishInfo.FromJson(json);
}
}
});
}
/// <summary>
/// Checks whether any post update packages needs to be installed.
/// </summary>
/// <returns></returns>
public Task<bool> PostUpdatePackagesRequired()
{
String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages");
return _packageRunner.IsPackageInstallationRequired(PackageType.Post, packagesFolder);
}
/// <summary>
/// Runs all post update packages.
/// </summary>
/// <returns></returns>
public Task<PackageRunnerResult> RunPostUpdatePackages()
{
String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages");
Version previousVersion = null;
String str = _settings.PreviousApplicationVersion;
if (Version.TryParse(str, out previousVersion))
{
return _packageRunner.Run(PackageType.Post, previousVersion, packagesFolder);
}
else
{
throw new InvalidCastException($"Error parsing the previous version string '{str}'.");
}
}
#endregion
#region Protected Methods
protected virtual void UpdateProgress(String name, String message = "", bool isIntermediate = true, double progress = 0, double total = 0)
{
InvokeUINow(() =>
{
Status = new MachineUpdateProgress()
{
Name = name,
Message = message,
IsIntermediate = isIntermediate,
Progress = progress,
Total = total,
};
Progress?.Invoke(this, Status);
});
UIHelper.DoEvents();
}
#endregion
#region Auto Check For Update
private async void _checkForUpdateTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (EnableAutoCheckForUpdates && _settings.AutoCheckForUpdates && !_isUpdating)
{
_checkForUpdateTimer.Stop();
try
{
var response = await CheckForUpdate(_machineProvider.Machine.SerialNumber);
if (response.IsUpdateAvailable || response.IsDatabaseUpdateAvailable)
{
_checkForUpdateTimer.Interval = TimeSpan.FromMinutes(60).TotalMilliseconds;
LogManager.Log($"New {(response.IsDatabaseUpdateAvailable ? "database updates" : "application version")} detected ({response.Version}). Raising event...");
UpdateAvailable?.Invoke(this, response);
}
}
catch { }
_checkForUpdateTimer.Start();
}
}
#endregion
}
}