Exemple #1
0
        private void ThreadExecution(CancellationToken cancellationToken)
        {
            try
            {
                _state.Value = PatcherState.None;

                DebugLogger.Log("Patcher thread started.");

                ThreadLoadPatcherData();

                EnsureSingleInstance();

                ThreadLoadPatcherConfiguration();

                UnityDispatcher.Invoke(() => _app = new App(_data.Value.AppDataPath, _data.Value.AppSecret, _data.Value.OverrideLatestVersionId)).WaitOne();

                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    ThreadWaitForUserDecision(cancellationToken);

                    cancellationToken.ThrowIfCancellationRequested();

                    ThreadExecuteUserDecision(cancellationToken);
                }
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log("Patcher thread finished: thread has been cancelled.");
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log("Patcher thread finished: thread has been interrupted.");
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log("Patcher thread finished: thread has been aborted.");
            }
            catch (MultipleInstancesException exception)
            {
                DebugLogger.LogException(exception);
                Quit();
            }
            catch (Exception exception)
            {
                DebugLogger.LogError("Patcher thread failed: an exception has occured.");
                DebugLogger.LogException(exception);
            }
            finally
            {
                _state.Value = PatcherState.None;

                if (_app != null)
                {
                    _app.Dispose();
                    _app = null;
                }
            }
        }
Exemple #2
0
        private void ThreadDisplayError(PatcherError error, CancellationToken cancellationToken)
        {
            try
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0}...", error));

                ErrorDialog.Display(error, cancellationToken);

                DebugLogger.Log(string.Format("Patcher error {0} displayed.", error));
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0} cancelled.", _userDecision));
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0} interrupted: thread has been interrupted. Rethrowing exception.", error));
                throw;
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0} aborted: thread has been aborted. Rethrowing exception.", error));
                throw;
            }
            catch (Exception)
            {
                DebugLogger.LogWarning(string.Format("Error while displaying patcher error {0}: an exception has occured. Rethrowing exception.", error));
                throw;
            }
        }
