diff options
Diffstat (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate')
4 files changed, 210 insertions, 1326 deletions
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs index 7c835165f..85d61d4cc 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/IMachineUpdateManager.cs @@ -4,27 +4,12 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.PMR.Synchronization; -using Tango.PPC.Common.Publish; -using Tango.PPC.Common.UpdatePackages; using Tango.PPC.Common.Web; namespace Tango.PPC.Common.MachineUpdate { public interface IMachineUpdateManager { - /// <summary> - /// Occurs when an application update is available. - /// </summary> - event EventHandler<CheckForUpdateResponse> UpdateAvailable; - - /// <summary> - /// Gets or sets a value indicating whether to automatically check for new application updates. - /// </summary> - bool EnableAutoCheckForUpdates { get; set; } - - /// <summary> - /// Gets the current machine update progress status. - /// </summary> MachineUpdateProgress Status { get; } /// <summary> @@ -38,68 +23,46 @@ namespace Tango.PPC.Common.MachineUpdate event EventHandler<MachineUpdateProgress> Progress; /// <summary> - /// Performs a machine update. + /// 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> - Task<MachineUpdateResult> Update(bool setupFirmware, bool setupFPGA); + Task<MachineUpdateResult> Update(String serialNumber, bool setupFirmware, bool setupFPGA); /// <summary> /// Performs a machine update using the specified software update package path. /// </summary> /// <param name="fileName">Name of the file.</param> /// <returns></returns> - Task<MachineUpdateResult> UpdateFromTUP(String fileName, bool setupFirmware, bool setupFPGA); - - /// <summary> - /// Performs a firmware upgrade from the specified TFP file. - /// </summary> - /// <param name="fileName">Name of the file.</param> - /// <returns></returns> - Task UpdateFromTFP(String fileName); + Task<MachineUpdateResult> UpdateFromTUP(String fileName); /// <summary> - /// Checks if any update are available. + /// Checks if any update are available for the specified machine serial number. /// </summary> + /// <param name="serialNumber">The serial number.</param> /// <returns></returns> - Task<CheckForUpdateResponse> CheckForUpdate(); + Task<CheckForUpdateResponse> CheckForUpdate(String serialNumber); /// <summary> /// Checks whether it is necessary to updates all the "overwrite-able" database tables. /// </summary> + /// <param name="serialNumber">The serial number.</param> /// <returns></returns> - Task<DbCompareResult> UpdateDBCheck(); + Task<DbCompareResult> UpdateDBCheck(String serialNumber); /// <summary> /// Updates all the "overwrite-able" database tables. /// </summary> /// <returns></returns> - Task UpdateDB(DbCompareResult dbCompareResult); + Task UpdateDB(DbCompareResult dbCompareResult, String serialNumber); /// <summary> /// Gets the update package file information. /// </summary> /// <param name="filePath">The file path.</param> /// <returns></returns> - Task<PublishInfo> GetUpdatePackageFileInfo(String filePath); - - /// <summary> - /// Checks whether any post update packages needs to be installed. - /// </summary> - /// <returns></returns> - Task<bool> PostUpdatePackagesRequired(); - - /// <summary> - /// Runs all post update packages. - /// </summary> - /// <returns></returns> - Task<PackageRunnerResult> RunPostUpdatePackages(); - - /// <summary> - /// Restores the last database backup. - /// </summary> - /// <returns></returns> - Task RestoreLastDatabaseBackup(); + Task<UpdatePackageFile> GetUpdatePackageFileInfo(String filePath); } } 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,48 +16,26 @@ 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<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; @@ -74,25 +50,12 @@ namespace Tango.PPC.Common.MachineUpdate #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 @@ -101,531 +64,23 @@ namespace Tango.PPC.Common.MachineUpdate /// 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, 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<LogItemBase>(); - LogManager.NewLog += LogManager_NewLog; - - _settings = SettingsManager.Default.GetOrCreate<PPCSettings>(); - - _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, - }); - } - - 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; - } - - private void ClearLastDatabaseBackup() - { - Task.Factory.StartNew(() => - { - try - { - var lastBackupFile = SettingsManager.Default.GetOrCreate<PPCSettings>().LastDatabaseBackupFile; - - if (File.Exists(lastBackupFile)) - { - File.Delete(lastBackupFile); - } - } - catch (Exception ex) - { - LogManager.Log(ex, "Error removing last database backup file."); - } + SerialNumber = serialNumber, }); } @@ -634,8 +89,9 @@ namespace Tango.PPC.Common.MachineUpdate #region Public Methods /// <summary> - /// Performs a machine update. + /// 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> @@ -645,32 +101,19 @@ namespace Tango.PPC.Common.MachineUpdate /// or /// </exception> /// <exception cref="System.InvalidProgramException">Database tango does not exists.</exception> - public async Task<MachineUpdateResult> Update(bool setupFirmware, bool setupFPGA) + public async Task<MachineUpdateResult> Update(String serialNumber, 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 machineGuid = _machineProvider.Machine.Guid; try { - _isUpdating = true; - - var machineServiceAddress = _settings.GetMachineServiceAddress(); + var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress(); - LogManager.Log($"Starting machine update..."); + LogManager.Log($"Starting machine update for serial number {serialNumber}..."); //Connecting to machine... LogManager.Log("Verifying machine connection and state..."); @@ -689,11 +132,10 @@ namespace Tango.PPC.Common.MachineUpdate { 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.")); + if (op.IsPrinting) + { + 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. @@ -701,14 +143,21 @@ namespace Tango.PPC.Common.MachineUpdate LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - await Login(machineGuid); + await Login(serialNumber); DownloadUpdateRequest request = new DownloadUpdateRequest(); + request.SerialNumber = serialNumber; + + DownloadUpdateResponse update_response = null; update_response = await _client.MachineUpdate(request); LogManager.Log($"Machine update response received: {Environment.NewLine}{update_response.ToJsonString()}"); + //Create temporary folders for packages. + var _newPackageTempFolder = TemporaryManager.CreateFolder(); + _newPackageTempFolder.Persist = true; + LogManager.Log($"Temporary package folder created: {_newPackageTempFolder}."); //Download software package. @@ -718,102 +167,68 @@ namespace Tango.PPC.Common.MachineUpdate LogManager.Log("Downloading software package..."); + long fileSize = 0; UpdateProgress("Downloading software package", "Downloading...", false); - using (AutoFileDownloader downloader = new AutoFileDownloader(update_response.BlobAddress, update_response.CdnAddress, tempFile)) + using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => { - 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", "Downloading...", false, current, fileSize); + })) + { + 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); } UpdateProgress("Downloading software package", "Extracting package..."); LogManager.Log("Extracting downloaded zip file..."); + //Extract software package. + ZipFile.ExtractToDirectory(tempFile, _newPackageTempFolder); - 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); + + //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); - //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) + LogManager.Log("Checking Tango database exists on the local machine..."); + if (!db.Exists(localDataSource.Catalog)) { - throw LogManager.Log(ex, "Update manager error while trying to create a database backup."); + throw new InvalidProgramException("Database tango does not exists."); } - //Run pre-update packages. - try + if (setupFirmware) { - UpdateProgress("Preparing", "Running update packages..."); - LogManager.Log("Running pre-update packages..."); - var packagesFolder = Path.Combine(_newPackageTempFolder, "Packages"); + LogManager.Log("Setup firmware is active so a database rollback procedure should be configured."); + UpdateProgress("Updating Database", "Creating database backup..."); - Version updateVersion = new Version(1, 0, 0, 0); try { - updateVersion = Version.Parse(update_response.Version); + 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 parsing new version string for package runner."); + throw LogManager.Log(ex, "Setup manager error while trying to create a database backup."); } - - 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("Checking Tango database exists on the local machine..."); - if (!db.Exists(localDataSource.Catalog)) - { - throw new InvalidProgramException("Database tango does not exists."); } LogManager.Log("Disposing database manager."); @@ -828,7 +243,7 @@ namespace Tango.PPC.Common.MachineUpdate Path.Combine(_newPackageTempFolder, "Update Scripts"), update_response.DataSource, localDataSource, - machineGuid); + serialNumber); runner.Log += (x, msg) => { @@ -852,12 +267,14 @@ namespace Tango.PPC.Common.MachineUpdate } catch (Exception ex) { - throw LogManager.Log(ex, "Update manager error while trying to synchronize database."); + throw LogManager.Log(ex, "Setup manager error while trying to synchronize database."); } //Updating firmware if (setupFirmware) { + performDatabaseRollback = true; + UpdateProgress("Updating Firmware", "Connecting to firmware device..."); LogManager.Log(""); LogManager.Log("-------------------------------------------------------------------------"); @@ -876,88 +293,106 @@ namespace Tango.PPC.Common.MachineUpdate op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU; } - var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); + var handler = await op.UpgradeFirmware(stream); handler.Failed += (_, ex) => { stream.Dispose(); - OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder); + throw ex; }; handler.Completed += (_, __) => { UpdateProgress("Updating Firmware", "Firmware update completed successfully."); stream.Dispose(); - OnCompleted(new MachineUpdateResult() + result.SetResult(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); + throw new Exception("The operation has been canceled."); }; handler.Progress += (_, e) => { - UpdateProgress("Updating Firmware", e.Message, e.IsIndeterminate, e.Current, e.Total); + UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total); }; } else { - OnCompleted(new MachineUpdateResult() + result.SetResult(new MachineUpdateResult() { UpdatePackagePath = _newPackageTempFolder, - }, result, update_response, null, backupsFolder, localDataSource); + }); } } catch (Exception ex) { - OnFailed(ex, result, update_response, performDatabaseRollback, dbBackupFile, backupsFolder, null, localDataSource, _newPackageTempFolder); + LogManager.Log(ex, "An error occurred in machine update."); + + if (performDatabaseRollback) + { + LogManager.Log("Rolling back database changes..."); + + using (DbManager db = DbManager.FromDataSource(localDataSource)) + { + try + { + 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 { } + } + } + } + + result.SetException(ex); + } + finally + { + try + { + File.Delete(dbBackupFile); + } + catch { } } return await result.Task; } /// <summary> - /// Checks if any update are available for the specified machine. + /// 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() + public Task<CheckForUpdateResponse> CheckForUpdate(string serialNumber) { return Task.Factory.StartNew<CheckForUpdateResponse>(() => { - _isUpdating = true; - - var machineServiceAddress = _settings.GetMachineServiceAddress(); + var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress(); LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - String machineGuid = _machineProvider.Machine.Guid; - - Login(machineGuid).GetAwaiter().GetResult(); + Login(serialNumber).GetAwaiter().GetResult(); LogManager.Log($"Checking if updates available..."); CheckForUpdateRequest request = new CheckForUpdateRequest(); + request.SerialNumber = serialNumber; 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; @@ -965,8 +400,6 @@ namespace Tango.PPC.Common.MachineUpdate LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}"); - _isUpdating = false; - return update_response; }); } @@ -974,145 +407,96 @@ namespace Tango.PPC.Common.MachineUpdate /// <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) + 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; + LogManager.Log("Starting database update..."); - try - { - LogManager.Log("Starting database update..."); + UpdateProgress("Updating Database", "Initializing..."); - if (_machineProvider.MachineOperator.IsPrinting) - { - throw LogManager.Log(new InvalidOperationException($"Could not perform a database update while the machine is dyeing.")); - } + LogManager.Log("Looking for update scripts configuration on application path..."); - UpdateProgress("Updating Database", "Initializing..."); + String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); - LogManager.Log("Looking for update scripts configuration on application path..."); + if (!File.Exists(config_file)) + { + throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); + } - String config_file = Path.Combine(PathHelper.GetStartupPath(), "Update Scripts", "config.xml"); + UpdateDBResponse update_response = dbCompareResult.UpdateDBResponse; - if (!File.Exists(config_file)) - { - throw LogManager.Log(new FileNotFoundException($"Could not locate '{config_file}' file on application folder.")); - } + var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource; - update_response = dbCompareResult.UpdateDBResponse; + LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); - LogManager.Log($"Updating database '{update_response.DataSource.ToString()}' => '{localDataSource.ToString()}'..."); + UpdateProgress("Updating Database", "Initializing update sequence..."); - UpdateProgress("Updating Database", "Initializing update sequence..."); + ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); - ExaminerSequenceConfiguration config_sequence = ExaminerSequenceConfiguration.FromFile(config_file); + 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}...'"); - UpdateProgress("Updating Database", "Connecting to local database..."); - LogManager.Log("Initializing database manager..."); - DbManager db = DbManager.FromDataSource(localDataSource); + ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); + builder.SetSource(update_response.DataSource); + builder.SetTarget(localDataSource); - LogManager.Log("Checking Tango database exists on the local machine..."); - if (!db.Exists(localDataSource.Catalog)) + if (item.RequiresSerialNumber) { - throw new InvalidProgramException("Database tango does not exists."); + builder.SetMachineSerialNumber(serialNumber); } - UpdateProgress("Updating Database", "Creating database backup..."); + builder.Synchronize(); - //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."); - } + var config = builder.Build(); - LogManager.Log("Disposing database manager."); - db.Dispose(); + ExaminerProcess process = new ExaminerProcess(config, item.Type == ExaminerSequenceItemType.Data ? ExaminerProcessType.Data : ExaminerProcessType.Schema); + process.Progress += (x, msg) => + { + LogManager.Log(msg); + }; - foreach (var item in config_sequence.Items.Where(x => x.Type == ExaminerSequenceItemType.Data || update_response.PerformSchemaUpdate).OrderBy(x => x.Index)) + try { - LogManager.Log($"Executing update script '{item.FileName}...'"); + UpdateProgress("Updating Database", item.Name + "..."); - ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(Path.Combine(Path.GetDirectoryName(config_file), item.FileName)); - builder.SetSource(update_response.DataSource); - builder.SetTarget(localDataSource); + var result = process.Execute().Result; - if (item.RequiresSerialNumber) + if (result.ExitCode != ExaminerProcessExitCode.Success) { - builder.SetMachineSerialNumber(_machineProvider.Machine.Guid); + throw LogManager.Log(new InvalidDataException($"{item.FileName} script has terminated with exit code '{result.ExitCode}'.")); } - 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."); - } + LogManager.Log("Script executed successfully."); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Setup 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; } + + UpdateProgress("Updating Database", "Database synchronization completed successfully."); + LogManager.Log("Update completed successfully."); }); } /// <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() + public Task<DbCompareResult> UpdateDBCheck(string serialNumber) { return Task.Factory.StartNew<DbCompareResult>(() => { - var machineServiceAddress = _settings.GetMachineServiceAddress(); + var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress(); - LogManager.Log($"Checking if database update is required..."); + LogManager.Log($"Checking if database update is required for serial number {serialNumber}..."); LogManager.Log("Looking for update scripts configuration on application path..."); @@ -1125,11 +509,10 @@ namespace Tango.PPC.Common.MachineUpdate LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); - Login(_machineProvider.Machine.Guid).Wait(); + Login(serialNumber).Wait(); UpdateDBRequest request = new UpdateDBRequest(); - request.ApplicationVersion = _app_manager.Version.ToString(); - request.FirmwareVersion = _app_manager.FirmwareVersion.ToString(); + request.SerialNumber = serialNumber; UpdateDBResponse update_response = null; @@ -1158,7 +541,7 @@ namespace Tango.PPC.Common.MachineUpdate if (item.RequiresSerialNumber) { - builder.SetMachineSerialNumber(_machineProvider.Machine.Guid); + builder.SetMachineSerialNumber(serialNumber); } var config = builder.Build(); @@ -1197,18 +580,12 @@ namespace Tango.PPC.Common.MachineUpdate } 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, @@ -1222,373 +599,31 @@ namespace Tango.PPC.Common.MachineUpdate /// </summary> /// <param name="fileName">Name of the file.</param> /// <returns></returns> - public async Task<MachineUpdateResult> UpdateFromTUP(string fileName, bool setupFirmware, bool setupFPGA) + public Task<MachineUpdateResult> UpdateFromTUP(string fileName) { - _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 + return Task.Factory.StartNew<MachineUpdateResult>(() => { - _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; + LogManager.Log($"Starting machine update from update package '{fileName}'..."); - 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."); - } + //Create temporary folders for packages. + var _newPackageTempFolder = TemporaryManager.CreateFolder(); + _newPackageTempFolder.Persist = true; - 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("Extracting downloaded zip file..."); + //Extract software package. + ZipFile.ExtractToDirectory(fileName, _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(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."); - } - - 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 (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, 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, e.IsIndeterminate, 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..."); + LogManager.Log("Update operation completed!"); - op.FirmwareUpgradeMode = FirmwareUpgradeModes.DFU | FirmwareUpgradeModes.TFP_PACKAGE; - - var handler = await op.UpgradeFirmware(stream, _machineProvider.Machine.IsDemo); - handler.Failed += (_, ex) => - { - stream.Dispose(); - OnFailed(ex, result, version); - }; - handler.Completed += (_, __) => + return new MachineUpdateResult() { - UpdateProgress("Updating Firmware", "Firmware update completed successfully."); - stream.Dispose(); - OnCompleted(result, version); + UpdatePackagePath = _newPackageTempFolder, }; - 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 - { - if (stream != null) - { - stream.Dispose(); - } - } - catch { } - - OnFailed(ex, result, version); - } - - await result.Task; + }); } /// <summary> @@ -1596,88 +631,25 @@ namespace Tango.PPC.Common.MachineUpdate /// </summary> /// <param name="filePath">The file path.</param> /// <returns></returns> - public Task<PublishInfo> GetUpdatePackageFileInfo(string filePath) + public Task<UpdatePackageFile> GetUpdatePackageFileInfo(string filePath) { - return Task.Factory.StartNew<PublishInfo>(() => + return Task.Factory.StartNew<UpdatePackageFile>(() => { + UpdatePackageFile file = new UpdatePackageFile(); + var tempFolder = TemporaryManager.CreateFolder(); + 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); - } + var appEntry = zip.Entries.SingleOrDefault(x => x.FileName == "Tango.PPC.UI.exe"); + appEntry.Extract(tempFolder); } - }); - } - - /// <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; + FileVersionInfo info = FileVersionInfo.GetVersionInfo(Path.Combine(tempFolder, "Tango.PPC.UI.exe")); + file.Version = Version.Parse(info.ProductVersion); - if (Version.TryParse(str, out previousVersion)) - { - return _packageRunner.Run(PackageType.Post, previousVersion, packagesFolder); - } - else - { - throw new InvalidCastException($"Error parsing the previous version string '{str}'."); - } - } + tempFolder.Delete(); - public Task RestoreLastDatabaseBackup() - { - return Task.Factory.StartNew(() => - { - LogManager.Log("Rolling back database changes..."); - UpdateProgress("Rollback", "Rolling back database changes..."); - - var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource; - var lastBackupFile = SettingsManager.Default.GetOrCreate<PPCSettings>().LastDatabaseBackupFile; - - using (DbManager db = DbManager.FromDataSource(localDataSource)) - { - 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 { } - } - } + 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 } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs index 85dd5b7d2..17ae394ee 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateResult.cs @@ -12,18 +12,5 @@ namespace Tango.PPC.Common.MachineUpdate /// Gets or sets the temporary update package path from which to get the last downloaded software version. /// </summary> public String UpdatePackagePath { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether the application should replace it's binaries. - /// </summary> - public bool RequiresBinariesUpdate { get; set; } - - /// <summary> - /// Initializes a new instance of the <see cref="MachineUpdateResult"/> class. - /// </summary> - public MachineUpdateResult() - { - RequiresBinariesUpdate = true; - } } } diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs new file mode 100644 index 000000000..df496c3be --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/UpdatePackageFile.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.PPC.Common.MachineUpdate +{ + public class UpdatePackageFile + { + public Version Version { get; set; } + } +} |
