From 00a491d93733d4625ad329b2ba8237f445364b3f Mon Sep 17 00:00:00 2001 From: Mirta Date: Wed, 30 Dec 2020 16:39:52 +0200 Subject: merge --- .../MachineUpdate/MachineUpdateManager.cs | 1879 +++++--------------- 1 file changed, 400 insertions(+), 1479 deletions(-) (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs') diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs index c115f4f5b..b7573ec60 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs @@ -9,8 +9,6 @@ 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; @@ -18,47 +16,25 @@ 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; -using Tango.PPC.Common.ExternalBridge; -using Tango.Integration.ExternalBridge; -using Tango.BL.DTO; -using Tango.PPC.Shared.Updates; -using Tango.PPC.Shared.RemoteUpgrade; -using Tango.Core.Threading; namespace Tango.PPC.Common.MachineUpdate { - public class MachineUpdateManager : ExtendedObject, IMachineUpdateManager, IExternalBridgeRequestHandler + public class MachineUpdateManager : ExtendedObject, IMachineUpdateManager { private IPPCApplicationManager _app_manager; private IMachineProvider _machineProvider; - private IPackageRunner _packageRunner; private PPCWebClient _client; - private List _logs; - private System.Timers.Timer _checkForUpdateTimer; - private bool _isUpdating; - private PPCSettings _settings; - private DateTime _updateStartDate; #region Events - /// - /// Occurs when an application update is available. - /// - public event EventHandler UpdateAvailable; - /// /// Occurs when there is a text log message available. /// @@ -74,25 +50,12 @@ namespace Tango.PPC.Common.MachineUpdate #region Properties private MachineUpdateProgress _status; - /// - /// Gets the current machine update progress status. - /// public MachineUpdateProgress Status { get { return _status; } private set { _status = value; RaisePropertyChangedAuto(); } } - private bool _autoCheckForUpdates; - /// - /// Gets or sets a value indicating whether to automatically check for new application updates. - /// - public bool EnableAutoCheckForUpdates - { - get { return _autoCheckForUpdates; } - set { _autoCheckForUpdates = value; RaisePropertyChangedAuto(); } - } - #endregion #region Constructors @@ -101,1583 +64,592 @@ namespace Tango.PPC.Common.MachineUpdate /// Initializes a new instance of the class. /// /// The application manager. - public MachineUpdateManager(PPCWebClient ppcWebClient, IPPCApplicationManager applicationManager, IMachineProvider machineProvider, IPackageRunner packageRunner, IPPCExternalBridgeService externalBridge) + public MachineUpdateManager(PPCWebClient ppcWebClient, IPPCApplicationManager applicationManager, IMachineProvider machineProvider) { _client = ppcWebClient; _machineProvider = machineProvider; _app_manager = applicationManager; - _app_manager.ApplicationReady += _app_manager_ApplicationReady; - _packageRunner = packageRunner; - _packageRunner.PackageProgress += _packageRunner_PackageProgress; - - _logs = new List(); - LogManager.NewLog += LogManager_NewLog; - - _settings = SettingsManager.Default.GetOrCreate(); - - _checkForUpdateTimer = new System.Timers.Timer(_settings.AutoUpdateCheckInterval.TotalMilliseconds); - _checkForUpdateTimer.Elapsed += _checkForUpdateTimer_Elapsed; - _checkForUpdateTimer.Stop(); - - externalBridge.RegisterRequestHandler(this); - } - - #endregion - - #region Event Handlers - - private void _app_manager_ApplicationReady(object sender, EventArgs e) - { - _checkForUpdateTimer.Start(); - - if (!_app_manager.IsUpdateFailed) - { - ClearLastDatabaseBackup(); - } - } - - 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 machineGuid) + private Task Login(String serialNumber) { return _client.Login(new LoginRequest() { Mode = LoginMode.Machine, - MachineGuid = machineGuid, + SerialNumber = serialNumber, }); } - private async void OnFailed(Exception ex, TaskCompletionSource completionSource, DownloadUpdateResponse response, bool performDatabaseRollback, String dbBackupFile, String backupsFolder, String tempDbName, Tango.Core.DataSource localDataSource, String tempUpdatePackageFolder = null, PublishInfo tupPublishInfo = null) + #endregion + + #region Public Methods + + /// + /// Performs a machine update using the specified serial number and machine service address. + /// + /// The serial number. + /// if set to true updates the embedded device firmware. + /// if set to true updates the embedded device FPGA version and other parameters. + /// + /// + /// Could not perform an update while the machine is not connected. + /// or + /// or + /// + /// Database tango does not exists. + public async Task Update(String serialNumber, bool setupFirmware, bool setupFPGA) { - LogManager.Log(ex, "An error occurred in machine update."); + TaskCompletionSource result = new TaskCompletionSource(); + + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; + bool performDatabaseRollback = false; + String dbBackupFile = null; - await Task.Factory.StartNew(() => + try { + var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); - if (performDatabaseRollback) - { - LogManager.Log("Rolling back database changes..."); + LogManager.Log($"Starting machine update for serial number {serialNumber}..."); - 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 { } - } - } - } + //Connecting to machine... + LogManager.Log("Verifying machine connection and state..."); - 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."); - } - } + UpdateProgress("Verifying machine state", "Initializing..."); - try - { - Directory.Delete(backupsFolder, true); - } - catch (Exception ee) - { - LogManager.Log(ee, $"Error deleting backups folder '{backupsFolder}'."); - } + await Task.Delay(1000); + + IMachineOperator op = _machineProvider.MachineOperator; - if (tempUpdatePackageFolder != null) + if (setupFirmware) { - try + LogManager.Log("Machine is configured to update firmware..."); + + if (op.State != Transport.TransportComponentState.Connected) { - Directory.Delete(tempUpdatePackageFolder, true); + throw LogManager.Log(new InvalidOperationException("Could not perform an update while the machine is not connected.")); } - catch (Exception eee) + if (op.IsPrinting) { - LogManager.Log(eee, "Error removing temporary package folder."); + 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..."); - completionSource.SetException(ex); + LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - String logs = GetLogsStringAndClear(); + await Login(serialNumber); - 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."); - } + DownloadUpdateRequest request = new DownloadUpdateRequest(); + request.SerialNumber = serialNumber; - 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."); - } - } + DownloadUpdateResponse update_response = null; + + update_response = await _client.MachineUpdate(request); + LogManager.Log($"Machine update response received: {Environment.NewLine}{update_response.ToJsonString()}"); - if (tupPublishInfo != null) - { - try + //Create temporary folders for packages. + var _newPackageTempFolder = TemporaryManager.CreateFolder(); + _newPackageTempFolder.Persist = true; + + 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..."); + + long fileSize = 0; + UpdateProgress("Downloading software package", "Downloading...", false); + + using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => { - 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) + UpdateProgress("Downloading software package", "Downloading...", false, current, fileSize); + })) { - LogManager.Log(xxx, "Error saving tango offline update information to database."); + LogManager.Log($"Connecting to storage blob with address {update_response.BlobAddress}"); + CloudBlockBlob blob = new CloudBlockBlob(new Uri(update_response.BlobAddress)); + LogManager.Log("Fetching blob attributes..."); + blob.FetchAttributes(); + fileSize = blob.Properties.Length; + LogManager.Log("Download size: " + fileSize + " bytes."); + LogManager.Log("Starting blob download..."); + blob.DownloadToStream(fs); } - } - _isUpdating = false; - } + UpdateProgress("Downloading software package", "Extracting package..."); - private async void OnCompleted(MachineUpdateResult result, TaskCompletionSource completionSource, DownloadUpdateResponse response, String tempDbName, String backupsFolder, Core.DataSource localDataSource, PublishInfo tupPublishInfo = null) - { - await Task.Factory.StartNew(() => - { - if (tempDbName != null) + LogManager.Log("Extracting downloaded zip file..."); + //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); + + + //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)) { - 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."); - } + throw new InvalidProgramException("Database tango does not exists."); } - //try - //{ - // Directory.Delete(backupsFolder, true); - //} - //catch (Exception ex) - //{ - // LogManager.Log(ex, $"Error deleting backups folder '{backupsFolder}'."); - //} - - if (!result.RequiresBinariesUpdate) + if (setupFirmware) { + LogManager.Log("Setup firmware is active so a database rollback procedure should be configured."); + UpdateProgress("Updating Database", "Creating database backup..."); + try { - Directory.Delete(result.UpdatePackagePath, true); + Directory.CreateDirectory("C:\\Backups"); + dbBackupFile = $"C:\\Backups\\{Path.GetRandomFileName()}.bak"; + LogManager.Log($"Creating database backup to '{dbBackupFile}'..."); + await Task.Factory.StartNew(() => db.Backup(localDataSource.Catalog, dbBackupFile)); + LogManager.Log("Database backup created successfully."); } catch (Exception ex) { - LogManager.Log(ex, "Error removing temporary package folder."); + throw LogManager.Log(ex, "Setup manager error while trying to create a database backup."); } } - }); + LogManager.Log("Disposing database manager."); + db.Dispose(); - completionSource.SetResult(result); + LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}..."); - 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."); - } + UpdateProgress("Updating Database", "Initializing update sequence..."); - try + 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) => { - 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(msg); + ProgressLog?.Invoke(this, msg); + }; + + runner.ScriptExecuting += (x, item) => { - LogManager.Log(ex, "Error saving tango update information to database."); - } - } + LogManager.Log($"Executing script {item.ToString()}..."); + UpdateProgress("Updating Database", item.Name + "..."); + }; + LogManager.Log("Starting synchronization process..."); - 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(); - } + await runner.Run(); + LogManager.Log("Synchronization completed successfully!"); + UpdateProgress("Updating Database", "Database synchronization completed successfully."); } - catch (Exception xxx) + catch (Exception ex) { - LogManager.Log(xxx, "Error saving tango offline update information to database."); + throw LogManager.Log(ex, "Setup manager error while trying to synchronize database."); } - } - _isUpdating = false; - } + //Updating firmware + if (setupFirmware) + { + performDatabaseRollback = true; - private void OnFailed(Exception ex, UpdateDBResponse response, bool performDatabaseRollback, String dbBackupFile, Tango.Core.DataSource localDataSource) - { - LogManager.Log(ex, "An error occurred in database update."); + UpdateProgress("Updating Firmware", "Connecting to firmware device..."); + LogManager.Log(""); + LogManager.Log("-------------------------------------------------------------------------"); + LogManager.Log("Updating Firmware..."); - if (performDatabaseRollback) - { - LogManager.Log("Rolling back database changes..."); + UpdateProgress("Updating Firmware", "Loading firmware package..."); + var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp"); + var stream = new FileStream(tfpPath, FileMode.Open); - using (DbManager db = DbManager.FromDataSource(localDataSource)) - { - try + if (setupFPGA) { - UpdateProgress("Rollback", "Rolling back database changes..."); - db.Restore(localDataSource.Catalog, dbBackupFile); - LogManager.Log("Database restored successfully."); + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; } - catch (Exception e) + else { - LogManager.Log(e, "Could not rollback the database."); - throw ex; + op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; } - finally + + var handler = await op.UpgradeFirmware(stream); + handler.Failed += (_, ex) => { - try - { - File.Delete(dbBackupFile); - } - catch { } - } - } - } - - String logs = GetLogsStringAndClear(); - - if (response != null) - { - try - { - var r = _client.NotifyUpdateCompleted(new MachineUpdateCompletedRequest() + stream.Dispose(); + throw ex; + }; + handler.Completed += (_, __) => { - 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()) + UpdateProgress("Updating Firmware", "Firmware update completed successfully."); + stream.Dispose(); + result.SetResult(new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + }); + }; + handler.Canceled += (_, __) => { - 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(); - } + stream.Dispose(); + throw new Exception("The operation has been canceled."); + }; + handler.Progress += (_, e) => + { + UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total); + }; } - catch (Exception exx) + else { - LogManager.Log(exx, "Error saving database update information to database."); + result.SetResult(new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + }); } } - - _isUpdating = false; - } - - private void OnCompleted(UpdateDBResponse response, bool completedWithNoDifferences = false) - { - if (response != null) + catch (Exception ex) { - 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."); - } + LogManager.Log(ex, "An error occurred in machine update."); - if (!completedWithNoDifferences) + if (performDatabaseRollback) { - try + LogManager.Log("Rolling back database changes..."); + + using (DbManager db = DbManager.FromDataSource(localDataSource)) { - using (ObservablesContext db = ObservablesContext.CreateDefault()) + try { - 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(); + UpdateProgress("Rollback", "Rolling back database changes..."); + await Task.Factory.StartNew(() => 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 { } } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error saving database update information to database."); } } - } - - _isUpdating = false; - } - - private void OnFailed(Exception ex, TaskCompletionSource 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."); + result.SetException(ex); } - - _isUpdating = false; - } - - private void OnCompleted(TaskCompletionSource completionSource, String firmwareVersion) - { - LogManager.Log("Firmware upgrade completed successfully."); - completionSource.SetResult(true); - - try + finally { - using (ObservablesContext db = ObservablesContext.CreateDefault()) + try { - 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(); + File.Delete(dbBackupFile); } + catch { } } - 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; - } - - private void ClearLastDatabaseBackup() - { - Task.Factory.StartNew(() => - { - try - { - var lastBackupFile = SettingsManager.Default.GetOrCreate().LastDatabaseBackupFile; - if (File.Exists(lastBackupFile)) - { - File.Delete(lastBackupFile); - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error removing last database backup file."); - } - }); + return await result.Task; } - #endregion - - #region Public Methods - /// - /// Performs a machine update. + /// Checks if any update are available for the specified machine serial number. /// - /// if set to true updates the embedded device firmware. - /// if set to true updates the embedded device FPGA version and other parameters. + /// The serial number. + /// The machine service address. /// - /// - /// Could not perform an update while the machine is not connected. - /// or - /// or - /// - /// Database tango does not exists. - public async Task Update(bool setupFirmware, bool setupFPGA) + public Task CheckForUpdate(string serialNumber) { - _updateStartDate = DateTime.UtcNow; - _logs.Clear(); - - TaskCompletionSource result = new TaskCompletionSource(); - - var localDataSource = SettingsManager.Default.GetOrCreate().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 machineGuid = _machineProvider.Machine.Guid; - - try + return Task.Factory.StartNew(() => { - _isUpdating = true; - - var machineServiceAddress = _settings.GetMachineServiceAddress(); - - LogManager.Log($"Starting machine update..."); - - //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..."); + var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - await Login(machineGuid); - - DownloadUpdateRequest request = new DownloadUpdateRequest(); - - 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..."); + Login(serialNumber).GetAwaiter().GetResult(); - await Task.Factory.StartNew(() => - { - //Extract software package. - ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder); - }); + LogManager.Log($"Checking if updates available..."); - 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); + CheckForUpdateRequest request = new CheckForUpdateRequest(); + request.SerialNumber = serialNumber; + request.Version = _app_manager.Version.ToString(); - LogManager.Log("Initializing database manager..."); - DbManager db = DbManager.FromDataSource(localDataSource); + CheckForUpdateResponse update_response = null; - //Create Database Backup - UpdateProgress("Updating Database", "Creating database backup..."); - try - { - Directory.CreateDirectory(backupsFolder); - dbBackupFile = $"{backupsFolder}\\{Path.GetRandomFileName()}.bak"; - _settings.LastDatabaseBackupFile = dbBackupFile; - _settings.Save(); - 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."); - } + update_response = _client.CheckForUpdates(request).Result; - //Run pre-update packages. - try - { - UpdateProgress("Preparing", "Running update packages..."); - LogManager.Log("Running pre-update packages..."); - var packagesFolder = Path.Combine(_newPackageTempFolder, "Packages"); + LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}"); - 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."); - } + return update_response; + }); + } - await _packageRunner.Run(PackageType.Pre, updateVersion, packagesFolder); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error running pre-update packages..."); - } + /// + /// Updates all the "overwrite-able" database tables. + /// + /// The serial number. + /// The machine service address. + /// + public Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber) + { + return Task.Factory.StartNew(() => + { + LogManager.Log("Starting database update..."); - //Synchronize database UpdateProgress("Updating Database", "Initializing..."); - LogManager.Log($"Synchronizing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + LogManager.Log("Looking for update scripts configuration on application path..."); - UpdateProgress("Updating Database", "Connecting to local database..."); + String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); - LogManager.Log("Checking Tango database exists on the local machine..."); - if (!db.Exists(localDataSource.Catalog)) + if (!File.Exists(config_file)) { - throw new InvalidProgramException("Database tango does not exists."); + throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); } - LogManager.Log("Disposing database manager."); - db.Dispose(); - - LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}..."); - - UpdateProgress("Updating Database", "Initializing update sequence..."); + UpdateDBResponse update_response = dbCompareResult.UpdateDBResponse; - ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner( - Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"), - Path.Combine(_newPackageTempFolder, "Update Scripts"), - update_response.DataSource, - localDataSource, - machineGuid); - - 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 (setupFPGA) - { - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; - } - else - { - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; - } - - var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); - 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, e.IsIndeterminate, 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; - } - - /// - /// Checks if any update are available for the specified machine. - /// - /// The machine service address. - /// - public Task CheckForUpdate() - { - return Task.Factory.StartNew(() => - { - _isUpdating = true; - - var machineServiceAddress = _settings.GetMachineServiceAddress(); - - LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - - String machineGuid = _machineProvider.Machine.Guid; - - Login(machineGuid).GetAwaiter().GetResult(); - - LogManager.Log($"Checking if updates available..."); - - CheckForUpdateRequest request = new CheckForUpdateRequest(); - request.Version = _app_manager.Version.ToString(); - request.FirmwareVersion = _app_manager.FirmwareVersion?.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; - }); - } - - /// - /// Updates all the "overwrite-able" database tables. - /// - /// The machine service address. - /// - public Task UpdateDB(DbCompareResult dbCompareResult) - { - _updateStartDate = DateTime.UtcNow; - _logs.Clear(); - - return Task.Factory.StartNew(() => - { - _isUpdating = true; - UpdateDBResponse update_response = null; - var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; - bool performDatabaseRollback = false; - String dbBackupFile = null; - - try - { - LogManager.Log("Starting database update..."); - - if (_machineProvider.MachineOperator.IsPrinting) - { - throw LogManager.Log(new InvalidOperationException($"Could not perform a database update while the machine is dyeing.")); - } - - 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(_machineProvider.Machine.Guid); - } - - 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; - } - }); - } - - /// - /// Checks whether it is necessary to updates all the "overwrite-able" database tables. - /// - /// The machine service address. - /// - public Task UpdateDBCheck() - { - return Task.Factory.StartNew(() => - { - var machineServiceAddress = _settings.GetMachineServiceAddress(); - - LogManager.Log($"Checking if database update is required..."); - - 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(_machineProvider.Machine.Guid).Wait(); - - UpdateDBRequest request = new UpdateDBRequest(); - 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().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(_machineProvider.Machine.Guid); - } - - 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, - }; - }); - } - - /// - /// Performs a machine update using the specified software update package path. - /// - /// Name of the file. - /// - public async Task UpdateFromTUP(string fileName, bool setupFirmware, bool setupFPGA) - { - _updateStartDate = DateTime.UtcNow; - _logs.Clear(); - - TaskCompletionSource result = new TaskCompletionSource(); - - var localDataSource = SettingsManager.Default.GetOrCreate().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 (TUP) 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, - _machineProvider.Machine.Guid); - - 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."); - } + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; - LogManager.Log("Getting setup firmware/fpga directly from db.."); + LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); - 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"); + UpdateProgress("Updating Database", "Initializing update sequence..."); - setupFirmware = bool.Parse(firmware); - setupFPGA = bool.Parse(fpga); - } - catch (Exception ex) - { - LogManager.Log(ex, "Error getting new values of SETUP_FIRMWARE and SETUP_FPGA."); - } - } + ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); - //Updating firmware - if (setupFirmware) + foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data || update_response.PerformSchemaUpdate).OrderBy(x => x.Index)) { - UpdateProgress("Updating Firmware", "Connecting to firmware device..."); - LogManager.Log(""); - LogManager.Log("-------------------------------------------------------------------------"); - LogManager.Log("Updating Firmware..."); + LogManager.Log($"Executing update script '{item.FileName}...'"); - UpdateProgress("Updating Firmware", "Loading firmware package..."); - var tfpPath = Path.Combine(_newPackageTempFolder, "firmware_package.tfp"); - var stream = new FileStream(tfpPath, FileMode.Open); + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); + builder.SetSource(update_response.DataSource); + builder.SetTarget(localDataSource); - if (setupFPGA) - { - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; - } - else + if (item.RequiresSerialNumber) { - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; + builder.SetMachineSerialNumber(serialNumber); } - var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); - handler.Failed += (_, ex) => + builder.Synchronize(); + + var config = builder.Build(); + + ExaminerProcess process = new ExaminerProcess(config, item.Type == ExaminerSequenceItemType.Data ? ExaminerProcessType.Data : ExaminerProcessType.Schema); + process.Progress += (x, msg) => { - stream.Dispose(); - OnFailed(ex, result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo); + LogManager.Log(msg); }; - handler.Completed += (_, __) => + + try { - UpdateProgress("Updating Firmware", "Firmware update completed successfully."); - stream.Dispose(); - OnCompleted(new MachineUpdateResult() + UpdateProgress("Updating Database", item.Name + "..."); + + var result = process.Execute().Result; + + if (result.ExitCode != ExaminerProcessExitCode.Success) { - 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, e.IsIndeterminate, e.Current, e.Total); - }; - } - else - { - OnCompleted(new MachineUpdateResult() + throw LogManager.Log(new InvalidDataException($"{item.FileName} script has terminated with exit code '{result.ExitCode}'.")); + } + + LogManager.Log("Script executed successfully."); + } + catch (Exception ex) { - UpdatePackagePath = _newPackageTempFolder, - RequiresBinariesUpdate = replaceBinaries, - }, result, null, tempDbName, backupsFolder, localDataSource, publishInfo); + throw LogManager.Log(ex, "Setup manager error while trying to update the database."); + } } - } - catch (Exception ex) - { - OnFailed(ex, result, null, performDatabaseRollback, dbBackupFile, backupsFolder, tempDbName, localDataSource, _newPackageTempFolder, publishInfo); - } - return await result.Task; + UpdateProgress("Updating Database", "Database synchronization completed successfully."); + LogManager.Log("Update completed successfully."); + }); } /// - /// Performs a firmware upgrade from the specified TFP file. + /// Checks whether it is necessary to updates all the "overwrite-able" database tables. /// - /// Name of the file. + /// The serial number. + /// The machine service address. /// - /// - /// Could not perform a firmware upgrade while the machine is not connected. - /// or - /// - public async Task UpdateFromTFP(String fileName) + public Task UpdateDBCheck(string serialNumber) { - _updateStartDate = DateTime.UtcNow; - _logs.Clear(); + return Task.Factory.StartNew(() => + { + var machineServiceAddress = SettingsManager.Default.GetOrCreate().GetMachineServiceAddress(); - TaskCompletionSource result = new TaskCompletionSource(); + LogManager.Log($"Checking if database update is required for serial number {serialNumber}..."); - String version = String.Empty; - Stream stream = null; + LogManager.Log("Looking for update scripts configuration on application path..."); - try - { - _isUpdating = true; + String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); - IMachineOperator op = _machineProvider.MachineOperator; + if (!File.Exists(config_file)) + { + throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); + } - UpdateProgress("Updating Firmware", "Loading firmware package..."); - stream = new FileStream(fileName, FileMode.Open); + LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - var packageInfo = await op.GetFirmwarePackageInfo(stream); - stream.Position = 0; - version = packageInfo.FileDescriptors.FirstOrDefault(x => x.Destination == PMR.FirmwareUpgrade.VersionFileDestination.Mcu)?.Version; + Login(serialNumber).Wait(); - LogManager.Log("Verifying machine connection and state..."); + UpdateDBRequest request = new UpdateDBRequest(); + request.SerialNumber = serialNumber; - UpdateProgress("Verifying machine state", "Initializing..."); + UpdateDBResponse update_response = null; - await Task.Delay(1000); + update_response = _client.UpdateDB(request).Result; - 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.")); - } + LogManager.Log($"Update DB response received: {Environment.NewLine}{update_response.ToJsonString()}"); - UpdateProgress("Updating Firmware", "Connecting to firmware device..."); - LogManager.Log(""); - LogManager.Log("-------------------------------------------------------------------------"); - LogManager.Log("Updating Firmware..."); + var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; + LogManager.Log($"Comparing database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); - var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); - 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, e.IsIndeterminate, e.Current, e.Total); - }; - } - catch (Exception ex) - { - try + 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)) { - if (stream != null) + 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) { - stream.Dispose(); + builder.SetMachineSerialNumber(serialNumber); } - } - catch { } - OnFailed(ex, result, version); - } + var config = builder.Build(); - await result.Task; - } + ExaminerProcess process = new ExaminerProcess(config, ExaminerProcessType.Data); + process.Progress += (x, msg) => + { + LogManager.Log(msg); + }; - /// - /// Gets the update package file information. - /// - /// The file path. - /// - public Task GetUpdatePackageFileInfo(string filePath) - { - return Task.Factory.StartNew(() => - { - using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(filePath)) - { - var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "version.json"); - var reader = appEntry.OpenReader(); + LogManager.Log("Starting comparison process..."); + LogManager.Log("Generating report on " + report_file); - using (StreamReader stReader = new StreamReader(reader)) + try { - String json = stReader.ReadToEnd(); - reader.Dispose(); + 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..."); - return PublishInfo.FromJson(json); + 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) + { + throw LogManager.Log(ex, "Update manager error while trying to compare the database."); } } + + LogManager.Log("Comparison completed successfully."); + + return new DbCompareResult() + { + RequiresUpdate = has_differences, + UpdateDBResponse = update_response, + }; }); } /// - /// Checks whether any post update packages needs to be installed. + /// Performs a machine update using the specified software update package path. /// + /// Name of the file. /// - public Task PostUpdatePackagesRequired() + public Task UpdateFromTUP(string fileName) { - String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages"); - return _packageRunner.IsPackageInstallationRequired(PackageType.Post, packagesFolder); - } + return Task.Factory.StartNew(() => + { + LogManager.Log($"Starting machine update from update package '{fileName}'..."); - /// - /// Runs all post update packages. - /// - /// - public Task RunPostUpdatePackages() - { - String packagesFolder = Path.Combine(AssemblyHelper.GetCurrentAssemblyFolder(), "packages"); + //Create temporary folders for packages. + var _newPackageTempFolder = TemporaryManager.CreateFolder(); + _newPackageTempFolder.Persist = true; - Version previousVersion = null; - String str = _settings.PreviousApplicationVersion; + LogManager.Log("Extracting downloaded zip file..."); + //Extract software package. + ZipFile.ExtractToDirectory(fileName, _newPackageTempFolder); - if (Version.TryParse(str, out previousVersion)) - { - return _packageRunner.Run(PackageType.Post, previousVersion, packagesFolder); - } - else - { - throw new InvalidCastException($"Error parsing the previous version string '{str}'."); - } + 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); + + LogManager.Log("Update operation completed!"); + + return new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + }; + }); } - public Task RestoreLastDatabaseBackup() + /// + /// Gets the update package file information. + /// + /// The file path. + /// + public Task GetUpdatePackageFileInfo(string filePath) { - return Task.Factory.StartNew(() => + return Task.Factory.StartNew(() => { - LogManager.Log("Rolling back database changes..."); - UpdateProgress("Rollback", "Rolling back database changes..."); - - var localDataSource = SettingsManager.Default.GetOrCreate().DataSource; - var lastBackupFile = SettingsManager.Default.GetOrCreate().LastDatabaseBackupFile; + UpdatePackageFile file = new UpdatePackageFile(); + var tempFolder = TemporaryManager.CreateFolder(); - using (DbManager db = DbManager.FromDataSource(localDataSource)) + using (Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile(filePath)) { - try - { - db.Restore(localDataSource.Catalog, lastBackupFile); - LogManager.Log("Database restored successfully."); - } - catch (Exception ex) - { - LogManager.Log(ex, "Could not rollback the database after a failed updater."); - throw ex; - } - finally - { - try - { - File.Delete(lastBackupFile); - } - catch { } - } + var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "Tango.PPC.UI.exe"); + appEntry.Extract(tempFolder); } + + FileVersionInfo info = FileVersionInfo.GetVersionInfo(Path.Combine(tempFolder, "Tango.PPC.UI.exe")); + file.Version = Version.Parse(info.ProductVersion); + + tempFolder.Delete(); + + return file; }); } @@ -1705,56 +677,5 @@ namespace Tango.PPC.Common.MachineUpdate } #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(); - if (response.IsUpdateAvailable || response.IsDatabaseUpdateAvailable) - { - LogManager.Log($"New {(response.IsDatabaseUpdateAvailable ? "database updates" : "application version")} detected ({response.Version}). Raising event..."); - UpdateAvailable?.Invoke(this, response); - } - } - catch { } - - _checkForUpdateTimer.Start(); - } - } - - #endregion - - #region External Bridge - - public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) - { - //Do nothing. - } - - [ExternalBridgeRequestHandlerMethod(typeof(GetUpdatesAndPackagesRequest), RequestHandlerLoggingMode.LogRequestName)] - public async Task OnGetUpdatesAndPackagesRequest(GetUpdatesAndPackagesRequest request, String token, ExternalBridgeReceiver receiver) - { - using (ObservablesContext db = ObservablesContext.CreateDefault()) - { - var updates = await db.TangoUpdates.OrderByDescending(x => x.StartDate).ToListAsync(); - var updatesDTO = updates.Select(x => TangoUpdateDTO.FromObservable(x)).ToList(); - var packages = (await _packageRunner.GetPackagesFile()).PackageInstallations; - - var response = new GetUpdatesAndPackagesResponse(); - response.Updates.AddRange(updatesDTO); - response.Packages.AddRange(packages); - - await receiver.SendGenericResponse(response, token); - } - } - - #endregion } } -- cgit v1.3.1