diff options
| author | Roy Ben-Shabat <Roy@Twine-s.com> | 2018-08-30 19:04:18 +0300 |
|---|---|---|
| committer | Roy Ben-Shabat <Roy@Twine-s.com> | 2018-08-30 19:04:18 +0300 |
| commit | 37e5138e6acac4a9b93e018087fe9c50d36c4b34 (patch) | |
| tree | 4acec95a8e5362c67f0e0fc5444c40c23791776d /Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs | |
| parent | 3d9beda13daccac78fb05dc94d1430a0a47e9db6 (diff) | |
| download | Tango-37e5138e6acac4a9b93e018087fe9c50d36c4b34.tar.gz Tango-37e5138e6acac4a9b93e018087fe9c50d36c4b34.zip | |
Implemented machine update on PPC !!!
Need to verify update scripts...
Diffstat (limited to 'Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs')
| -rw-r--r-- | Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs new file mode 100644 index 000000000..b86fb88d4 --- /dev/null +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineUpdate/MachineUpdateManager.cs @@ -0,0 +1,287 @@ +using FluentFTP; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Tango.Core; +using Tango.Core.DB; +using Tango.Core.Helpers; +using Tango.Core.IO; +using Tango.PMR.Synchronization; +using Tango.PPC.Common.Application; +using Tango.Settings; +using Tango.SQLExaminer; +using Tango.Transport.Web; + +namespace Tango.PPC.Common.MachineUpdate +{ + public class MachineUpdateManager : ExtendedObject, IMachineUpdateManager + { + private IPPCApplicationManager _app_manager; + + #region Events + + /// <summary> + /// Occurs when there is a text log message available. + /// </summary> + public event EventHandler<string> ProgressLog; + + /// <summary> + /// Occurs when the <see cref="CurrentStep" /> has changed. + /// </summary> + public event EventHandler<MachineUpdateSteps> ProgressStep; + + #endregion + + #region Properties + + private MachineUpdateSteps _currentStep; + /// <summary> + /// Gets the current setup step. + /// </summary> + public MachineUpdateSteps CurrentStep + { + get { return _currentStep; } + set + { + if (_currentStep != value) + { + _currentStep = value; + RaisePropertyChangedAuto(); + ProgressStep?.Invoke(this, _currentStep); + LogManager.Log("Machine Setup Manager Step: " + value.ToString()); + } + } + } + + private double _downloadProgress; + /// <summary> + /// Gets the downloading packages step progress. + /// </summary> + public double DownloadingPackagesProgress + { + get { return _downloadProgress; } + private set { _downloadProgress = value; RaisePropertyChangedAuto(); } + } + + private String _updatingPackagesStatus; + /// <summary> + /// Gets the downloading packages step status. + /// </summary> + public String DownloadingPackagesStatus + { + get { return _updatingPackagesStatus; } + set { _updatingPackagesStatus = value; RaisePropertyChangedAuto(); } + } + + #endregion + + /// <summary> + /// Initializes a new instance of the <see cref="MachineUpdateManager"/> class. + /// </summary> + /// <param name="applicationManager">The application manager.</param> + public MachineUpdateManager(IPPCApplicationManager applicationManager) + { + _app_manager = applicationManager; + } + + #region Public Methods + + /// <summary> + /// Performs a machine setup using the specified serial number and machine service address. + /// </summary> + /// <param name="serialNumber">The serial number.</param> + /// <param name="machineServiceAddress">The machine service address.</param> + /// <returns></returns> + public Task<MachineUpdateResult> Update(string serialNumber, string machineServiceAddress) + { + return Task.Factory.StartNew<MachineUpdateResult>(() => + { + + LogManager.Log($"Starting machine update for serial number {serialNumber}..."); + + //Connect to machine service and get matching packages for this machine. + CurrentStep = MachineUpdateSteps.DownloadingPackage; + DownloadingPackagesProgress = 0; + DownloadingPackagesStatus = "Connecting to machine service..."; + + LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); + + DownloadUpdateRequest request = new DownloadUpdateRequest(); + request.SerialNumber = serialNumber; + + DownloadUpdateResponse update_response = null; + + using (var http = new ProtoWebClient()) + { + update_response = http.Post<DownloadUpdateRequest, DownloadUpdateResponse>(machineServiceAddress + "/api/Synchronization/MachineUpdate", request).Result; + } + + 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. + var tempFile = TemporaryManager.CreateFile(".zip"); + + LogManager.Log($"Temporary package zip file created: {tempFile}."); + + DownloadingPackagesStatus = "Downloading software package..."; + + LogManager.Log("Downloading software package..."); + + int fileSize = 0; + DownloadingPackagesProgress = 0; + + using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => + { + InvokeUINow(() => + { + Thread.Sleep(2); //TODO: this is necessary only for visibility... + DownloadingPackagesProgress = ((double)current / (double)fileSize) * 100d; + }); + })) + { + using (FtpClient ftp = new FtpClient(update_response.FtpAddress, update_response.FtpUserName, update_response.FtpPassword)) + { + LogManager.Log("FTP: Connecting to site: " + update_response.FtpAddress); + ftp.ConnectAsync().Wait(); + LogManager.Log("FTP: Retrieving download size..."); + fileSize = (int)ftp.GetFileSize(update_response.FtpFilePath); + LogManager.Log("FTP: Download size: " + fileSize + " bytes."); + LogManager.Log("FTP: Starting download..."); + ftp.DownloadAsync(fs, update_response.FtpFilePath).Wait(); + } + } + + 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 + CurrentStep = MachineUpdateSteps.SynchronizingSchema; + + String db_name = "Tango"; + String localAddress = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource.Address; + String remote_address = update_response.DbAddress; + + LogManager.Log($"Synchronizing database '{remote_address}\\{db_name}' => '{localAddress}\\{db_name}'..."); + + LogManager.Log("Initializing database manager..."); + DbManager db = DbManager.FromAddressAndName(localAddress, db_name); + + LogManager.Log("Checking Tango database exists on the local machine..."); + if (!db.Exists(db_name)) + { + throw new InvalidProgramException("Database tango does not exists."); + } + + LogManager.Log("Disposing database manager."); + db.Dispose(); + + LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}..."); + + ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner( + Path.Combine(_newPackageTempFolder, "Update Scripts", "config.xml"), + Path.Combine(_newPackageTempFolder, "Update Scripts"), + new ExaminerSequenceDataSource() + { + Address = remote_address, + DataBaseName = db_name, + IntegratedSecurity = false, + UserName = update_response.DbUserName, + Password = update_response.DbPassword, + }, + new ExaminerSequenceDataSource() + { + Address = localAddress, + DataBaseName = db_name, + IntegratedSecurity = true, + }, serialNumber); + + runner.Log += (x, msg) => + { + LogManager.Log(msg); + ProgressLog?.Invoke(this, msg); + }; + + runner.ScriptExecuting += (x, item) => + { + LogManager.Log($"Executing script {item.ToString()}..."); + + if (item.Type == ExaminerSequenceItemType.Data && item.RequiresSerialNumber) + { + CurrentStep = MachineUpdateSteps.SynchronizingMachineConfiguration; + } + else if (item.Type == ExaminerSequenceItemType.Data) + { + CurrentStep = MachineUpdateSteps.SynchronizingData; + } + }; + + LogManager.Log("Starting synchronization process..."); + + try + { + runner.Run().Wait(); + LogManager.Log("Synchronization completed successfully!"); + } + catch (Exception ex) + { + throw LogManager.Log(ex, "Setup manager error while trying to synchronize database."); + } + + return new MachineUpdateResult() + { + UpdatePackagePath = _newPackageTempFolder, + }; + }); + } + + /// <summary> + /// Checks if any update are available for the specified machine serial number. + /// </summary> + /// <param name="serialNumber">The serial number.</param> + /// <param name="machineServiceAddress">The machine service address.</param> + /// <returns></returns> + public Task<CheckForUpdateResponse> CheckForUpdate(string serialNumber, string machineServiceAddress) + { + return Task.Factory.StartNew<CheckForUpdateResponse>(() => + { + LogManager.Log($"Connecting to machine service on {machineServiceAddress}..."); + LogManager.Log($"Checking if updates available..."); + + CheckForUpdateRequest request = new CheckForUpdateRequest(); + request.SerialNumber = serialNumber; + request.Version = _app_manager.Version.ToString(); + + CheckForUpdateResponse update_response = null; + + using (var http = new ProtoWebClient()) + { + update_response = http.Post<CheckForUpdateRequest, CheckForUpdateResponse>(machineServiceAddress + "/api/Synchronization/CheckForUpdate", request).Result; + } + + LogManager.Log($"Check for update response received: {Environment.NewLine}{update_response.ToJsonString()}"); + + return update_response; + }); + } + + #endregion + } +} |
