Exemplo n.º 1
0
        public void Update(CancellationToken cancellationToken)
        {
            Assert.MethodCalledOnlyOnce(ref _updateHasBeenCalled, "Update");
            Assert.ApplicationIsInstalled(_context.App);

            DebugLogger.Log("Updating with diff strategy.");

            var latestVersionId       = _context.App.GetLatestVersionId();
            var currentLocalVersionId = _context.App.GetInstalledVersionId();

            DebugLogger.LogVariable(latestVersionId, "latestVersionId");
            DebugLogger.LogVariable(currentLocalVersionId, "currentLocalVersionId");

            var commandFactory   = new AppUpdaterCommandFactory();
            var geolocateCommand = commandFactory.CreateGeolocateCommand();

            geolocateCommand.Prepare(_context.StatusMonitor);
            geolocateCommand.Execute(cancellationToken);

            var checkDiskSpaceCommand = commandFactory.CreateCheckDiskSpaceCommandForDiff(latestVersionId, _context);

            checkDiskSpaceCommand.Prepare(_context.StatusMonitor);
            checkDiskSpaceCommand.Execute(cancellationToken);

            var validateLicense = commandFactory.CreateValidateLicenseCommand(_context);

            validateLicense.Prepare(_context.StatusMonitor);
            validateLicense.Execute(cancellationToken);

            var diffCommandsList = new List <DiffCommands>();

            for (int i = currentLocalVersionId + 1; i <= latestVersionId; i++)
            {
                DiffCommands diffCommands;

                diffCommands.Download = commandFactory.CreateDownloadDiffPackageCommand(i, validateLicense.KeySecret,
                                                                                        geolocateCommand.CountryCode, _context);
                diffCommands.Download.Prepare(_context.StatusMonitor);

                diffCommands.Install = commandFactory.CreateInstallDiffCommand(i, _context);
                diffCommands.Install.Prepare(_context.StatusMonitor);

                diffCommandsList.Add(diffCommands);
            }

            foreach (var diffCommands in diffCommandsList)
            {
                diffCommands.Download.Execute(cancellationToken);
                diffCommands.Install.Execute(cancellationToken);
            }

            _context.App.DownloadDirectory.Clear();
        }
        public AppRepairer(AppUpdaterContext context, UpdaterStatus status)
        {
            DebugLogger.LogConstructor();

            Checks.ArgumentNotNull(context, "context");

            Context = context;
            _status = status;

            _strategyResolver = new AppUpdaterStrategyResolver(_status);
            _commandFactory   = new AppUpdaterCommandFactory();
        }
Exemplo n.º 3
0
        private bool IsVersionIntegral(long contentSize, AppUpdaterContext context, CancellationToken cancellationToken)
        {
            var commandFactory     = new AppUpdaterCommandFactory();
            int installedVersionId = context.App.GetInstalledVersionId();

            _logger.LogTrace("installedVersionId = " + installedVersionId);
            _logger.LogTrace("context.Configuration.HashSizeThreshold = " + context.Configuration.HashSizeThreshold);

            bool isCheckingHash = contentSize < context.Configuration.HashSizeThreshold;

            _logger.LogTrace("isCheckingHash = " + isCheckingHash);

            var checkVersionIntegrity = commandFactory.CreateCheckVersionIntegrityCommand(
                installedVersionId, context, isCheckingHash, true, cancellationToken);

            checkVersionIntegrity.Prepare(_status, cancellationToken);
            checkVersionIntegrity.Execute(CancellationToken.Empty);

            bool isValid = checkVersionIntegrity.Results.Files.All(
                fileIntegrity => fileIntegrity.Status == FileIntegrityStatus.Ok);

            if (!isValid)
            {
                foreach (var fileIntegrity in checkVersionIntegrity.Results.Files)
                {
                    if (fileIntegrity.Status != FileIntegrityStatus.Ok)
                    {
                        string logMessage = string.Format("File {0} is not consistent - {1}",
                                                          fileIntegrity.FileName, fileIntegrity.Status);

                        if (!string.IsNullOrEmpty(fileIntegrity.Message))
                        {
                            logMessage += " - " + fileIntegrity.Message;
                        }

                        _logger.LogDebug(logMessage);
                    }
                }
            }

            return(isValid);
        }
