Skip to content

Important improvements to the updater #2982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions UniGetUI.iss
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!

#define MyAppVersion "3.1.2"
#define MyAppVersion "3.1.4-beta1"
#define MyAppName "UniGetUI (formerly WingetUI)"
#define MyAppPublisher "Martí Climent"
#define MyAppURL "https://github.com/marticliment/UniGetUI"
Expand All @@ -23,7 +23,7 @@ AppPublisher={#MyAppPublisher}
AppPublisherURL="https://www.marticliment.com/unigetui/"
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
VersionInfoVersion=3.1.2.0
VersionInfoVersion=3.1.4.0
DefaultDirName="{autopf64}\UniGetUI"
DisableProgramGroupPage=yes
DisableDirPage=no
Expand Down
1 change: 1 addition & 0 deletions scripts/BuildNumber
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
70
22 changes: 17 additions & 5 deletions scripts/apply_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,26 @@
os.chdir(os.path.join(os.path.dirname(__file__), "..")) # move to root project

try:
floatval = input("Enter version code (X.XXX) : ")
# floatval = input("Enter version code (X.XXX) : ")
# versionCode = float(floatval)
versionName = str(input("Enter version name (string) : "))

if floatval == "":
if versionName == "":
print("Version changer script aborted")
exit()

BuildNumber = -1
c = ""
if os.path.exists("scripts/BuildNumber"):
with open("scripts/BuildNumber", "r") as f:
c = f.read()

BuildNumber = int(c) if c != "" else int(input("Build number file was empty. Insert (integer) build number: "))-1
print(f"Build number set to {BuildNumber+1}")
with open("scripts/BuildNumber", "w") as f:
f.write(str(BuildNumber+1))


versionCode = float(floatval)
versionName = str(input("Enter version name (string) : "))
versionISS = str(input("Enter version (X.X.X.X) : "))

def fileReplaceLinesWith(filename: str, list: dict[str, str], encoding="utf-8"):
Expand All @@ -32,7 +44,7 @@ def fileReplaceLinesWith(filename: str, list: dict[str, str], encoding="utf-8"):

fileReplaceLinesWith("src/UniGetUI.Core.Data/CoreData.cs", {
" public const string VersionName = ": f" \"{versionName}\"; // Do not modify this line, use file scripts/apply_versions.py\n",
" public const double VersionNumber = ": f" {versionCode}; // Do not modify this line, use file scripts/apply_versions.py\n",
" public const int BuildNumber = ": f" {BuildNumber+1}; // Do not modify this line, use file scripts/apply_versions.py\n",
}, encoding="utf-8-sig")

fileReplaceLinesWith("src/SharedAssemblyInfo.cs", {
Expand Down
2 changes: 2 additions & 0 deletions scripts/translation_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ def get_all_strings():
r'<[a-zA-Z0-9]+:ButtonCard' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:ButtonCard' + MAIN_WILDCARD + r'+ButtonText=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" ButtonText=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:CheckboxCard' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:CheckboxButtonCard' + MAIN_WILDCARD + r'+CheckboxText=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:CheckboxButtonCard' + MAIN_WILDCARD + r'+ButtonText=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:ComboboxCard' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:BetterMenuItem' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
r'<[a-zA-Z0-9]+:NavButton' + MAIN_WILDCARD + r'+Text=["\'].+["\']' + MAIN_WILDCARD + r'*\/?>': lambda match: match.split(" Text=\"")[1].split("\"")[0].encode('raw_unicode_escape').decode('unicode_escape'),
Expand Down
6 changes: 3 additions & 3 deletions src/SharedAssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[assembly: AssemblyTitle("UniGetUI")]
[assembly: AssemblyDefaultAlias("UniGetUI")]
[assembly: AssemblyCopyright("2024, Martí Climent")]
[assembly: AssemblyVersion("3.1.2.0")]
[assembly: AssemblyFileVersion("3.1.2.0")]
[assembly: AssemblyInformationalVersion("3.1.2")]
[assembly: AssemblyVersion("3.1.4.0")]
[assembly: AssemblyFileVersion("3.1.4.0")]
[assembly: AssemblyInformationalVersion("3.1.4-beta1")]
[assembly: SupportedOSPlatform("windows10.0.19041")]
5 changes: 1 addition & 4 deletions src/UniGetUI.Core.Data.Tests/CoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,9 @@ public void CheckDirectoryAttributes(string directory)
public void CheckOtherAttributes()
{
Assert.NotEmpty(CoreData.VersionName);
Assert.NotEqual(0, CoreData.VersionNumber);
Assert.NotEqual(0, CoreData.BuildNumber);
Assert.True(File.Exists(CoreData.IgnoredUpdatesDatabaseFile), "The Ignored Updates database file does not exist, but it should have been created automatically.");

int notif_3 = CoreData.UpdatesAvailableNotificationTag;
int notif_4 = CoreData.UpdatesAvailableNotificationTag;
Assert.True(notif_3 == notif_4, "The UpdatesAvailableNotificationId must be always the same");
Assert.NotEqual(0, CoreData.UpdatesAvailableNotificationTag);

Assert.True(Directory.Exists(CoreData.UniGetUIExecutableDirectory), "Directory where the executable is located does not exist");
Expand Down
3 changes: 2 additions & 1 deletion src/UniGetUI.Core.Data/CoreData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private static int GetCodePage()
}

public const string VersionName = "3.1.4-beta1"; // Do not modify this line, use file scripts/apply_versions.py
public const double VersionNumber = 3.14; // Do not modify this line, use file scripts/apply_versions.py
public const int BuildNumber = 70; // Do not modify this line, use file scripts/apply_versions.py

public const string UserAgentString = $"UniGetUI/{VersionName} (https://marticliment.com/unigetui/; [email protected])";

Expand Down Expand Up @@ -169,6 +169,7 @@ public static string IgnoredUpdatesDatabaseFile
/// The ID of the notification that is used to inform the user that updates are available
/// </summary>
public const int UpdatesAvailableNotificationTag = 1234;
public const int UniGetUICanBeUpdated = 1235;


/// <summary>
Expand Down
40 changes: 40 additions & 0 deletions src/UniGetUI.Core.Tools/Tools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using System.Diagnostics;
using System.Globalization;
using System.Net;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using UniGetUI.Core.Classes;
using UniGetUI.Core.Data;
using UniGetUI.Core.Language;
using UniGetUI.Core.Logging;
Expand Down Expand Up @@ -542,5 +544,43 @@ public static ProcessStartInfo UpdateEnvironmentVariables(ProcessStartInfo info)
}
return info;
}


/// <summary>
/// Pings the update server and 3 well-known sites to check for internet availability
/// </summary>
public static async Task WaitForInternetConnection()
=> await (await TaskRecycler<Task>.RunOrAttachAsync(_waitForInternetConnection));

public static async Task _waitForInternetConnection()
{
Logger.Debug("Checking for internet connectivity. Pinging google.com, microsoft.com, couldflare.com and marticliment.com");
string[] hosts = ["google.com", "microsoft.com", "cloudflare.com", "marticliment.com"];
while (true)
{
foreach (var host in hosts)
{
using (var pinger = new Ping())
{
try
{
PingReply reply = await pinger.SendPingAsync(host, 10);
if (reply.Status is IPStatus.Success)
{
Logger.Debug($"{host} responded successfully to ping, internet connection was validated.");
return;
}

Logger.Debug($"Could not ping {host}!");
}
catch (Exception ex)
{
Logger.Debug($"Could not ping {host} with error {ex.Message}. Are you connected to the internet?");
}
}
}
await Task.Delay(TimeSpan.FromSeconds(5));
}
}
}
}
2 changes: 1 addition & 1 deletion src/UniGetUI.Interface.BackgroundApi/BackgroundApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public void BuildV1WidgetsApi()
return 401;
}