Exemple #3
0
        private void ThreadUpdateApp(CancellationToken cancellationToken)
        {
            _state.Value = PatcherState.UpdatingApp;

            _remoteVersionId.Value = _app.GetLatestVersionId();
            if (_app.IsInstalled())
            {
                _localVersionId.Value = _app.GetInstalledVersionId();
            }

            _updateAppCancellationTokenSource = new CancellationTokenSource();

            using (cancellationToken.Register(() => _updateAppCancellationTokenSource.Cancel()))
            {
                var appUpdater = new AppUpdater.AppUpdater(new AppUpdaterContext(_app, _configuration.AppUpdaterConfiguration));
                appUpdater.Context.StatusMonitor.OverallStatusChanged += OnUpdateAppStatusChanged;

                try
                {
                    appUpdater.Update(_updateAppCancellationTokenSource.Token);
                }
                finally
                {
                    appUpdater.Context.StatusMonitor.OverallStatusChanged -= OnUpdateAppStatusChanged;
                    _updateAppCancellationTokenSource = null;
                }
            }
        }
        private void ThreadDisplayError(PatcherErrorMessage error, CancellationToken cancellationToken)
        {
            PatcherStatistics.DispatchSendEvent(PatcherStatistics.Event.PatcherFailed);

            try
            {
                _state.Value = PatcherState.DisplayingError;

                DebugLogger.Log(string.Format("Displaying patcher error {0}...", error.Message));

                ErrorDialog.Display(error, cancellationToken);

                DebugLogger.Log(string.Format("Patcher error {0} displayed.", error.Message));
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0} cancelled.", _userDecision));
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0} interrupted: thread has been interrupted. Rethrowing exception.", error.Message));
                throw;
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log(string.Format("Displaying patcher error {0} aborted: thread has been aborted. Rethrowing exception.", error.Message));
                throw;
            }
            catch (Exception)
            {
                DebugLogger.LogWarning(string.Format("Error while displaying patcher error {}: an exception has occured. Rethrowing exception.", error.Message));
                throw;
            }
        }
        // returns true if data is valid (was valid from the start or successfull repair was performed)
        public bool Perform(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            _lowestVersionWithContentId = Context.App.GetLowestVersionWithContentId(cancellationToken);

            for (int attempt = 1; attempt <= RepeatCount; ++attempt)
            {
                DebugLogger.Log("Running integrity check, attempt " + attempt + " of " + RepeatCount);

                if (PerformInternal(cancellationToken))
                {
                    return(true);
                }
            }

            // retry count reached, let's check for the last time if data is ok, but without repairing
            int installedVersionId   = Context.App.GetInstalledVersionId();
            VersionIntegrity results = CheckIntegrity(cancellationToken, installedVersionId);
            var filesNeedFixing      = FilesNeedFixing(results);

            if (filesNeedFixing.Count() == 0)
            {
                DebugLogger.Log("No missing or invalid size files.");
                return(true);
            }


            DebugLogger.LogError("Still have corrupted files after all fixing attempts");
            return(false);
        }
        // returns true if there was no integrity errors, false if there was and repair was performed
        private bool PerformInternal(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            int installedVersionId = Context.App.GetInstalledVersionId();

            VersionIntegrity results = CheckIntegrity(cancellationToken, installedVersionId);
            var filesNeedFixing      = FilesNeedFixing(results);

            if (filesNeedFixing.Count() == 0)
            {
                DebugLogger.Log("No missing or invalid size files.");
                return(true);
            }

            // need to collect some data about the application to calculate the repair cost and make decisions

            int latestVersionId = Context.App.GetLatestVersionId(true, cancellationToken);

            AppContentSummary installedVersionContentSummary
                = Context.App.RemoteMetaData.GetContentSummary(installedVersionId, cancellationToken);

            AppContentSummary latestVersionContentSummary
                = Context.App.RemoteMetaData.GetContentSummary(latestVersionId, cancellationToken);

            bool isNewVersionAvailable = installedVersionId < latestVersionId;

            long contentSize = isNewVersionAvailable
                ? latestVersionContentSummary.Files.Sum(f => f.Size)
                : installedVersionContentSummary.Files.Sum(f => f.Size);

            double repairCost = CalculateRepairCost(installedVersionContentSummary, filesNeedFixing);

            // increasing repair costs that reinstallation will be done for 1/3 of the content size
            repairCost *= IncreaseRepairCost;


            if (_lowestVersionWithContentId > installedVersionId)
            {
                DebugLogger.Log(
                    "Repair is impossible because lowest version with content id is "
                    + _lowestVersionWithContentId +
                    " and currently installed version id is "
                    + installedVersionId +
                    ". Reinstalling.");

                ReinstallContent(cancellationToken);
            }
            else if (repairCost < contentSize)
            {
                DebugLogger.Log(string.Format("Repair cost {0} is smaller than content cost {1}, repairing...", repairCost, contentSize));
                IAppUpdaterStrategy repairStrategy = _strategyResolver.Create(StrategyType.Repair, Context);
                repairStrategy.Update(cancellationToken);
            }
            else
            {
                DebugLogger.Log(string.Format("Content cost {0} is smaller than repair {1}. Reinstalling.", contentSize, repairCost));
                ReinstallContent(cancellationToken);
            }

            return(false);
        }
        /// <summary>
        /// Like Thread.Sleep() but checks if cancelation occured meanwhile
        /// </summary>
        /// <param name="duration">Miliseconds, time to sleep</param>
        /// <param name="cancellationToken">token to check cancellation exception</param>
        public static void CancelableSleep(int duration, PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            // FIX: Bug #692
            int singleSleep = 100;

            for (int i = 0; i < duration / singleSleep; ++i)
            {
                cancellationToken.ThrowIfCancellationRequested();
                Thread.Sleep(singleSleep);
            }
        }
        private void ReinstallContent(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            IUninstallCommand uninstall = _commandFactory.CreateUninstallCommand(Context);

            uninstall.Prepare(_status, cancellationToken);
            uninstall.Execute(cancellationToken);

            // not catching any exceptions here, because exception during content installation in this place should be fatal
            var contentStrategy = new AppUpdaterContentStrategy(Context, _status);

            contentStrategy.RepairOnError = false; // do not attempt to repair content to not cause a loop
            contentStrategy.Update(cancellationToken);
        }
