aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/PPC/Tango.PPC.Common/MachineSetup/MachineSetupManager.cs
blob: fa9c957423c3657023d187b09a7c67165381586a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.PPC.Common.Modules
{
    /// <summary>
    /// Represents a PPC <see cref="IPPCModule"/> modules loading engine.
    /// </summary>
    public interface IPPCModuleLoader
    {
        /// <summary>
        /// Occurs when the user has logged in and user modules are loaded.
        /// </summary>
        event EventHandler ModulesLoaded;

        /// <summary>
        /// Gets all loaded modules.
        /// </summary>
        ObservableCollection<IPPCModule> AllModules { get; }

        /// <summary>
        /// Gets all the user permitted modules.
        /// </summary>
        ObservableCollection<IPPCModule> UserModules { get; }

        /// <summary>
        /// Gets the PPC module of type T if loaded.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetPPCModule<T>() where T : IPPCModule;

        /// <summary>
        /// Loads all available PPC modules.
        /// </summary>
        void LoadModules();
    }
}
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
using FluentFTP;
using Microsoft.WindowsAzure.Storage.Blob;
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.DB;
using Tango.Core.Helpers;
using Tango.Core.IO;
using Tango.Integration.Operation;
using Tango.PMR.Synchronization;
using Tango.PPC.Common.Application;
using Tango.PPC.Common.Connection;
using Tango.PPC.Common.OS;
using Tango.PPC.Common.RemoteAssistance;
using Tango.PPC.Common.UWF;
using Tango.PPC.Common.Web;
using Tango.Settings;
using Tango.SharedUI.Helpers;
using Tango.SQLExaminer;
using Tango.Transport.Web;

namespace Tango.PPC.Common.MachineSetup
{
    /// <summary>
    /// Represents the PPC machine setup manager.
    /// </summary>
    /// <seealso cref="Tango.Core.ExtendedObject" />
    /// <seealso cref="Tango.PPC.Common.MachineSetup.IMachineSetupManager" />
    public class MachineSetupManager : ExtendedObject, IMachineSetupManager
    {
        private IRemoteAssistanceProvider _remoteAssistance;
        private IUnifiedWriteFilterManager _uwf;
        private IOperationSystemManager _windows_manager;
        private PPCWebClient _client;

        #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<MachineSetupProgress> Progress;

        #endregion

        #region Properties

