using FluentFTP; using System; using System.Collections.Generic; using System.Data.SqlClient; using System.IO; using System.IO.Compression; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.Core; using Tango.Core.IO; using Tango.PMR.Synchronization; using Tango.Settings; using Tango.SQLExaminer; using Tango.Transport.Web; namespace Tango.PPC.Common.MachineSetup { public class MachineSetupManager : ExtendedObject, IMachineSetupManager { public event EventHandler ProgressLog; public event EventHandler ProgressStep; private MachineSetupSteps _currentStep; public MachineSetupSteps CurrentStep { get { return _currentStep; } set { _currentStep = value; RaisePropertyChangedAuto(); ProgressStep?.Invoke(this, _currentStep); } } private double _downloadProgress; public double UpdatingPackagesProgress { get { return _downloadProgress; } private set { _downloadProgress = value; RaisePropertyChangedAuto(); } } private String _updatingPackagesStatus; public String UpdatingPackagesStatus { get { return _updatingPackagesStatus; } set { _updatingPackagesStatus = value; RaisePropertyChangedAuto(); } } public Task Setup(string serialNumber, string machineServiceAddress) { return Task.Factory.StartNew(() => { //Connect to machine service and get matching packages for this machine. CurrentStep = MachineSetupSteps.UpdatingPackages; UpdatingPackagesProgress = 0; UpdatingPackagesStatus = "Connecting to machine service..."; MachineSetupRequest request = new MachineSetupRequest(); request.SerialNumber = serialNumber; MachineSetupResponse setup_response = null; using (var http = new ProtoWebClient()) { setup_response = http.Post(machineServiceAddress + "/api/Synchronization/MachineSetup", request).Result; } //Create temporary folders for packages. var _newPackageTempFolder = TemporaryManager.CreateFolder(); _newPackageTempFolder.Persist = true; var software_package_folder = _newPackageTempFolder.CreateFolder(); var embedded_package_folder = _newPackageTempFolder.CreateFolder(); //Download software package. var tempFile = TemporaryManager.CreateFile(".zip"); UpdatingPackagesStatus = "Downloading application package..."; int fileSize = 0; UpdatingPackagesProgress = 0; using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => { InvokeUINow(() => { Thread.Sleep(10); UpdatingPackagesProgress = ((double)current / (double)fileSize) * 100d; }); })) { using (FtpClient ftp = new FtpClient(setup_response.FtpAddress, setup_response.UserName, setup_response.Password)) { LogManager.Log("Connecting to FTP site: " + setup_response.FtpAddress); ftp.ConnectAsync().Wait(); LogManager.Log("Retrieving download size..."); fileSize = (int)ftp.GetFileSize(setup_response.ApplicationFtpFilePath); LogManager.Log("Download size: " + fileSize + " bytes."); LogManager.Log("Starting download..."); ftp.DownloadAsync(fs, setup_response.ApplicationFtpFilePath).Wait(); } } //Extract software package. ZipFile.ExtractToDirectory(tempFile, software_package_folder); //Download embedded package. tempFile = TemporaryManager.CreateFile(".zip"); UpdatingPackagesStatus = "Downloading embedded package..."; fileSize = 0; UpdatingPackagesProgress = 0; using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) => { InvokeUINow(() => { Thread.Sleep(10); UpdatingPackagesProgress = ((double)current / (double)fileSize) * 100d; }); })) { using (FtpClient ftp = new FtpClient(setup_response.FtpAddress, setup_response.UserName, setup_response.Password)) { LogManager.Log("Connecting to FTP site: " + setup_response.FtpAddress); ftp.ConnectAsync().Wait(); LogManager.Log("Retrieving download size..."); fileSize = (int)ftp.GetFileSize(setup_response.EmbeddedFtpFilePath); LogManager.Log("Download size: " + fileSize + " bytes."); LogManager.Log("Starting download..."); ftp.DownloadAsync(fs, setup_response.EmbeddedFtpFilePath).Wait(); } } //Extract embedded package. ZipFile.ExtractToDirectory(tempFile, embedded_package_folder); //Synchronize database String remote_address = setup_response.DbAddress; CurrentStep = MachineSetupSteps.SynchronizingSchema; String db_name = "Tango"; String localAddress = SettingsManager.Default.GetOrCreate().DataBaseSource; var tempFolder = TemporaryManager.Default.CreateFolder("Machine Setup"); String report_file = tempFolder.CreateImaginaryFile(".xml"); String config_file = tempFolder.CreateImaginaryFile(".xml"); DbManager db = new DbManager(new SqlConnection(String.Format("Server={0};Integrated security=SSPI", localAddress))); if (!db.Exists("Tango")) { throw new InvalidProgramException("Database tango does not exists."); } //Create schema configuration ExaminerConfigurationBuilder builder = new ExaminerConfigurationBuilder(ExaminerConfigurationType.Schema); builder. SetSourceServer(remote_address, db_name). SetTargetServer(localAddress, db_name). Synchronize(); //Synchronize Source schema with Target schema var process = new ExaminerProcess(builder.Build(), ExaminerProcessType.Schema); process.Progress += (x, msg) => { ProgressLog?.Invoke(this, msg); }; var result = process.Execute().Result; //Synchronization was successful if (result.ExitCode != ExaminerProcessExitCode.Success) { throw new InvalidProgramException("Error while trying to synchronize database schema."); } CurrentStep = MachineSetupSteps.SynchronizingData; //Create override data configuration builder = new ExaminerConfigurationBuilder(ExaminerConfigurationType.OverrideData); builder. SetSourceServer(remote_address, db_name). SetTargetServer(localAddress, db_name). Synchronize(); process = new ExaminerProcess(builder.Build(), ExaminerProcessType.Data); process.Progress += (x, msg) => { ProgressLog?.Invoke(this, msg); }; result = process.Execute().Result; //Synchronization was successful if (result.ExitCode != ExaminerProcessExitCode.Success) { throw new InvalidProgramException("Error while trying to synchronize data."); } CurrentStep = MachineSetupSteps.SynchronizingMachineConfiguration; //Provision Target builder = new ExaminerConfigurationBuilder(ExaminerConfigurationType.ProvisionMachine); builder. SetSourceServer(remote_address, db_name). SetTargetServer(localAddress, db_name). SetMachineSerialNumber(serialNumber). Synchronize(); process = new ExaminerProcess(builder.Build(), ExaminerProcessType.Data); process.Progress += (x, msg) => { ProgressLog?.Invoke(this, msg); }; result = process.Execute().Result; //Synchronization was successful if (result.ExitCode != ExaminerProcessExitCode.Success) { throw new InvalidProgramException("Error while trying to synchronize database schema."); } }); } } }