Exemple #9
0
        private bool TryHandleFallback(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            var fallbackType = _strategyResolver.GetFallbackStrategy(_strategy.GetStrategyType());

            if (fallbackType == StrategyType.None)
            {
                return(false);
            }

            _strategy = _strategyResolver.Create(fallbackType, Context);

            _strategy.Update(cancellationToken);

            return(true);
        }
        public override void Prepare(UpdaterStatus status, CancellationToken cancellationToken)
        {
            base.Prepare(status, cancellationToken);

            if (status == null)
            {
                throw new ArgumentNullException("status");
            }

            DebugLogger.Log("Preparing package download.");

            _status = new DownloadStatus
            {
                Weight      = { Value = StatusWeightHelper.GetResourceDownloadWeight(_resource) },
                Description = { Value = "Downloading package..." }
            };
            status.RegisterOperation(_status);
        }
        private VersionIntegrity CheckIntegrity(
            PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken,
            int installedVersionId
            )
        {
            ICheckVersionIntegrityCommand checkIntegrity = _commandFactory
                                                           .CreateCheckVersionIntegrityCommand(
                versionId: installedVersionId,
                context: Context,
                isCheckingHash: CheckHashes,
                isCheckingSize: true,
                cancellationToken: cancellationToken);

            checkIntegrity.Prepare(_status, cancellationToken);
            checkIntegrity.Execute(cancellationToken);

            return(checkIntegrity.Results);
        }
        private void ThreadUpdateApp(bool automatically, CancellationToken cancellationToken)
        {
            _state.Value = PatcherState.Connecting;

            _updateAppCancellationTokenSource = new PatchKit.Unity.Patcher.Cancellation.CancellationTokenSource();

            using (cancellationToken.Register(() => _updateAppCancellationTokenSource.Cancel()))
            {
                _appInfo.Value         = _app.RemoteMetaData.GetAppInfo(!automatically, _updateAppCancellationTokenSource.Token);
                _remoteVersionId.Value = _app.GetLatestVersionId(!automatically, _updateAppCancellationTokenSource.Token);
                if (_app.IsFullyInstalled())
                {
                    _localVersionId.Value = _app.GetInstalledVersionId();
                }

                var appUpdater = new AppUpdater.AppUpdater(new AppUpdaterContext(_app, _configuration.AppUpdaterConfiguration));

                try
                {
                    _updaterStatus.Value = appUpdater.Status;

                    using (_updaterStatus.Take(1).Subscribe((status) => _state.Value = PatcherState.UpdatingApp))
                    {
                        appUpdater.Update(_updateAppCancellationTokenSource.Token);
                        _wasUpdateSuccessfulOrNotNecessary = true;
                    }
                }
                catch (OperationCanceledException)
                {
                    PatcherStatistics.DispatchSendEvent(PatcherStatistics.Event.PatcherCanceled);

                    throw;
                }
                finally
                {
                    _state.Value = PatcherState.None;

                    _updaterStatus.Value = null;
                    _updateAppCancellationTokenSource = null;
                }
            }
        }
Exemple #13
0
        public void Update(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            Assert.MethodCalledOnlyOnce(ref _updateHasBeenCalled, "Update");

            if (Context.App.IsInstallationBroken() || Context.App.IsFullyInstalled())
            {
                PreUpdate(cancellationToken);
            }

            DebugLogger.Log("Updating.");

            StrategyType type = _strategyResolver.Resolve(Context, cancellationToken);

            _strategy = _strategyResolver.Create(type, Context);

            try
            {
                _strategy.Update(cancellationToken);
            }
            catch (Exception ex)
            {
                if (ex is OperationCanceledException ||
                    ex is UnauthorizedAccessException ||
                    ex is NotEnoughtDiskSpaceException ||
                    ex is ThreadInterruptedException ||
                    ex is ThreadAbortException)
                {
                    DebugLogger.LogWarning("Strategy caused exception, to be handled further");
                    throw;
                }
                else
                {
                    DebugLogger.LogWarningFormat("Strategy caused exception, being handled by fallback: {0}, Trace: {1}", ex, ex.StackTrace);

                    if (!TryHandleFallback(cancellationToken))
                    {
                        throw;
                    }
                }
            }
        }
        protected void Display(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            Assert.IsFalse(_unityThread == Thread.CurrentThread,
                           "Display dialog can be only used on separate thread.");

            try
            {
                _isDisplaying = true;

                _dialogDisplayed.Reset();
                using (cancellationToken.Register(() => _dialogDisplayed.Set()))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    _dialogDisplayed.WaitOne();
                }
            }
            finally
            {
                _isDisplaying = false;
            }
        }
