private static ApplicationUninstallerEntry GetSteamUninstallerEntry()
        {
            if (string.IsNullOrEmpty(SteamFactory.SteamLocation))
            {
                return(null);
            }

            return(new ApplicationUninstallerEntry
            {
                AboutUrl = @"http://store.steampowered.com/about/",
                InstallLocation = SteamFactory.SteamLocation,
                DisplayIcon = Path.Combine(SteamFactory.SteamLocation, "Steam.exe"),
                DisplayName = "Steam",
                UninstallerKind = UninstallerType.Nsis,
                UninstallString = Path.Combine(SteamFactory.SteamLocation, "uninstall.exe"),
                IsOrphaned = true,
                IsValid = File.Exists(Path.Combine(SteamFactory.SteamLocation, "uninstall.exe")),
                InstallDate = Directory.GetCreationTime(SteamFactory.SteamLocation),
                Publisher = "Valve Corporation",
                // Prevent very long size scan in case of many games, the install itself is about 600-800MB
                EstimatedSize = FileSize.FromKilobytes(1024 * 700)
            });
        }
예제 #2
0
        private async void ModUpdateProgress_Shown(object sender, EventArgs e)
        {
            var averageDownloadSpeed = new MovingAverage(20);
            var downloadStartTime    = DateTime.MinValue;

            try
            {
                #region Initialize UI

                progressBar1.Style   = ProgressBarStyle.Marquee;
                progressBar1.Value   = 0;
                progressBar1.Maximum = 1;

                labelPercent.Text = "";

                checkBoxSleep.Enabled = false;

                var random = new Random();
                if (random.Next(0, 10) >= 8)
                {
                    var offset    = random.Next(20, 80);
                    var offsetStr = new string(Enumerable.Repeat(' ', offset).ToArray());
                    labelPercent.Text  = offsetStr + " ( )  ( )\n";
                    labelPercent.Text += offsetStr + "( o . o)";
                }

                olvColumnProgress.Renderer     = new BarRenderer(0, 100);
                olvColumnProgress.AspectGetter = rowObject => (int)Math.Round(((UpdateDownloadItem)rowObject).FinishPercent);
                olvColumnSize.AspectGetter     = rowObject => ((UpdateDownloadItem)rowObject).TotalSize;
                //olvColumnDownloaded.AspectGetter = rowObject => ((UpdateDownloadItem)rowObject).GetDownloadedSize();
                olvColumnStatus.AspectGetter = rowObject =>
                {
                    var item = (UpdateDownloadItem)rowObject;
                    return(item.Exceptions.Count == 0
                        ? item.Status.ToString()
                        : item.Status + " - " + string.Join("; ", item.Exceptions.Select(x => x.Message)));
                };
                olvColumnName.AspectGetter = rowObject => ((UpdateDownloadItem)rowObject).DownloadPath.Name;
                olvColumnNo.AspectGetter   = rowObject => ((UpdateDownloadItem)rowObject).Order;

                fastObjectListView1.PrimarySortColumn   = olvColumnStatus;
                fastObjectListView1.SecondarySortColumn = olvColumnNo;
                fastObjectListView1.Sorting             = SortOrder.Ascending;
                fastObjectListView1.PrimarySortOrder    = SortOrder.Ascending;
                fastObjectListView1.SecondarySortOrder  = SortOrder.Ascending;
                fastObjectListView1.ShowSortIndicators  = true;
                fastObjectListView1.Sort();
                fastObjectListView1.ShowSortIndicator();

                _overallSize = _completedSize = FileSize.Empty;

                #endregion

                SetStatus("Preparing...");
                if (await ProcessWaiter.CheckForProcessesBlockingKoiDir() == false)
                {
                    throw new OperationCanceledException();
                }

                #region Find and select updates

                SetStatus("Searching for mod updates...");
                labelPercent.Text = "Please wait, this might take a couple of minutes.";
                var updateTasks = await UpdateSourceManager.GetUpdates(_cancelToken.Token, _updaters, _autoInstallGuids);

                _cancelToken.Token.ThrowIfCancellationRequested();

                progressBar1.Style = ProgressBarStyle.Blocks;

                if (updateTasks.All(x => x.UpToDate))
                {
                    SetStatus("Everything is up to date!");
                    progressBar1.Value = progressBar1.Maximum;
                    _cancelToken.Cancel();
                    return;
                }

                var isAutoInstall = _autoInstallGuids != null && _autoInstallGuids.Length > 0;
                if (!isAutoInstall)
                {
                    SetStatus($"Found {updateTasks.Count} updates, waiting for user confirmation.");
                    updateTasks = ModUpdateSelectDialog.ShowWindow(this, updateTasks);
                }
                else
                {
                    var skipped = updateTasks.RemoveAll(x => x.UpToDate);
                    SetStatus($"Found {updateTasks.Count} update tasks in silent mode, {skipped} are already up-to-date.", true, true);
                }

                if (updateTasks == null)
                {
                    throw new OperationCanceledException();
                }

                #endregion

                SleepControls.PreventSleepOrShutdown(Handle, "Update is in progress");

                #region Set up update downloader and start downloading

                downloadStartTime = DateTime.Now;

                var downloader    = UpdateDownloadCoordinator.Create(updateTasks);
                var downloadItems = downloader.UpdateItems;

                SetStatus($"{downloadItems.Count(items => items.DownloadSources.Count > 1)} out of {downloadItems.Count} items have more than 1 source", false, true);

                fastObjectListView1.Objects = downloadItems;

                progressBar1.Maximum  = 1000;
                progressBar1.Value    = 0;
                checkBoxSleep.Enabled = true;

                _overallSize = FileSize.SumFileSizes(downloadItems.Select(x => x.TotalSize));

                var lastCompletedSize = FileSize.Empty;
                updateTimer.Tick += (o, args) =>
                {
                    var itemCount = fastObjectListView1.GetItemCount();
                    if (itemCount > 0)
                    {
                        fastObjectListView1.BeginUpdate();
                        fastObjectListView1.RedrawItems(0, itemCount - 1, true);
                        // Needed if user changes sorting column
                        //fastObjectListView1.SecondarySortColumn = olvColumnNo;
                        fastObjectListView1.Sort();
                        fastObjectListView1.EndUpdate();
                    }

                    _completedSize = FileSize.SumFileSizes(downloadItems.Select(x => x.GetDownloadedSize()));

                    var totalPercent = (double)_completedSize.GetKbSize() / (double)_overallSize.GetKbSize() * 100d;
                    if (double.IsNaN(totalPercent))
                    {
                        totalPercent = 0;
                    }

                    // Download speed calc
                    var secondsPassed       = updateTimer.Interval / 1000d;
                    var downloadedSinceLast = FileSize.FromKilobytes((long)((_completedSize - lastCompletedSize).GetKbSize() / secondsPassed));
                    lastCompletedSize = _completedSize;
                    averageDownloadSpeed.Sample(downloadedSinceLast.GetKbSize());
                    var etaSeconds = (_overallSize - _completedSize).GetKbSize() / (double)averageDownloadSpeed.GetAverage();
                    var eta = double.IsNaN(etaSeconds) || etaSeconds <0 || etaSeconds> TimeSpan.MaxValue.TotalSeconds
                        ? "Unknown"
                        : TimeSpan.FromSeconds(etaSeconds).GetReadableTimespan();

                    labelPercent.Text =
                        $"Overall: {totalPercent:F1}% done  ({_completedSize} out of {_overallSize})\r\n" +
                        $"Speed: {downloadedSinceLast}/s  (ETA: {eta})";
                    //$"Speed: {downloadedSinceLast:F1}KB/s";

                    progressBar1.Value = Math.Min((int)Math.Round(totalPercent * 10), progressBar1.Maximum);
                };
                updateTimer.Start();

                SetStatus("Downloading updates...", true, true);

                await downloader.RunUpdate(_cancelToken.Token);

                _cancelToken.Token.ThrowIfCancellationRequested();

                #endregion

                #region Show finish messages

                var failedItems     = downloadItems.Where(x => x.Status == UpdateDownloadStatus.Failed).ToList();
                var unfinishedCount = downloadItems.Count(x => x.Status != UpdateDownloadStatus.Finished);

                var s = $"Successfully updated/removed {downloadItems.Count - unfinishedCount} files from {updateTasks.Count} tasks.";
                if (failedItems.Any())
                {
                    s += $"\nFailed to update {failedItems.Count} files because some sources crashed. Check log for details.";
                }

                SetStatus(s, true, true);

                updateTimer.Stop();
                progressBar1.Value = progressBar1.Maximum;
                labelPercent.Text  = "";

                if (failedItems.Any(x => x.Exceptions.Count > 0))
                {
                    var exceptionMessages = failedItems
                                            .SelectMany(x => x.Exceptions)
                                            .Where(y => !(y is DownloadSourceCrashedException))
                                            // Deal with wrapped exceptions
                                            .Select(y => y.Message.Contains("InnerException") && y.InnerException != null ? y.InnerException.Message : y.Message)
                                            .Distinct();

                    var failDetails = "Reason(s) for failing:\n" + string.Join("\n", exceptionMessages);
                    Console.WriteLine(failDetails);
                    s += " " + failDetails;
                }

                // Sleep before showing a messagebox since the box will block until user clicks ok
                SleepIfNecessary();

                MessageBox.Show(s, "Finished updating", MessageBoxButtons.OK, MessageBoxIcon.Information);

                #endregion
            }
            catch (OutdatedVersionException ex)
            {
                SetStatus("KK Manager needs to be updated to get updates.", true, true);
                ex.ShowKkmanOutdatedMessage();
            }
            catch (OperationCanceledException)
            {
                SetStatus("Update was cancelled by the user.", true, true);
            }
            catch (Exception ex)
            {
                var exceptions = ex is AggregateException aex?aex.Flatten().InnerExceptions : (ICollection <Exception>) new[] { ex };

                if (!exceptions.Any(x => x is OperationCanceledException))
                {
                    SleepIfNecessary();
                }

                SetStatus("Unexpected crash while updating mods, aborting.", true, true);
                SetStatus(string.Join("\n---\n", exceptions), false, true);
                MessageBox.Show("Something unexpected happened and the update could not be completed. Make sure that your internet connection is stable, " +
                                "and that you did not hit your download limits, then try again.\n\nError message (check log for more):\n" + string.Join("\n", exceptions.Select(x => x.Message)),
                                "Update failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                updateTimer.Stop();
                checkBoxSleep.Enabled = false;

                fastObjectListView1.EmptyListMsg = "Nothing was downloaded";

                _cancelToken.Cancel();

                labelPercent.Text = "";
                if (_completedSize != FileSize.Empty)
                {
                    labelPercent.Text += $"Downloaded {_completedSize} out of {_overallSize}";
                    if (downloadStartTime != DateTime.MinValue)
                    {
                        var timeSpent = DateTime.Now - downloadStartTime;
                        labelPercent.Text += $" in {timeSpent.GetReadableTimespan()}";
                    }
                    labelPercent.Text += "\n";
                }
                var averageDlSpeed = averageDownloadSpeed.GetAverage();
                if (averageDlSpeed > 0)
                {
                    labelPercent.Text += $"Average download speed: {new FileSize(averageDlSpeed)}/s";
                }

                progressBar1.Style = ProgressBarStyle.Blocks;
                button1.Enabled    = true;
                button1.Text       = "OK";

                if (_autoInstallGuids != null && _autoInstallGuids.Length > 0)
                {
                    Close();
                }

                SleepControls.AllowSleepOrShutdown(Handle);
            }
        }
예제 #3
0
        private static ApplicationUninstallerEntry GetOneDrive()
        {
            var result = new ApplicationUninstallerEntry();

            // Check if installed
            try
            {
                using (var key = RegistryTools.OpenRegistryKey(@"HKEY_CURRENT_USER\SOFTWARE\Microsoft\OneDrive", false))
                {
                    result.RegistryPath    = key.Name;
                    result.RegistryKeyName = key.GetKeyName();

                    result.InstallLocation = key.GetValue("CurrentVersionPath") as string;
                    if (result.InstallLocation == null || !Directory.Exists(result.InstallLocation))
                    {
                        return(null);
                    }

                    result.DisplayIcon    = key.GetValue("OneDriveTrigger") as string;
                    result.DisplayVersion = ApplicationEntryTools.CleanupDisplayVersion(key.GetValue("Version") as string);
                }
            }
            catch
            {
                return(null);
            }

            // Check if the uninstaller is available
            var systemRoot    = WindowsTools.GetEnvironmentPath(CSIDL.CSIDL_WINDOWS);
            var uninstallPath = Path.Combine(systemRoot, @"System32\OneDriveSetup.exe");

            if (!File.Exists(uninstallPath))
            {
                uninstallPath = Path.Combine(systemRoot, @"SysWOW64\OneDriveSetup.exe");
                if (!File.Exists(uninstallPath))
                {
                    uninstallPath = null;
                }
            }

            if (uninstallPath != null)
            {
                result.IsValid              = true;
                result.UninstallString      = $"\"{uninstallPath}\" /uninstall";
                result.QuietUninstallString = result.UninstallString;
                if (!File.Exists(result.DisplayIcon))
                {
                    result.DisplayIcon = uninstallPath;
                }
            }

            result.AboutUrl       = @"https://onedrive.live.com/";
            result.RawDisplayName = "OneDrive";
            result.Publisher      = "Microsoft Corporation";
            result.EstimatedSize  = FileSize.FromKilobytes(1024 * 90);
            result.Is64Bit        = MachineType.X86;
            result.IsRegistered   = true;

            result.UninstallerKind = UninstallerType.Unknown;

            result.InstallDate = Directory.GetCreationTime(result.InstallLocation);

            if (!string.IsNullOrEmpty(result.DisplayIcon))
            {
                result.IconBitmap = UninstallToolsGlobalConfig.TryExtractAssociatedIcon(result.DisplayIcon);
            }

            return(result);
        }
예제 #4
0
        private static FileSize GetEstimatedSize(RegistryKey uninstallerKey)
        {
            var tempSize = (int)uninstallerKey.GetValue(ApplicationUninstallerEntry.RegistryNameEstimatedSize, 0);

            return(FileSize.FromKilobytes(tempSize));
        }
        private async Task <bool> UpdateSingleItem(IGrouping <string, Tuple <UpdateInfo, UpdateItem> > task)
        {
            var firstItem = task.First().Item2;
            var itemSize  = firstItem.GetDownloadSize();

            var lastTimestamp        = DateTime.UtcNow;
            var lastDownloadedKBytes = 0l;

            var progress = new Progress <double>(thisPercent =>
            {
                var timeNow = DateTime.UtcNow;
                var secondsSinceLastUpdate = (timeNow - lastTimestamp).TotalSeconds;

                if (secondsSinceLastUpdate < 1 && thisPercent < 100)
                {
                    return;
                }

                //This item: 70% done (1MB / 20MB)
                //Overall: 50% done (111MB / 1221MB)
                //Speed: 1234KB/s (average 1111KB/s)

                var downloadedKBytes    = (long)(itemSize.GetRawSize() * (thisPercent / 100d));
                var downloadedSize      = FileSize.FromKilobytes(downloadedKBytes);
                var totalDownloadedSize = _completedSize + downloadedSize;
                var totalPercent        = ((double)totalDownloadedSize.GetRawSize() / (double)_overallSize.GetRawSize()) * 100d;

                var speed = (downloadedKBytes - lastDownloadedKBytes) / secondsSinceLastUpdate;
                if (double.IsNaN(speed))
                {
                    speed = 0;
                }
                lastDownloadedKBytes = downloadedKBytes;
                lastTimestamp        = timeNow;

                labelPercent.Text =
                    $@"This item: {thisPercent:F1}% done ({downloadedSize} / {itemSize})
Overall: {totalPercent:F1}% done ({totalDownloadedSize} / {_overallSize})
Speed: {speed:F1}KB/s";

                progressBar1.Value = Math.Min((int)(totalPercent * 10), progressBar1.Maximum);
            });

            SetStatus($"Updating {firstItem.TargetPath.Name}");
            SetStatus($"Updating {InstallDirectoryHelper.GetRelativePath(firstItem.TargetPath)}", false, true);

            var sourcesToAttempt = task.Where(x => !_badUpdateSources.Contains(x.Item1)).OrderBy(x => GetPing(x.Item1)).ToList();

            if (sourcesToAttempt.Count == 0)
            {
                Console.WriteLine("There are no working sources to download from. Check the log for reasons why the sources failed.");

                _failedItems.Add(task);
                return(false);
            }

            Exception ex = null;

            foreach (var source in sourcesToAttempt)
            {
                try
                {
                    // Needed because ZipUpdater doesn't support progress
                    if (source.Item2.RemoteFile is ZipUpdater.ArchiveItem)
                    {
                        labelPercent.Text = $"Extracting... Overall progress: {_completedSize} / {_overallSize}.";
                    }

                    await RetryHelper.RetryOnExceptionAsync(() => source.Item2.Update(progress, _cancelToken.Token), 3,
                                                            TimeSpan.FromSeconds(3), _cancelToken.Token);

                    _completedSize += source.Item2.GetDownloadSize();
                    ex              = null;
                    break;
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Marking source {source.Item1.Source.Origin} as broken because of exception: {e.ToStringDemystified()}");

                    ex = e;
                    _badUpdateSources.Add(source.Item1);
                }
            }
            // Check if all sources failed
            if (ex != null)
            {
                Console.WriteLine("There are no working sources to download from. Check the log for reasons why the sources failed.");

                _failedItems.Add(task);
                _failedExceptions.Add(ex);
                return(false);
            }

            return(true);
        }