return CoreData.VersionNumber.ToString();
return CoreData.BuildNumber.ToString();
});

// Return found updates
Expand Down
1 change: 1 addition & 0 deletions src/UniGetUI.Interface.Enums/Enums.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,6 @@ public class NotificationArguments
public const string Show = "openUniGetUI";
public const string ShowOnUpdatesTab = "openUniGetUIOnUpdatesTab";
public const string UpdateAllPackages = "updateAll";
public const string ReleaseSelfUpdateLock = "releaseSelfUpdateLock";
}
}
147 changes: 0 additions & 147 deletions src/UniGetUI/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,6 @@ private async Task LoadComponentsAsync()
{
try
{
// Run other initializations asynchronously
if (!Settings.Get("DisableAutoUpdateWingetUI"))
{
UpdateUniGetUIIfPossible();
}

IconDatabase.InitializeInstance();
IconDatabase.Instance.LoadIconAndScreenshotsDatabase();

Expand Down Expand Up @@ -404,147 +398,6 @@ public async void DisposeAndQuit(int outputCode = 0)
Environment.Exit(outputCode);
}

private async void UpdateUniGetUIIfPossible(int round = 0)
{
InfoBar? banner = null;
try
{
Logger.Debug("Starting update check");

string fileContents;

using (HttpClient client = new(CoreData.GenericHttpClientParameters))
{
client.Timeout = TimeSpan.FromSeconds(600);
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString);
fileContents = await client.GetStringAsync("https://www.marticliment.com/versions/unigetui.ver");
}

if (!fileContents.Contains("///"))
{
throw new FormatException("The updates file does not follow the FloatVersion///Sha256Hash format");
}

float LatestVersion = float.Parse(fileContents.Split("///")[0].Replace("\n", "").Trim(), CultureInfo.InvariantCulture);
string InstallerHash = fileContents.Split("///")[1].Replace("\n", "").Trim().ToLower();

if (LatestVersion > CoreData.VersionNumber)
{
Logger.Info("Updates found, downloading installer...");
Logger.Info("Current version: " + CoreData.VersionNumber.ToString(CultureInfo.InvariantCulture));
Logger.Info("Latest version : " + LatestVersion.ToString(CultureInfo.InvariantCulture));

banner = MainWindow.UpdatesBanner;
banner.Title = CoreTools.Translate("WingetUI version {0} is being downloaded.", LatestVersion.ToString(CultureInfo.InvariantCulture));
banner.Message = CoreTools.Translate("This may take a minute or two");
banner.Severity = InfoBarSeverity.Informational;
banner.IsOpen = true;
banner.IsClosable = false;

Uri DownloadUrl = new("https://github.com/marticliment/WingetUI/releases/latest/download/UniGetUI.Installer.exe");
string InstallerPath = Path.Join(Directory.CreateTempSubdirectory().FullName, "unigetui-updater.exe");

using (HttpClient client = new(CoreData.GenericHttpClientParameters))
{
client.DefaultRequestHeaders.UserAgent.ParseAdd(CoreData.UserAgentString);
HttpResponseMessage result = await client.GetAsync(DownloadUrl);
using FileStream fs = new(InstallerPath, FileMode.CreateNew);
await result.Content.CopyToAsync(fs);
}

string Hash = "";
SHA256 Sha256 = SHA256.Create();
using (FileStream stream = File.OpenRead(InstallerPath))
{
Hash = Convert.ToHexString(Sha256.ComputeHash(stream)).ToLower();
}

if (Hash == InstallerHash)
{

banner.Title = CoreTools.Translate("WingetUI {0} is ready to be installed.", LatestVersion.ToString(CultureInfo.InvariantCulture));
banner.Message = CoreTools.Translate("The update will be installed upon closing WingetUI");
banner.ActionButton = new Button
{
Content = CoreTools.Translate("Update now")
};
banner.ActionButton.Click += (_, _) => { MainWindow.HideWindow(); };
banner.Severity = InfoBarSeverity.Success;
banner.IsOpen = true;
banner.IsClosable = true;

if (MainWindow.Visible)
{
Logger.Debug("Waiting for mainWindow to be hidden");
}

while (MainWindow.Visible)
{
await Task.Delay(100);
}

if (Settings.Get("DisableAutoUpdateWingetUI"))
{
Logger.Warn("User disabled updates!");
return;
}

Logger.ImportantInfo("The hash matches the expected value, starting update process...");
Process p = new();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = $"/c start /B \"\" \"{InstallerPath}\" /silent";
p.StartInfo.UseShellExecute = true;
p.StartInfo.CreateNoWindow = true;
p.Start();
DisposeAndQuit();
}
else
{
Logger.Error("Hash mismatch, not updating!");
Logger.Error("Current hash : " + Hash);
Logger.Error("Expected hash: " + InstallerHash);
File.Delete(InstallerPath);

banner.Title = CoreTools.Translate("The installer hash does not match the expected value.");
banner.Message = CoreTools.Translate("The update will not continue.");
banner.Severity = InfoBarSeverity.Error;
banner.IsOpen = true;
banner.IsClosable = true;

await Task.Delay(3600000); // Check again in 1 hour
UpdateUniGetUIIfPossible();
}
}
else
{
Logger.Info("UniGetUI is up to date");
await Task.Delay(3600000); // Check again in 1 hour
UpdateUniGetUIIfPossible();
}
}
catch (Exception e)
{
if (banner is not null)
{
banner.Title = CoreTools.Translate("An error occurred when checking for updates: ");
banner.Message = e.Message;
banner.Severity = InfoBarSeverity.Error;
banner.IsOpen = true;
banner.IsClosable = true;
}

Logger.Error(e);

if (round >= 3)
{
return;
}

await Task.Delay(600000); // Try again in 10 minutes
UpdateUniGetUIIfPossible(round + 1);
}
}

public void KillAndRestart()
{
Process.Start(CoreData.UniGetUIExecutableFile);
Expand Down
Loading
Loading