Exemple #15
0
        private void ThreadUpdateApp(CancellationToken cancellationToken)
        {
            _state.Value = PatcherState.UpdatingApp;

            _updateAppCancellationTokenSource = new CancellationTokenSource();

            using (cancellationToken.Register(() => _updateAppCancellationTokenSource.Cancel()))
            {
                var appUpdater = new AppUpdater.AppUpdater(_app, _configuration.AppUpdaterConfiguration);

                appUpdater.Context.StatusMonitor.OverallStatusChanged += OnUpdateAppStatusChanged;

                try
                {
                    appUpdater.Update(_updateAppCancellationTokenSource.Token);
                }
                finally
                {
                    appUpdater.Context.StatusMonitor.OverallStatusChanged -= OnUpdateAppStatusChanged;
                    _updateAppCancellationTokenSource = null;
                }
            }
        }
        private void ThreadExecuteUserDecision(CancellationToken cancellationToken)
        {
            bool displayWarningInsteadOfError = false;

            try
            {
                _warning.Value = string.Empty;

                DebugLogger.Log(string.Format("Executing user decision {0}...", _userDecision));

                switch (_userDecision)
                {
                case UserDecision.None:
                    break;

                case UserDecision.RepairApp:
                    break;

                case UserDecision.StartAppAutomatically:
                case UserDecision.StartApp:
                    ThreadStartApp();
                    break;

                case UserDecision.InstallAppAutomatically:
                    displayWarningInsteadOfError = _app.IsFullyInstalled();
                    ThreadUpdateApp(true, cancellationToken);
                    break;

                case UserDecision.InstallApp:
                    ThreadUpdateApp(false, cancellationToken);
                    break;

                case UserDecision.CheckForAppUpdatesAutomatically:
                    displayWarningInsteadOfError = _app.IsFullyInstalled();
                    ThreadUpdateApp(true, cancellationToken);
                    break;

                case UserDecision.CheckForAppUpdates:
                    ThreadUpdateApp(false, cancellationToken);
                    break;
                }

                DebugLogger.Log(string.Format("User decision {0} execution done.", _userDecision));
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log(string.Format("User decision {0} execution cancelled.", _userDecision));
            }
            catch (UnauthorizedAccessException e)
            {
                DebugLogger.Log(string.Format("User decision {0} execution issue: permissions failure.",
                                              _userDecision));
                DebugLogger.LogException(e);

                if (ThreadTryRestartWithRequestForPermissions())
                {
                    UnityDispatcher.Invoke(Quit);
                }
                else
                {
                    ThreadDisplayError(PatcherErrorMessage.NoPermissions(), cancellationToken);
                }
            }
            catch (ApiConnectionException e)
            {
                DebugLogger.LogException(e);

                if (displayWarningInsteadOfError)
                {
                    _warning.Value = "Unable to check for updates. Please check your internet connection.";
                }
                else
                {
                    ThreadDisplayError(PatcherErrorMessage.NoInternetConnection(), cancellationToken);
                }
            }
            catch (NotEnoughtDiskSpaceException e)
            {
                DebugLogger.LogException(e);
                ThreadDisplayError(PatcherErrorMessage.NotEnoughDiskSpace(e.RequiredSpace - e.AvailableSpace), cancellationToken);
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log(string.Format(
                                    "User decision {0} execution interrupted: thread has been interrupted. Rethrowing exception.",
                                    _userDecision));
                throw;
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log(string.Format(
                                    "User decision {0} execution aborted: thread has been aborted. Rethrowing exception.",
                                    _userDecision));
                throw;
            }
            catch (Exception exception)
            {
                DebugLogger.LogWarning(string.Format(
                                           "Error while executing user decision {0}: an exception has occured.", _userDecision));
                DebugLogger.LogException(exception);

                if (displayWarningInsteadOfError)
                {
                    _warning.Value = "Unable to check for updates. Please check your internet connection.";
                }
                else
                {
                    ThreadDisplayError(PatcherErrorMessage.Other(), cancellationToken);
                }
            }
        }
        private void ThreadWaitForUserDecision(CancellationToken cancellationToken)
        {
            try
            {
                DebugLogger.Log("Waiting for user decision...");

                _state.Value = PatcherState.WaitingForUserDecision;

                bool isInstalled = _app.IsFullyInstalled();

                DebugLogger.LogVariable(isInstalled, "isInstalled");

                bool canRepairApp          = false;        // not implemented
                bool canInstallApp         = !isInstalled;
                bool canCheckForAppUpdates = isInstalled;
                bool canStartApp           = isInstalled;

                _isAppInstalled.Value = isInstalled;

                _canRepairApp.Value          = false;
                _canInstallApp.Value         = false;
                _canCheckForAppUpdates.Value = false;
                _canStartApp.Value           = false;

                if (canInstallApp && _configuration.AutomaticallyInstallApp && !_hasAutomaticallyInstalledApp)
                {
                    DebugLogger.Log("Automatically deciding to install app.");
                    _hasAutomaticallyInstalledApp        = true;
                    _hasAutomaticallyCheckedForAppUpdate = true;
                    _userDecision = UserDecision.InstallAppAutomatically;
                    return;
                }

                if (canCheckForAppUpdates && _configuration.AutomaticallyCheckForAppUpdates &&
                    !_hasAutomaticallyCheckedForAppUpdate)
                {
                    DebugLogger.Log("Automatically deciding to check for app updates.");
                    _hasAutomaticallyInstalledApp        = true;
                    _hasAutomaticallyCheckedForAppUpdate = true;
                    _userDecision = UserDecision.CheckForAppUpdatesAutomatically;
                    return;
                }

                var updatesOnly = Environment.GetCommandLineArgs().Any(arg => arg.Equals("--updateOnly", StringComparison.OrdinalIgnoreCase));
                if (canStartApp && updatesOnly)
                {
                    _canStartApp.Value = true;
                    _userDecision      = UserDecision.AppUpdatesOnly;
                    return;
                }
                else
                {
                    if (canStartApp && _configuration.AutomaticallyStartApp && !_hasAutomaticallyStartedApp)
                    {
                        DebugLogger.Log("Automatically deciding to start app.");
                        _hasAutomaticallyStartedApp = true;
                        _userDecision = UserDecision.StartAppAutomatically;
                        return;
                    }

                    _canRepairApp.Value          = canRepairApp;
                    _canInstallApp.Value         = canInstallApp;
                    _canCheckForAppUpdates.Value = canCheckForAppUpdates;
                    _canStartApp.Value           = canStartApp;
                }
                _userDecisionSetEvent.Reset();
                using (cancellationToken.Register(() => _userDecisionSetEvent.Set()))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    _userDecisionSetEvent.WaitOne();
                }

                _canRepairApp.Value          = false;
                _canInstallApp.Value         = false;
                _canCheckForAppUpdates.Value = false;
                _canStartApp.Value           = false;

                cancellationToken.ThrowIfCancellationRequested();

                DebugLogger.Log(string.Format("Waiting for user decision result: {0}.", _userDecision));
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log("Waiting for user decision cancelled.");
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log("Waiting for user decision interrupted: thread has been interrupted. Rethrowing exception.");
                throw;
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log("Waiting for user decision aborted: thread has been aborted. Rethrowing exception.");
                throw;
            }
            catch (Exception)
            {
                DebugLogger.LogWarning("Error while waiting for user decision: an exception has occured. Rethrowing exception.");
                throw;
            }
        }
        private void ThreadExecution(CancellationToken cancellationToken)
        {
            try
            {
                _state.Value = PatcherState.None;

                DebugLogger.Log("Patcher thread started.");

                try
                {
                    ThreadLoadPatcherData();
                }
                catch (NonLauncherExecutionException)
                {
                    try
                    {
                        LauncherUtilities.ExecuteLauncher();
                        return;
                    }
                    catch (ApplicationException)
                    {
                        ThreadDisplayError(PatcherErrorMessage.NonLauncherExecution(), cancellationToken);
                        return;
                    }
                    finally
                    {
                        Quit();
                    }
                }

                EnsureSingleInstance();

                ThreadLoadPatcherConfiguration();

                UnityDispatcher.Invoke(() => _app = new App(_data.Value.AppDataPath, _data.Value.AppSecret, _data.Value.OverrideLatestVersionId, _requestTimeoutCalculator)).WaitOne();

                PatcherStatistics.TryDispatchSendEvent(PatcherStatistics.Event.PatcherStarted);

                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    ThreadWaitForUserDecision(cancellationToken);

                    cancellationToken.ThrowIfCancellationRequested();

                    ThreadExecuteUserDecision(cancellationToken);
                }
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log("Patcher thread finished: thread has been cancelled.");
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log("Patcher thread finished: thread has been interrupted.");
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log("Patcher thread finished: thread has been aborted.");
            }
            catch (MultipleInstancesException exception)
            {
                DebugLogger.LogException(exception);
                Quit();
            }
            catch (Exception exception)
            {
                DebugLogger.LogError("Patcher thread failed: an exception has occured.");
                DebugLogger.LogException(exception);
            }
            finally
            {
                _state.Value = PatcherState.None;
            }
        }
        public static void TryExecute(Action action, IRequestRetryStrategy retryStrategy, PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            do
            {
                try
                {
                    action();
                    return;
                }
                catch (IOException e)
                {
                    retryStrategy.OnRequestFailure();

                    if (!retryStrategy.ShouldRetry)
                    {
                        DebugLogger.LogError(string.Format("An IO Exception has occured: {0}. rethrowing.", e));
                        throw;
                    }

                    DebugLogger.LogWarning(string.Format("An IO Exception has occured: {0}. retrying...", e));
                    Threading.CancelableSleep(retryStrategy.DelayBeforeNextTry, cancellationToken);
                }
            } while (retryStrategy.ShouldRetry);
        }
 public static void TryExecute(Action action, PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
 {
     TryExecute(action, new RetryStrategy(), cancellationToken);
 }
Exemple #21
0
        private void ThreadWaitForUserDecision(CancellationToken cancellationToken)
        {
            try
            {
                DebugLogger.Log("Waiting for user decision...");

                _state.Value = PatcherState.WaitingForUserDecision;

                bool isInstalled = _app.IsInstalled();

                DebugLogger.LogVariable(isInstalled, "isInstalled");

                _canRepairApp.Value          = false; // not implemented
                _canInstallApp.Value         = !isInstalled;
                _canCheckForAppUpdates.Value = isInstalled;
                _canStartApp.Value           = isInstalled;

                if (_canInstallApp.Value && _configuration.AutomaticallyInstallApp && !_hasAutomaticallyInstalledApp)
                {
                    DebugLogger.Log("Automatically deciding to install app.");
                    _hasAutomaticallyInstalledApp = true;
                    _userDecision = UserDecision.InstallAppAutomatically;
                    return;
                }

                if (_canCheckForAppUpdates.Value && _configuration.AutomaticallyCheckForAppUpdates &&
                    !_hasAutomaticallyCheckedForAppUpdate)
                {
                    DebugLogger.Log("Automatically deciding to check for app updates.");
                    _hasAutomaticallyCheckedForAppUpdate = true;
                    _userDecision = UserDecision.CheckForAppUpdatesAutomatically;
                    return;
                }

                if (_canStartApp.Value && _configuration.AutomaticallyStartApp && !_hasAutomaticallyStartedApp)
                {
                    DebugLogger.Log("Automatically deciding to start app.");
                    _hasAutomaticallyStartedApp = true;
                    _userDecision = UserDecision.StartAppAutomatically;
                    return;
                }

                _userDecisionSetEvent.Reset();
                using (cancellationToken.Register(() => _userDecisionSetEvent.Set()))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    _userDecisionSetEvent.WaitOne();
                }
                cancellationToken.ThrowIfCancellationRequested();

                DebugLogger.Log(string.Format("Waiting for user decision result: {0}.", _userDecision));
            }
            catch (OperationCanceledException)
            {
                DebugLogger.Log("Waiting for user decision cancelled.");
            }
            catch (ThreadInterruptedException)
            {
                DebugLogger.Log("Waiting for user decision interrupted: thread has been interrupted. Rethrowing exception.");
                throw;
            }
            catch (ThreadAbortException)
            {
                DebugLogger.Log("Waiting for user decision aborted: thread has been aborted. Rethrowing exception.");
                throw;
            }
            catch (Exception)
            {
                DebugLogger.LogWarning("Error while waiting for user decision: an exception has occured. Rethrowing exception.");
                throw;
            }
        }
