aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.UI/ViewModels/UpdateViewVM.cs
blob: c40f91005a28eaffa88381e603cf0377a123e1e4 (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
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 */
/************************************************************************************************************************
 * control.c
 **************************************************************************************************************************/
#ifndef MODULES_CONTROL_CONTROL_H_
#define MODULES_CONTROL_CONTROL_H_

////////////////////////////////State machine operation////////////////////////////////////
//the state machine operation is used to operate in runtime correct profile flow execution
//by recieved esign flow of the user from the UI
///////////////////////////////////////////////////////////////////////////////////////////
#include "include.h"

//typedef  uint32_t (* DeviceDataFunction)(uint32_t deviceID, uint32_t *Value);
typedef  uint32_t (* ControlCBFunction)(uint32_t IfIndex, uint32_t ReadValue);
typedef  uint32_t (* DataReadCBFunction)( uint32_t Parameter1);
typedef enum {
    eNoControl = 0,
    eOneMillisecond = 1,
    eTenMillisecond = 10,
    eHundredMillisecond = 100,
    eOneSecond = 1000,
    eOneMinute = 60000
}CTRL_TIMING_ENUM;
typedef enum
{
    IfTypeNone,
    IfTypeThread,
    IfTypeWinder,
    IfTypeIDS,
    IfTypeHeaters,
    IfTypeWaste,
    IfTypeMotors,
    MAX_INTERFACE_TYPES
}SYSTEM_INTERFACE_TYPES_ID_ENUM;


void        ControlInit(void);
void        ControlStop(void);
void        ControlStart(void);
uint32_t    AddControlCallback( ControlCBFunction Callback, CTRL_TIMING_ENUM CtrlFrequency, DataReadCBFunction DriverfPtr, uint32_t IfIndex, uint32_t Parameter1, uint32_t Parameter2 );
int         RemoveControlCallback(uint32_t deviceId, ControlCBFunction Callback );
uint32_t    TemplateDataReadCBFunction (uint32_t deviceId, uint32_t Parameter1);

extern Task_Handle Control_Task_Handle;

#endif
'>403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
using FluentFTP;
using Ionic.Zip;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.Core.Commands;
using Tango.Core.DI;
using Tango.Core.Helpers;
using Tango.Core.IO;
using Tango.Logging;
using Tango.MachineStudio.Common.Authentication;
using Tango.MachineStudio.Common.Navigation;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.Common.StudioApplication;
using Tango.MachineStudio.Common.Web;
using Tango.SharedUI;
using Tango.MachineStudio.UI.Messages;
using Tango.Settings;
using Tango.MachineStudio.Common;
using Tango.Transport.Web;
using Tango.BL;

namespace Tango.MachineStudio.UI.ViewModels
{
    public enum UpdateStatus
    {
        None,
        CheckingForUpdate,
        UpToDate,
        UpdateAvailable,
        Downloading,
        Updating,
        UpdateCompleted,
        Error,
        RollingBack,
        RollbackCompleted,
        RollbackError,
    }

    public class UpdateViewVM : ViewModel
    {
        private String _appPath = AppDomain.CurrentDomain.BaseDirectory;
        private LogManager logManager = LogManager.Default;

        private INotificationProvider _notification;
        private INavigationManager _navigation;
        private IStudioApplicationManager _application;
        private IAuthenticationProvider _authentication;
        private CheckForUpdatesResponse _updateInfo;
        private TemporaryFolder _newPackageTempFolder;
        private TemporaryFolder _previousPackageTempFolder;
        private MachineStudioWebClient _machineStudioWebClient;

        private bool _forcedUpdate;
        public bool ForcedUpdate
        {
            get { return _forcedUpdate; }
            set { _forcedUpdate = value; RaisePropertyChangedAuto(); }
        }

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

        private String _latestVersion;
        public String LatestVersion
        {
            get { return _latestVersion; }
            set { _latestVersion = value; RaisePropertyChangedAuto(); }
        }

        private String _updateComments;
        /// <summary>
        /// Gets or sets the latest version comments.
        /// </summary>
        public String UpdateComments
        {
            get { return _updateComments; }
            set { _updateComments = value; RaisePropertyChangedAuto(); }
        }

        private double _downloadProgress;

        public double DownloadProgress
        {
            get { return _downloadProgress; }
            set { _downloadProgress = value; RaisePropertyChangedAuto(); }
        }

        private double _rollbackProgress;

        public double RollbackProgress
        {
            get { return _rollbackProgress; }
            set { _rollbackProgress = value; RaisePropertyChangedAuto(); }
        }

        private double _updateProgress;

        public double UpdateProgress
        {
            get { return _updateProgress; }
            set { _updateProgress = value; RaisePropertyChangedAuto(); }
        }

        private String _currentUpdateFile;

        public String CurrentUpdateFile
        {
            get { return _currentUpdateFile; }
            set { _currentUpdateFile = value; RaisePropertyChanged(nameof(CurrentUpdateFile)); }
        }

        private bool _isRollbackAvailable;

        public bool IsRollbackAvailable
        {
            get { return _isRollbackAvailable; }
            set { _isRollbackAvailable = value; RaisePropertyChangedAuto(); }
        }

        public RelayCommand UpdateCommand { get; set; }

        public RelayCommand BackCommand { get; set; }

        public RelayCommand RestartCommand { get; set; }

        public RelayCommand TryAgainCommand { get; set; }

        public RelayCommand RollbackCommand { get; set; }

        public RelayCommand TryRollbackAgainCommand { get; set; }

        public UpdateViewVM(MachineStudioWebClient machineStudioWebClient, INotificationProvider notification, IAuthenticationProvider authentication, INavigationManager navigation, IStudioApplicationManager application)
        {
            _machineStudioWebClient = machineStudioWebClient;
            _notification = notification;
            _navigation = navigation;
            _application = application;
            _authentication = authentication;

            LatestVersion = "1.0.0.2";
            Status = UpdateStatus.CheckingForUpdate;
            UpdateCommand = new RelayCommand(StartUpdate, () => Status == UpdateStatus.UpdateAvailable);
            BackCommand = new RelayCommand(BackToApplication, () => Status != UpdateStatus.Updating && !ForcedUpdate);
            RestartCommand = new RelayCommand(RestartApplication, () => Status == UpdateStatus.UpdateCompleted || Status == UpdateStatus.RollbackCompleted);
            TryAgainCommand = new RelayCommand(TryAgain, () => Status == UpdateStatus.Error);
            RollbackCommand = new RelayCommand(Rollback, () => Status != UpdateStatus.RollingBack && !ForcedUpdate);
            TryRollbackAgainCommand = new RelayCommand(TryRollbackAgain, () => Status == UpdateStatus.RollbackError);

            IsRollbackAvailable = File.Exists(GetRollbackFile());

            TangoMessenger.Default.Register<Messages.ForcedUpdateMessage>(HandleForcedUpdateMessage);
            TangoMessenger.Default.Register<Messages.ChangeVersionMessage>(HandleChangeVersionMessage);
        }

        private async void HandleChangeVersionMessage(ChangeVersionMessage msg)
        {
            ForcedUpdate = true;
            InvalidateRelayCommands();

            Status = UpdateStatus.CheckingForUpdate;

            DownloadLatestVersionResponse response = await _machineStudioWebClient.DownloadLatestVersion(new DownloadLatestVersionRequest()
            {
                
            });

            _updateInfo = new CheckForUpdatesResponse();
            _updateInfo.BlobAddress = response.BlobAddress;
            _updateInfo.Version = response.Version;
            LatestVersion = _updateInfo.Version;

            StartUpdate();
        }

        private void HandleForcedUpdateMessage(ForcedUpdateMessage msg)
        {
            ForcedUpdate = true;
            InvalidateRelayCommands();

            _updateInfo = msg.UpdateResponse;
            Status = UpdateStatus.UpdateAvailable;
            LatestVersion = _updateInfo.Version;
            UpdateComments = _updateInfo.Comments;
            StartUpdate();
        }

        public void OnNavigatedInto()
        {
            if (!ForcedUpdate)
            {
                CheckForUpdates();
            }
        }

        private void CheckForUpdates()
        {
            Status = UpdateStatus.CheckingForUpdate;

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

            Task.Factory.StartNew((Action)(() =>
            {
                try
                {
                    Thread.Sleep(2000);

                    CheckForUpdatesResponse response = _machineStudioWebClient.CheckForUpdates(new CheckForUpdatesRequest()
                    {
                        Version = _application.Version.ToString(),
                    }).Result;

                    if (response.IsUpdateAvailable)
                    {
                        _updateInfo = response;
                        Status = UpdateStatus.UpdateAvailable;
                        LatestVersion = response.Version;
                        UpdateComments = response.Comments;
                    }
                    else
                    {
                        Status = UpdateStatus.UpToDate;
                    }
                }
                catch (Exception ex)
                {
                    logManager.Log(ex, "Error while checking for version update!");
                    Status = UpdateStatus.Error;
                }
            }));
        }

        private void BackToApplication()
        {
            if (Status == UpdateStatus.Downloading)
            {
                if (!_notification.ShowQuestion("This will abort all update operations. Are you sure?"))
                {
                    return;
                }
            }

            _navigation.NavigateTo(NavigationView.MainView);
            Status = UpdateStatus.None;
        }

        private void StartUpdate()
        {
            DownloadProgress = 0;
            UpdateProgress = 0;

            Status = UpdateStatus.Downloading;

            Task.Factory.StartNew(() =>
            {
                var tempFile = TemporaryManager.CreateFile(".zip");

                try
                {
                    logManager.Log("Creating temporary file " + tempFile);

                    using (StorageBlobDownloader downloader = new StorageBlobDownloader(_updateInfo.BlobAddress, tempFile.Path))
                    {
                        downloader.Progress += (x, e) => 
                        {
                            InvokeUINow(() =>
                            {
                                DownloadProgress = ((double)e.Current / (double)e.Total) * 100d;
                            });
                        };

                        downloader.Download().Wait();
                    }

                    Status = UpdateStatus.Updating;

                    _newPackageTempFolder = TemporaryManager.CreateFolder();
                    _newPackageTempFolder.Persist = true;

                    using (ZipFile zip = ZipFile.Read(tempFile.Path))
                    {
                        int currentEntry = 0;

                        zip.ExtractProgress += (x, args) =>
                        {
                            if (args.EventType == ZipProgressEventType.Extracting_AfterExtractEntry)
                            {
                                logManager.Log("Extracting " + Path.GetFileName(args.CurrentEntry.FileName));
                                UpdateProgress = ((double)(currentEntry++) / (double)zip.Entries.Count) * 100d;
                            }
                        };

                        foreach (ZipEntry entry in zip)
                        {
                            Thread.Sleep(10);

                            string newPath = Path.Combine(_newPackageTempFolder.Path, entry.FileName);

                            try
                            {
                                if (entry.IsDirectory)
                                {
                                    Directory.CreateDirectory(newPath);
                                }
                                else
                                {
                                    CurrentUpdateFile = Path.GetFileName(entry.FileName);
                                    entry.Extract(_newPackageTempFolder.Path, ExtractExistingFileAction.OverwriteSilently);
                                }
                            }
                            catch
                            {
                                logManager.Log("Could not extract file " + entry.FileName);
                            }
                        }
                    }

                    try
                    {
                        LogManager.Log("Backing up current version...");
                        CurrentUpdateFile = "Backing up current version...";

                        String rollbackFolder = GetRollbackFolder();
                        Directory.CreateDirectory(rollbackFolder);

                        String backFile = GetRollbackFile();

                        if (File.Exists(backFile))
                        {
                            File.Delete(backFile);
                        }

                        using (ZipFile backZip = new ZipFile(backFile))
                        {
                            int currentEntry = 0;

                            backZip.SaveProgress += (_, e) =>
                            {
                                UpdateProgress = ((double)(currentEntry++) / (double)backZip.Entries.Count) * 100d;
                            };

                            backZip.Password = "Aa123456";
                            backZip.AddDirectory(_appPath);
                            backZip.Save();
                        }
                    }
                    catch (Exception ex)
                    {
                        LogManager.Log(ex, "Could not construct rollback.");
                        _notification.ShowWarning("Update center has failed to construct a rollback point for the current version. Version rollback will not be available.");
                    }

                    TangoIOC.Default.GetInstance<MainViewVM>().DisableCheckForUpdates = true;
                    Status = UpdateStatus.UpdateCompleted;
                }
                catch (Exception ex)
                {
                    logManager.Log(ex, "Error while extracting update package.");
                    Status = UpdateStatus.Error;
                }
                finally
                {
                    tempFile.Delete();
                }
            });
        }

        private void TryAgain()
        {
            CheckForUpdates();
        }

        private void RestartApplication()
        {
            try
            {
                LogManager.Log("Clearing EF model store...");
                ObservablesContext.ClearModelStore();

                Process p = new Process();

                if (Status == UpdateStatus.UpdateCompleted)
                {
                    p.StartInfo.FileName = _newPackageTempFolder + "\\Tango.MachineStudio.Updater.exe";
                }
                else if (Status == UpdateStatus.RollbackCompleted)
                {
                    p.StartInfo.FileName = _previousPackageTempFolder + "\\Tango.MachineStudio.Updater.exe";
                }

                p.StartInfo.UseShellExecute = true;
                p.StartInfo.Arguments = _appPath;
                p.Start();
            }
            catch (Exception ex)
            {
                if (ex.Message == "The operation was canceled by the user")
                {
                    _notification.ShowWarning("It seems like you refused to invoke our update utility. This prevents Machine Studio from completing the update process!");
                    return;
                }
            }
            Environment.Exit(0);
        }

        private void Rollback()
        {
            if (_notification.ShowQuestion("Are you sure you want to restore the previous version?"))
            {
                Status = UpdateStatus.RollingBack;

                try
                {
                    Task.Factory.StartNew(() =>
                    {
                        _previousPackageTempFolder = TemporaryManager.CreateFolder();
                        _previousPackageTempFolder.Persist = true;

                        using (ZipFile zip = new ZipFile(GetRollbackFile()))
                        {
                            zip.Password = "Aa123456";

                            int currentEntry = 0;

                            zip.ExtractProgress += (x, args) =>
                            {
                                if (args.EventType == ZipProgressEventType.Extracting_AfterExtractEntry)
                                {
                                    logManager.Log("Extracting " + Path.GetFileName(args.CurrentEntry.FileName));
                                    RollbackProgress = ((double)(currentEntry++) / (double)zip.Entries.Count) * 100d;
                                }
                            };

                            foreach (ZipEntry entry in zip)
                            {
                                Thread.Sleep(10);

                                string newPath = Path.Combine(_previousPackageTempFolder.Path, entry.FileName);

                                try
                                {
                                    if (entry.IsDirectory)
                                    {
                                        Directory.CreateDirectory(newPath);
                                    }
                                    else
                                    {
                                        entry.Extract(_previousPackageTempFolder.Path, ExtractExistingFileAction.OverwriteSilently);
                                    }
                                }
                                catch
                                {
                                    logManager.Log("Could not extract file " + entry.FileName);
                                }
                            }

                        }

                        File.Delete(GetRollbackFile());

                        Status = UpdateStatus.RollbackCompleted;
                    });
                }
                catch (Exception ex)
                {
                    Status = UpdateStatus.Error;
                    LogManager.Log(ex, "Error while trying to restore version.");
                    _notification.ShowError("An error occurred while trying to restore the previous version.");
                }
            }
        }

        private void TryRollbackAgain()
        {
            CheckForUpdates();
        }

        private String GetRollbackFolder()
        {
            String rollbackFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Twine", "Tango", "Rollback");
            return rollbackFolder;
        }

        private String GetRollbackFile()
        {
            String backFile = Path.Combine(GetRollbackFolder(), Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName) + ".rollback");
            return backFile;
        }

        protected override void RaisePropertyChangedAuto([CallerMemberName] string caller = null)
        {
            base.RaisePropertyChangedAuto(caller);
            InvalidateRelayCommands();
        }
    }
}