Skip to content

Commit

Permalink
Disentangle AboutPage from checking for updates (prepare for the late…
Browse files Browse the repository at this point in the history
…r possibility of introducing AutoUpdate for MSI installs)
  • Loading branch information
christophwille committed Jun 17, 2023
1 parent 4514e33 commit b9c9e05
Show file tree
Hide file tree
Showing 6 changed files with 277 additions and 163 deletions.
166 changes: 6 additions & 160 deletions ILSpy/AboutPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,20 @@
// DEALINGS IN THE SOFTWARE.

using System;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Xml.Linq;

using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.Themes;
using ICSharpCode.ILSpy.Updates;
using ICSharpCode.ILSpyX.Settings;

namespace ICSharpCode.ILSpy
Expand All @@ -50,11 +46,6 @@ public override void Execute(object parameter)
);
}

static readonly Uri UpdateUrl = new Uri("https://ilspy.net/updates.xml");
const string band = "stable";

static AvailableVersionInfo latestAvailableVersion;

public static void Display(DecompilerTextView textView)
{
AvalonEditTextOutput output = new AvalonEditTextOutput() {
Expand All @@ -71,14 +62,14 @@ public static void Display(DecompilerTextView textView)
StackPanel stackPanel = new StackPanel();
stackPanel.HorizontalAlignment = HorizontalAlignment.Center;
stackPanel.Orientation = Orientation.Horizontal;
if (latestAvailableVersion == null)
if (NotifyOfUpdatesStrategy.LatestAvailableVersion == null)
{
AddUpdateCheckButton(stackPanel, textView);
}
else
{
// we already retrieved the latest version sometime earlier
ShowAvailableVersion(latestAvailableVersion, stackPanel);
ShowAvailableVersion(NotifyOfUpdatesStrategy.LatestAvailableVersion, stackPanel);
}
CheckBox checkBox = new CheckBox();
checkBox.Margin = new Thickness(4);
Expand Down Expand Up @@ -142,7 +133,7 @@ static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textV

try
{
AvailableVersionInfo vInfo = await GetLatestVersionAsync();
AvailableVersionInfo vInfo = await NotifyOfUpdatesStrategy.GetLatestVersionAsync();
stackPanel.Children.Clear();
ShowAvailableVersion(vInfo, stackPanel);
}
Expand All @@ -155,11 +146,9 @@ static void AddUpdateCheckButton(StackPanel stackPanel, DecompilerTextView textV
};
}

static readonly Version currentVersion = new Version(DecompilerVersionInfo.Major + "." + DecompilerVersionInfo.Minor + "." + DecompilerVersionInfo.Build + "." + DecompilerVersionInfo.Revision);

static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPanel stackPanel)
{
if (currentVersion == availableVersion.Version)
if (AppUpdateService.CurrentVersion == availableVersion.Version)
{
stackPanel.Children.Add(
new Image {
Expand All @@ -173,7 +162,7 @@ static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPan
VerticalAlignment = VerticalAlignment.Bottom
});
}
else if (currentVersion < availableVersion.Version)
else if (AppUpdateService.CurrentVersion < availableVersion.Version)
{
stackPanel.Children.Add(
new TextBlock {
Expand All @@ -197,149 +186,6 @@ static void ShowAvailableVersion(AvailableVersionInfo availableVersion, StackPan
stackPanel.Children.Add(new TextBlock { Text = Resources.UsingNightlyBuildNewerThanLatestRelease });
}
}

static async Task<AvailableVersionInfo> GetLatestVersionAsync()
{
var client = new HttpClient(new HttpClientHandler() {
UseProxy = true,
UseDefaultCredentials = true,
});
string data = await client.GetStringAsync(UpdateUrl);

XDocument doc = XDocument.Load(new StringReader(data));
var bands = doc.Root.Elements("band");
var currentBand = bands.FirstOrDefault(b => (string)b.Attribute("id") == band) ?? bands.First();
Version version = new Version((string)currentBand.Element("latestVersion"));
string url = (string)currentBand.Element("downloadUrl");
if (!(url.StartsWith("http://", StringComparison.Ordinal) || url.StartsWith("https://", StringComparison.Ordinal)))
url = null; // don't accept non-urls

latestAvailableVersion = new AvailableVersionInfo { Version = version, DownloadUrl = url };
return latestAvailableVersion;
}

sealed class AvailableVersionInfo
{
public Version Version;
public string DownloadUrl;
}

sealed class UpdateSettings : INotifyPropertyChanged
{
public UpdateSettings(ILSpySettings spySettings)
{
XElement s = spySettings["UpdateSettings"];
this.automaticUpdateCheckEnabled = (bool?)s.Element("AutomaticUpdateCheckEnabled") ?? true;
try
{
this.lastSuccessfulUpdateCheck = (DateTime?)s.Element("LastSuccessfulUpdateCheck");
}
catch (FormatException)
{
// avoid crashing on settings files invalid due to
// https://github.com/icsharpcode/ILSpy/issues/closed/#issue/2
}
}

bool automaticUpdateCheckEnabled;

public bool AutomaticUpdateCheckEnabled {
get { return automaticUpdateCheckEnabled; }
set {
if (automaticUpdateCheckEnabled != value)
{
automaticUpdateCheckEnabled = value;
Save();
OnPropertyChanged(nameof(AutomaticUpdateCheckEnabled));
}
}
}

DateTime? lastSuccessfulUpdateCheck;

public DateTime? LastSuccessfulUpdateCheck {
get { return lastSuccessfulUpdateCheck; }
set {
if (lastSuccessfulUpdateCheck != value)
{
lastSuccessfulUpdateCheck = value;
Save();
OnPropertyChanged(nameof(LastSuccessfulUpdateCheck));
}
}
}

public void Save()
{
XElement updateSettings = new XElement("UpdateSettings");
updateSettings.Add(new XElement("AutomaticUpdateCheckEnabled", automaticUpdateCheckEnabled));
if (lastSuccessfulUpdateCheck != null)
updateSettings.Add(new XElement("LastSuccessfulUpdateCheck", lastSuccessfulUpdateCheck));
ILSpySettings.SaveSettings(updateSettings);
}

public event PropertyChangedEventHandler PropertyChanged;

void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

/// <summary>
/// If automatic update checking is enabled, checks if there are any updates available.
/// Returns the download URL if an update is available.
/// Returns null if no update is available, or if no check was performed.
/// </summary>
public static async Task<string> CheckForUpdatesIfEnabledAsync(ILSpySettings spySettings)
{
UpdateSettings s = new UpdateSettings(spySettings);

// If we're in an MSIX package, updates work differently
if (s.AutomaticUpdateCheckEnabled)
{
// perform update check if we never did one before;
// or if the last check wasn't in the past 7 days
if (s.LastSuccessfulUpdateCheck == null
|| s.LastSuccessfulUpdateCheck < DateTime.UtcNow.AddDays(-7)
|| s.LastSuccessfulUpdateCheck > DateTime.UtcNow)
{
return await CheckForUpdateInternal(s);
}
else
{
return null;
}
}
else
{
return null;
}
}

public static Task<string> CheckForUpdatesAsync(ILSpySettings spySettings)
{
UpdateSettings s = new UpdateSettings(spySettings);
return CheckForUpdateInternal(s);
}

static async Task<string> CheckForUpdateInternal(UpdateSettings s)
{
try
{
var v = await GetLatestVersionAsync();
s.LastSuccessfulUpdateCheck = DateTime.UtcNow;
if (v.Version > currentVersion)
return v.DownloadUrl;
else
return null;
}
catch (Exception)
{
// ignore errors getting the version info
return null;
}
}
}

/// <summary>
Expand Down
8 changes: 5 additions & 3 deletions ILSpy/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.ILSpy.Themes;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.Updates;
using ICSharpCode.ILSpy.ViewModels;
using ICSharpCode.ILSpyX;
using ICSharpCode.ILSpyX.Settings;
Expand Down Expand Up @@ -954,13 +955,14 @@ public async Task ShowMessageIfUpdatesAvailableAsync(ILSpySettings spySettings,
string downloadUrl;
if (forceCheck)
{
downloadUrl = await AboutPage.CheckForUpdatesAsync(spySettings);
downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(spySettings);
}
else
{
downloadUrl = await AboutPage.CheckForUpdatesIfEnabledAsync(spySettings);
downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesIfEnabledAsync(spySettings);
}

// The Update Panel is only available for NotifyOfUpdatesStrategy, AutoUpdate will have differing UI requirements
AdjustUpdateUIAfterCheck(downloadUrl, forceCheck);
}

Expand All @@ -978,7 +980,7 @@ async void downloadOrCheckUpdateButtonClick(object sender, RoutedEventArgs e)
else
{
updatePanel.Visibility = Visibility.Collapsed;
string downloadUrl = await AboutPage.CheckForUpdatesAsync(ILSpySettings.Load());
string downloadUrl = await NotifyOfUpdatesStrategy.CheckForUpdatesAsync(ILSpySettings.Load());
AdjustUpdateUIAfterCheck(downloadUrl, true);
}
}
Expand Down
35 changes: 35 additions & 0 deletions ILSpy/Updates/AppUpdateService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;

namespace ICSharpCode.ILSpy.Updates
{
internal enum UpdateStrategy
{
NotifyOfUpdates,
// AutoUpdate
}

internal static class AppUpdateService
{
public static readonly UpdateStrategy updateStrategy = UpdateStrategy.NotifyOfUpdates;

public static readonly Version CurrentVersion = new Version(DecompilerVersionInfo.Major + "." + DecompilerVersionInfo.Minor + "." + DecompilerVersionInfo.Build + "." + DecompilerVersionInfo.Revision);
}
}
28 changes: 28 additions & 0 deletions ILSpy/Updates/AvailableVersionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;

namespace ICSharpCode.ILSpy.Updates
{
sealed class AvailableVersionInfo
{
public Version Version;
public string DownloadUrl;
}
}
Loading

0 comments on commit b9c9e05

Please sign in to comment.