Exemple #22
0
        private void PreUpdate(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            var appRepairer = new AppRepairer(Context, _status);

            appRepairer.Perform(cancellationToken);
        }
        private void PreUpdate(PatchKit.Unity.Patcher.Cancellation.CancellationToken cancellationToken)
        {
            DebugLogger.Log("Pre update integrity check");

            var commandFactory = new AppUpdaterCommandFactory();

            int installedVersionId         = Context.App.GetInstalledVersionId();
            int latestVersionId            = Context.App.GetLatestVersionId();
            int lowestVersionWithContentId = Context.App.GetLowestVersionWithContentId();

            if (lowestVersionWithContentId > installedVersionId)
            {
                DebugLogger.Log(
                    "Repair is impossible because lowest version with content id is "
                    + lowestVersionWithContentId +
                    " and currently installed version id is "
                    + installedVersionId +
                    ". Uninstalling to prepare for content strategy.");

                IUninstallCommand uninstall = commandFactory.CreateUninstallCommand(Context);
                uninstall.Prepare(_status);
                uninstall.Execute(cancellationToken);
                return;
            }

            AppContentSummary installedVersionContentSummary
                = Context.App.RemoteMetaData.GetContentSummary(installedVersionId);

            AppContentSummary latestVersionContentSummary
                = Context.App.RemoteMetaData.GetContentSummary(latestVersionId);

            bool isNewVersionAvailable = installedVersionId < latestVersionId;

            long contentSize = isNewVersionAvailable
                ? latestVersionContentSummary.Size
                : installedVersionContentSummary.Size;

            ICheckVersionIntegrityCommand checkIntegrity = commandFactory
                                                           .CreateCheckVersionIntegrityCommand(
                versionId: installedVersionId,
                context: Context,
                isCheckingHash: false,
                isCheckingSize: true);

            checkIntegrity.Prepare(_status);
            checkIntegrity.Execute(cancellationToken);

            var missingFiles = checkIntegrity.Results.Files
                               .Where(f => f.Status == FileIntegrityStatus.MissingData);

            int missingFilesCount = missingFiles.Count();

            var invalidSizeFiles = checkIntegrity.Results.Files
                                   .Where(f => f.Status == FileIntegrityStatus.InvalidSize);

            int invalidSizeFilesCount = invalidSizeFiles.Count();

            if (missingFilesCount + invalidSizeFilesCount == 0)
            {
                DebugLogger.Log("No missing or invalid size files.");
                return;
            }

            double repairCost = CalculateRepairCost(installedVersionContentSummary, missingFiles.Concat(invalidSizeFiles));

            if (repairCost < contentSize)
            {
                DebugLogger.Log(string.Format("Repair cost {0} is smaller than content cost {1}, repairing...", repairCost, contentSize));
                IAppUpdaterStrategy repairStrategy = _strategyResolver.Create(StrategyType.Repair, Context);
                repairStrategy.Update(cancellationToken);
            }
            else
            {
                DebugLogger.Log("Content cost is smaller than repair. Uninstalling to prepare for content strategy.");
                IUninstallCommand uninstall = commandFactory.CreateUninstallCommand(Context);
                uninstall.Prepare(_status);
                uninstall.Execute(cancellationToken);
            }
        }