infra: Use Ryujinx.UpdateClient NuGet package for checking for updates.

Main benefit to this is sharing the C# model definitions from what the server returns and Ryujinx uses in-app without differences.
Additionally removed the GitHub API JSON models.
This commit is contained in:
GreemDev 2025-06-19 04:18:02 -05:00
parent 6226eadf55
commit 6773406bb6
8 changed files with 38 additions and 101 deletions

View file

@ -4,42 +4,27 @@ using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Common;
using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging;
using Ryujinx.Systems.Update.Client;
using Ryujinx.Systems.Update.Common;
using Ryujinx.Systems.Updater.Common;
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Runtime.InteropServices;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace Ryujinx.Ava.Systems
{
internal static partial class Updater
{
private static string CreateUpdateQueryUrl()
{
#pragma warning disable CS8524
var os = RunningPlatform.CurrentOS switch
#pragma warning restore CS8524
{
OperatingSystemType.MacOS => "mac",
OperatingSystemType.Linux => "linux",
OperatingSystemType.Windows => "win"
};
private static VersionResponse _versionResponse;
var arch = RunningPlatform.Architecture switch
{
Architecture.Arm64 => "arm",
Architecture.X64 => "amd64",
_ => null
};
if (arch is null)
return null;
var rc = ReleaseInformation.IsCanaryBuild ? "canary" : "stable";
return $"https://update.ryujinx.app/latest/query?os={os}&arch={arch}&rc={rc}";
}
private static UpdateClient CreateUpdateClient()
=> UpdateClient.Builder()
.WithServerEndpoint("https://update.ryujinx.app") // This is the default, and doesn't need to be provided; it's here for transparency.
.WithLogger((format, args, caller) =>
Logger.Info?.Print(
LogClass.Application,
args.Length is 0 ? format : format.Format(args),
caller: caller)
);
public static async Task<Optional<(Version Current, Version Incoming)>> CheckVersionAsync(bool showVersionUpToDate = false)
{
@ -57,39 +42,31 @@ namespace Ryujinx.Ava.Systems
return default;
}
if (CreateUpdateQueryUrl() is not {} updateUrl)
{
Logger.Error?.Print(LogClass.Application, "Could not determine URL for updates.");
_running = false;
return default;
}
Logger.Info?.Print(LogClass.Application, $"Checking for updates from {updateUrl}.");
// Get latest version number from update.ryujinx.app API
using HttpClient jsonClient = ConstructHttpClient();
using UpdateClient updateClient = CreateUpdateClient();
try
{
UpdaterResponse response =
await jsonClient.GetFromJsonAsync(updateUrl, UpdaterResponseJsonContext.Default.UpdaterResponse);
_buildVer = response.Tag;
_buildUrl = response.DownloadUrl;
_changelogUrlFormat = response.ReleaseUrlFormat;
_versionResponse = await updateClient.QueryLatestAsync(ReleaseInformation.IsCanaryBuild
? ReleaseChannel.Canary
: ReleaseChannel.Stable);
}
catch (Exception e)
{
Logger.Error?.Print(LogClass.Application, $"An error occurred when parsing JSON response from API ({e.GetType().AsFullNamePrettyString()}): {e.Message}");
Logger.Error?.Print(LogClass.Application, $"An error occurred when requesting for updates ({e.GetType().AsFullNamePrettyString()}): {e.Message}");
_running = false;
return default;
}
if (_versionResponse == null)
{
// logging is done via the UpdateClient library
_running = false;
return default;
}
// If build URL not found, assume no new update is available.
if (_buildUrl is null or "")
if (_versionResponse.ArtifactUrl is null or "")
{
if (showVersionUpToDate)
{
@ -99,7 +76,7 @@ namespace Ryujinx.Ava.Systems
if (userResult is UserResult.Ok)
{
OpenHelper.OpenUrl(_changelogUrlFormat.Format(currentVersion));
OpenHelper.OpenUrl(_versionResponse.ReleaseUrlFormat.Format(currentVersion));
}
}
@ -111,7 +88,7 @@ namespace Ryujinx.Ava.Systems
}
if (!Version.TryParse(_buildVer, out Version newVersion))
if (!Version.TryParse(_versionResponse.Version, out Version newVersion))
{
Logger.Error?.Print(LogClass.Application,
$"Failed to convert the received {RyujinxApp.FullAppName} version from the update server!");
@ -127,17 +104,5 @@ namespace Ryujinx.Ava.Systems
return (currentVersion, newVersion);
}
[JsonSerializable(typeof(UpdaterResponse))]
partial class UpdaterResponseJsonContext : JsonSerializerContext;
public class UpdaterResponse
{
[JsonPropertyName("tag")] public string Tag { get; set; }
[JsonPropertyName("download_url")] public string DownloadUrl { get; set; }
[JsonPropertyName("web_url")] public string ReleaseUrl { get; set; }
[JsonIgnore] public string ReleaseUrlFormat => ReleaseUrl.Replace(Tag, "{0}");
}
}
}