        private MachineSetupProgress _status;
        public MachineSetupProgress Status
        {
            get { return _status; }
            private set { _status = value; RaisePropertyChangedAuto(); }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="MachineSetupManager"/> class.
        /// </summary>
        /// <param name="remoteAssistance">The remote assistance.</param>
        public MachineSetupManager(PPCWebClient ppcWebClient, IRemoteAssistanceProvider remoteAssistance, IUnifiedWriteFilterManager unifiedWriterFilterManager, IOperationSystemManager operationSystemManager)
        {
            _client = ppcWebClient;
            _remoteAssistance = remoteAssistance;
            _uwf = unifiedWriterFilterManager;
            _windows_manager = operationSystemManager;
        }

        #endregion

        #region Private Methods

        private Task Login(String serialNumber)
        {
            return Task.Factory.StartNew(() =>
            {
                return _client.Login(new LoginRequest()
                {
                    Mode = LoginMode.Machine,
                    SerialNumber = serialNumber,
                }).Result;

            });
        }

        #endregion

        #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 async Task<MachineSetupResult> Setup(string serialNumber)
        {
            TaskCompletionSource<MachineSetupResult> result = new TaskCompletionSource<MachineSetupResult>();

            try
            {
                LogManager.Log($"Starting machine setup for serial number {serialNumber}...");

                var machineServiceAddress = SettingsManager.Default.GetOrCreate<PPCSettings>().GetMachineServiceAddress();

                IMachineOperator op = null;

                var settings = SettingsManager.Default.GetOrCreate<PPCSettings>();

                //Connect to machine service and get matching packages for this machine.
                UpdateProgress("Validating serial number", "Connecting to machine service...");

                LogManager.Log($"Connecting to machine service on {machineServiceAddress}...");

                Login(serialNumber).Wait();

                MachineSetupRequest request = new MachineSetupRequest();
                request.SerialNumber = serialNumber;

                MachineSetupResponse setup_response = null;

                try
                {
                    setup_response = await _client.MachineSetup(request);
                }
                catch (Exception ex)
                {
                    throw LogManager.Log(ex, $"An error occurred while trying to contact machine service: {ex.FlattenMessage()}");
                }

                LogManager.Log($"Machine setup response received: {Environment.NewLine}{setup_response.ToJsonString()}");

                if (setup_response.SetupFirmware)
                {
                    //Connecting to machine...
                    LogManager.Log("Initiating machine connection...");

                    UpdateProgress("Connecting to machine", "Connecting...");
                    op = await DefaultMachineProvider.CreateMinimalMachineOperator((msg) =>
                    {
                        UpdateProgress("Connecting to machine", msg);
                    });
                }

                if (setup_response.SetupActivation)
                {
                    LogManager.Log("Activating windows license...");
                    UpdateProgress("Activating operation system license", "Activating...");
                    await _windows_manager.Activate(setup_response.OSKey);
                }

                if (setup_response.SetupRemoteAssistance)
                {
                    LogManager.Log("Installing remote assistance...");
                    UpdateProgress("Installing remote assistance", "Installing...");
                    await _remoteAssistance.InstallRemoteAssistance(serialNumber);
                }

                if (setup_response.SetupUWF)
                {
                    LogManager.Log("Activating unified write filter...");
                    UpdateProgress("Activating disk protection", "Activating...");
                    await _uwf.Setup();
                }

                //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);

                await Task.Factory.StartNew(() =>
                {
                    using (FileStreamWrapper fs = new FileStreamWrapper(tempFile.Path, FileMode.Create, (current) =>
                    {
                        UpdateProgress("Downloading software package", "Downloading...", false, current, fileSize);
                    }))
                    {

                        LogManager.Log($"Connecting to storage blob with address {setup_response.BlobAddress}");
                        CloudBlockBlob blob = new CloudBlockBlob(new Uri(setup_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);


                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...");

                var localDataSource = SettingsManager.Default.GetOrCreate<CoreSettings>().DataSource;

                LogManager.Log($"Synchronizing database '{setup_response.DataSource.ToString()}' => '{localDataSource.ToString()}'...");

                UpdateProgress("Updating Database", "Connecting to local database...");
                LogManager.Log($"Connecting to local database at {localDataSource}...");
                DbManager db = DbManager.FromAddress(localDataSource.Address);

                LogManager.Log($"Ensuring {localDataSource.Catalog} database exists on the local machine...");
                if (!db.Exists(localDataSource.Catalog))
                {
                    UpdateProgress("Updating Database", "Creating new database...");
                    LogManager.Log("Database does not exist. Creating new database...");
                    db.Create(localDataSource.Catalog);
                }
                else
                {
                    LogManager.Log("Database exists.");
                }

                db.Dispose();

                LogManager.Log("Initializing database manager...");
                db = DbManager.FromDataSource(localDataSource);

                UpdateProgress("Updating Database", "Clearing current database...");
                LogManager.Log("Clearing database...");
                db.ClearDb();

                LogManager.Log("Disposing database manager.");
                db.Dispose();

                LogManager.Log($"Initializing {nameof(ExaminerSequenceConfigurationRunner)}...");

                UpdateProgress("Updating Database", "Initializing provisioning sequence...");

                ExaminerSequenceConfigurationRunner runner = new ExaminerSequenceConfigurationRunner(
                    Path.Combine(_newPackageTempFolder, "Provision Scripts", "config.xml"),
                    Path.Combine(_newPackageTempFolder, "Provision Scripts"),
                    setup_response.DataSource,
                    localDataSource,
                    serialNumber);

                runner.Log += (x, msg) =>
                {
                    LogManager.Log(msg);
                    ProgressLog?.Invoke(this, msg);
                };

                runner.ScriptExecuting += (x, item) =>
                {
                    LogManager.Log($"Executing script {item.ToString()}...");
                    UpdateProgress("Updating Database", item.Name + "...");
                };

                LogManager.Log("Starting synchronization process...");

                try
                {
                    await runner.Run();
                    LogManager.Log("Synchronization completed successfully!");
                    UpdateProgress("Updating Database", "Database synchronization completed successfully.");
                }
                catch (Exception ex)
                {
                    throw LogManager.Log(ex, "Setup manager error while trying to synchronize database.");
                }

                if (setup_response.SetupFirmware)
                {
                    //Updating firmware
                    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);
                    var handler = await op.UpgradeFirmware(stream);
                    handler.Failed += (_, ex) =>
                    {
                        stream.Dispose();
                        result.SetException(ex);
                    };
                    handler.Completed += (_, __) =>
                    {
                        UpdateProgress("Updating Firmware", "Firmware update completed successfully.");
                        stream.Dispose();
                        result.SetResult(new MachineSetupResult()
                        {
                            UpdatePackagePath = _newPackageTempFolder,
                        });
                    };
                    handler.Canceled += (_, __) =>
                    {
                        stream.Dispose();
                        result.SetException(new Exception("The operation has been canceled."));
                    };
                    handler.Progress += (_, e) =>
                    {
                        UpdateProgress("Updating Firmware", e.Message, false, e.Current, e.Total);
                    };
                }
                else
                {
                    result.SetResult(new MachineSetupResult()
                    {
                        UpdatePackagePath = _newPackageTempFolder,
                    });
                }
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, "An error occurred in machine setup.");
                result.SetException(ex);
            }

            return await result.Task;
        }

        #endregion

        #region Protected Methods

        protected virtual void UpdateProgress(String name, String message = "", bool isIntermediate = true, double progress = 0, double total = 0)
        {
            InvokeUINow(() =>
            {
                Status = new MachineSetupProgress()
                {
                    Name = name,
                    Message = message,
                    IsIntermediate = isIntermediate,
                    Progress = progress,
                    Total = total,
                };

                Progress?.Invoke(this, Status);
            });

            UIHelper.DoEvents();
        }

        #endregion
    }
}