aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DB/ViewModels/MainViewVM.cs
blob: 9503e4c3845a36bee3760b75d638263a547b1bcd (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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Tango.BL;
using Tango.BL.Entities;
using Tango.Core.Commands;
using Tango.Core.DI;
using Tango.MachineStudio.Common;
using Tango.MachineStudio.Common.StudioApplication;
using Tango.SharedUI;

namespace Tango.MachineStudio.DB.ViewModels
{
    public class MainViewVM : StudioViewModel
    {
        private bool _isLoading;
        public bool IsLoading
        {
            get { return _isLoading; }
            set { _isLoading = value; RaisePropertyChangedAuto(); }
        }

        private bool _notLoaded;
        public bool NotLoaded
        {
            get { return _notLoaded; }
            set { _notLoaded = value; RaisePropertyChangedAuto(); }
        }

        public RelayCommand LoadCommand { get; set; }

        public MainViewVM() : base()
        {
            NotLoaded = true;
            LoadCommand = new RelayCommand(LoadAdapter,() => !IsLoading);
        }

        private async void LoadAdapter()
        {
            IsLoading = true;
            InvalidateRelayCommands();

            await Task.Factory.StartNew(() => 
            {
                ObservablesEntitiesAdapter.Instance.Initialize();
            });

            IsLoading = false;
            NotLoaded = false;
        }

        public override void OnApplicationReady()
        {
            
        }

        //public override void OnModuleRequest(params object[] args)
        //{
        //    if (args != null && args.Length > 0 && args[0] is IObservableEntity)
        //    {
        //        var arg = args[0];

        //        String vmName = arg.GetType().Name + "sViewVM";

        //        Type vmType = Assembly.GetAssembly(typeof(MainViewVM)).GetTypes().SingleOrDefault(x => x.Name == vmName);

        //        if (vmType == null)
        //        {
        //            vmName = arg.GetType().BaseType.Name + "sViewVM";
        //            vmType = Assembly.GetAssembly(typeof(MainViewVM)).GetTypes().SingleOrDefault(x => x.Name == vmName);
        //        }

        //        if (vmType != null)
        //        {
        //            var vm = TangoIOC.Default.GetInstance(vmType);
        //            vmType.GetProperty("SelectedEntity").SetValue(vm, arg);
        //            vmType.GetMethod("OnEdit", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(vm, new object[] { });
        //        }
        //    }
        //}
    }
}
ighlight .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 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();
        }
    }
}