Exemplo n.º 4
0
        private bool IsCheckIntegrityValid(AppUpdaterContext context)
        {
            var  commandFactory     = new AppUpdaterCommandFactory();
            int  installedVersionId = context.App.GetInstalledVersionId();
            long contentCost        = GetContentCost(context); // bytes

            long sizeThreshold  = context.Configuration.HashSizeThreshold;
            bool isCheckingHash = contentCost < sizeThreshold;

            DebugLogger.LogFormat("IsCheckingHash: {0}, for content size: {1} and contentSizeThreshold: {2}",
                                  isCheckingHash, contentCost, sizeThreshold);

            var checkVersionIntegrity = commandFactory.CreateCheckVersionIntegrityCommand(
                installedVersionId, context, isCheckingHash);

            checkVersionIntegrity.Prepare(context.StatusMonitor);
            checkVersionIntegrity.Execute(CancellationToken.Empty);

            bool isValid = checkVersionIntegrity.Results.Files.All(
                fileIntegrity => fileIntegrity.Status == FileIntegrityStatus.Ok);

            if (isValid)
            {
                DebugLogger.Log("Version is consistent. Diff update is allowed.");
            }
            else
            {
                foreach (var fileIntegrity in checkVersionIntegrity.Results.Files)
                {
                    if (fileIntegrity.Status != FileIntegrityStatus.Ok)
                    {
                        DebugLogger.Log(string.Format("File {0} is not consistent - {1}",
                                                      fileIntegrity.FileName, fileIntegrity.Status));
                    }
                }

                DebugLogger.Log(
                    "Version is not consistent. Diff update is forbidden - using content strategy.");
            }

            return(isValid);
        }
        public void Update(CancellationToken cancellationToken)
        {
            Assert.MethodCalledOnlyOnce(ref _updateHasBeenCalled, "Update");
            Assert.ApplicationIsInstalled(_context.App);

            DebugLogger.Log("Updating with diff strategy.");

            var latestVersionId       = _context.App.GetLatestVersionId(true, cancellationToken);
            var currentLocalVersionId = _context.App.GetInstalledVersionId();

            DebugLogger.LogVariable(latestVersionId, "latestVersionId");
            DebugLogger.LogVariable(currentLocalVersionId, "currentLocalVersionId");

            var commandFactory   = new AppUpdaterCommandFactory();
            var geolocateCommand = commandFactory.CreateGeolocateCommand();

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

            var checkDiskSpaceCommand = commandFactory.CreateCheckDiskSpaceCommandForDiff(latestVersionId, _context, cancellationToken);

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

            var validateLicense = commandFactory.CreateValidateLicenseCommand(_context);

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

            var diffCommandsList = new List <DiffCommands>();

            for (int i = currentLocalVersionId + 1; i <= latestVersionId; i++)
            {
                DiffCommands diffCommands;

                var resource = _context.App.RemoteData.GetDiffPackageResource(i, validateLicense.KeySecret, geolocateCommand.CountryCode, cancellationToken);

                diffCommands.Download = new DiffCommands.Context <IDownloadPackageCommand> {
                    Command = commandFactory.CreateDownloadDiffPackageCommand(i, validateLicense.KeySecret,
                                                                              geolocateCommand.CountryCode, _context, cancellationToken),
                    VersionId = i,
                    Size      = resource.Size,
                };
                diffCommands.Download.Command.Prepare(_status, cancellationToken);

                diffCommands.Install = commandFactory.CreateInstallDiffCommand(i, _context);
                diffCommands.Install.Prepare(_status, cancellationToken);

                diffCommandsList.Add(diffCommands);
            }

            foreach (var diffCommands in diffCommandsList)
            {
                var optionalParams = new PatcherStatistics.OptionalParams
                {
                    Size      = diffCommands.Download.Size,
                    VersionId = diffCommands.Download.VersionId
                };

                try
                {
                    PatcherStatistics.DispatchSendEvent(PatcherStatistics.Event.PatchDownloadStarted, optionalParams);
                    diffCommands.Download.Command.Execute(cancellationToken);
                    PatcherStatistics.DispatchSendEvent(PatcherStatistics.Event.PatchDownloadSucceeded, optionalParams);
                }
                catch (OperationCanceledException)
                {
                    PatcherStatistics.DispatchSendEvent(PatcherStatistics.Event.PatchDownloadCanceled, optionalParams);
                    throw;
                }
                catch (Exception)
                {
                    PatcherStatistics.DispatchSendEvent(PatcherStatistics.Event.PatchDownloadFailed, optionalParams);
                    throw;
                }

                diffCommands.Install.Execute(cancellationToken);
            }

            _context.App.DownloadDirectory.Clear();
        }
        public void Update(CancellationToken cancellationToken)
        {
            _logger.LogDebug("Executing content repair strategy.");
            var installedVersionId = _context.App.GetInstalledVersionId();

            string metaDestination = _context.App.DownloadDirectory.GetDiffPackageMetaPath(installedVersionId);

            var commandFactory = new AppUpdaterCommandFactory();

            var validateLicense = commandFactory.CreateValidateLicenseCommand(_context);

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

            var geolocateCommand = commandFactory.CreateGeolocateCommand();

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

            var resource = _context.App.RemoteData.GetContentPackageResource(
                installedVersionId,
                validateLicense.KeySecret,
                geolocateCommand.CountryCode,
                cancellationToken);

            if (!resource.HasMetaUrls())
            {
                throw new ArgumentException("Cannot execute content repair strategy without meta files.");
            }

            _logger.LogDebug("Downloading the meta file.");
            var downloader = new HttpDownloader(metaDestination, resource.GetMetaUrls());

            downloader.Download(cancellationToken);

            ICheckVersionIntegrityCommand checkVersionIntegrityCommand
                = commandFactory.CreateCheckVersionIntegrityCommand(installedVersionId, _context, true, true, cancellationToken);

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

            var meta = Pack1Meta.ParseFromFile(metaDestination);

            FileIntegrity[] filesIntegrity = checkVersionIntegrityCommand.Results.Files;

            var contentSummary = _context.App.RemoteMetaData.GetContentSummary(installedVersionId, cancellationToken);

            foreach (var invalidVersionIdFile in filesIntegrity.Where(x =>
                                                                      x.Status == FileIntegrityStatus.InvalidVersion).ToArray())
            {
                var fileName = invalidVersionIdFile.FileName;
                var file     = contentSummary.Files.First(x => x.Path == fileName);

                var localPath = _context.App.LocalDirectory.Path.PathCombine(file.Path);

                string actualFileHash = HashCalculator.ComputeFileHash(localPath);
                if (actualFileHash != file.Hash)
                {
                    FileOperations.Delete(localPath, cancellationToken);
                    _context.App.LocalMetaData.RegisterEntry(fileName, installedVersionId);
                    invalidVersionIdFile.Status = FileIntegrityStatus.MissingData;
                }
                else
                {
                    _context.App.LocalMetaData.RegisterEntry(fileName, installedVersionId);
                    invalidVersionIdFile.Status = FileIntegrityStatus.Ok;
                }
            }

            Pack1Meta.FileEntry[] brokenFiles = filesIntegrity
                                                // Filter only files with invalid size, hash or missing entirely
                                                .Where(f => f.Status == FileIntegrityStatus.InvalidHash ||
                                                       f.Status == FileIntegrityStatus.InvalidSize ||
                                                       f.Status == FileIntegrityStatus.MissingData)
                                                // Map to file entires from meta
                                                .Select(integrity => meta.Files.SingleOrDefault(file => file.Name == integrity.FileName))
                                                // Filter only regular files
                                                .Where(file => file.Type == Pack1Meta.RegularFileType)
                                                .ToArray();

            if (brokenFiles.Length == 0)
            {
                _logger.LogDebug("Nothing to repair.");
                return;
            }
            _logger.LogDebug(string.Format("Broken files count: {0}", brokenFiles.Length));

            IRepairFilesCommand repairCommand = commandFactory.CreateRepairFilesCommand(
                installedVersionId,
                _context,
                resource,
                brokenFiles,
                meta);

            repairCommand.Prepare(_status, cancellationToken);
            repairCommand.Execute(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);
            }
        }
        public IAppUpdaterStrategy Resolve(AppUpdaterContext context)
        {
            Checks.ArgumentNotNull(context, "context");

            DebugLogger.Log("Resolving best strategy for updating...");

            if (context.App.IsInstalled())
            {
                int installedVersionId = context.App.GetInstalledVersionId();
                int latestVersionId    = context.App.GetLatestVersionId();

                if (installedVersionId == latestVersionId)
                {
                    DebugLogger.Log("Installed version is the same as the latest version. Using empty strategy.");

                    return(new AppUpdaterEmptyStrategy());
                }

                if (installedVersionId < latestVersionId)
                {
                    DebugLogger.Log("Installed version is older than the latest version. Checking whether cost of updating with diff is lower than cost of updating with content...");

                    if (context.Configuration.CheckConsistencyBeforeDiffUpdate)
                    {
                        DebugLogger.Log("Checking consitency before allowing diff update...");

                        var commandFactory = new AppUpdaterCommandFactory();

                        var checkVersionIntegrity = commandFactory.CreateCheckVersionIntegrityCommand(
                            installedVersionId, context);

                        checkVersionIntegrity.Prepare(context.StatusMonitor);
                        checkVersionIntegrity.Execute(CancellationToken.Empty);

                        if (checkVersionIntegrity.Results.Files.All(
                                fileIntegrity => fileIntegrity.Status == FileIntegrityStatus.Ok))
                        {
                            DebugLogger.Log("Version is consistent. Diff update is allowed.");
                        }
                        else
                        {
                            foreach (var fileIntegrity in checkVersionIntegrity.Results.Files)
                            {
                                if (fileIntegrity.Status != FileIntegrityStatus.Ok)
                                {
                                    DebugLogger.Log(string.Format("File {0} is not consistent - {1}",
                                                                  fileIntegrity.FileName, fileIntegrity.Status));
                                }
                            }

                            DebugLogger.Log(
                                "Version is not consistent. Diff update is forbidden - using content strategy.");

                            return(new AppUpdaterContentStrategy(context));
                        }
                    }

                    var diffCost = GetDiffCost(context);
                    DebugLogger.LogVariable(diffCost, "diffCost");

                    DebugLogger.Log(string.Format("Cost of updating with diff equals {0}.", diffCost));

                    var contentCost = GetContentCost(context);
                    DebugLogger.LogVariable(contentCost, "contentCost");

                    DebugLogger.Log(string.Format("Cost of updating with content equals {0}.", contentCost));

                    if (diffCost < contentCost)
                    {
                        DebugLogger.Log("Cost of updating with diff is lower than cost of updating with content. Using diff strategy.");

                        return(new AppUpdaterDiffStrategy(context));
                    }

                    DebugLogger.Log("Cost of updating with content is lower than cost of updating with diff. Using content strategy.");
                }
                else
                {
                    DebugLogger.Log("Installed version is newer than the latest version. Using content strategy.");
                }
            }
            else
            {
                DebugLogger.Log("Application is not installed. Using content strategy.");
            }

            return(new AppUpdaterContentStrategy(context));
        }