From 24c90a8fdebe90dac25ac94ee5d77d495cc9e3f1 Mon Sep 17 00:00:00 2001 From: GreemDev Date: Sun, 16 Mar 2025 00:54:20 -0500 Subject: [PATCH] Prevent being cut off from updates for the future. The release channels are now provided via an API endpoint from ryujinx.app. --- src/Ryujinx.Common/ReleaseInformation.cs | 60 ++++++++++++++++++++++-- src/Ryujinx/Systems/Updater.cs | 19 ++++++-- 2 files changed, 70 insertions(+), 9 deletions(-) diff --git a/src/Ryujinx.Common/ReleaseInformation.cs b/src/Ryujinx.Common/ReleaseInformation.cs index 68db97465..c6644ffd6 100644 --- a/src/Ryujinx.Common/ReleaseInformation.cs +++ b/src/Ryujinx.Common/ReleaseInformation.cs @@ -1,5 +1,9 @@ +using Ryujinx.Common.Utilities; using System; +using System.Net.Http; using System.Reflection; +using System.Text.Json.Serialization; +using System.Threading.Tasks; namespace Ryujinx.Common { @@ -34,12 +38,60 @@ namespace Ryujinx.Common public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute()?.InformationalVersion; - public static string GetChangelogUrl(Version currentVersion, Version newVersion) => + public static string GetChangelogUrl(Version currentVersion, Version newVersion, ReleaseChannels.Channel releaseChannel) => IsCanaryBuild ? $"https://github.com/{ReleaseChannelOwner}/{ReleaseChannelSourceRepo}/compare/Canary-{currentVersion}...Canary-{newVersion}" - : GetChangelogForVersion(newVersion); + : GetChangelogForVersion(newVersion, releaseChannel); - public static string GetChangelogForVersion(Version version) => - $"https://github.com/{ReleaseChannelOwner}/{ReleaseChannelRepo}/releases/{version}"; + public static string GetChangelogForVersion(Version version, ReleaseChannels.Channel releaseChannel) => + $"https://github.com/{releaseChannel}/releases/{version}"; + + public static async Task GetReleaseChannelsAsync(HttpClient httpClient) + { + ReleaseChannelPair releaseChannelPair = JsonHelper.Deserialize(await httpClient.GetStringAsync("https://ryujinx.app/api/release-channels"), ReleaseChannelPairContext.Default.ReleaseChannelPair); + return ReleaseChannels.Create(releaseChannelPair); + } + } + + public struct ReleaseChannels + { + internal static ReleaseChannels Create(ReleaseChannelPair channelPair) => + new() + { + Stable = new Channel(channelPair.Stable), + Canary = new Channel(channelPair.Canary) + }; + + public Channel Stable { get; init; } + public Channel Canary { get; init; } + + public struct Channel + { + public Channel(string raw) + { + string[] parts = raw.Split('/'); + Owner = parts[0]; + Repo = parts[1]; + } + + public string Owner; + public string Repo; + + public override string ToString() => $"{Owner}/{Repo}"; + + public string GetLatestReleaseApiUrl() => + $"https://api.github.com/repos/{ToString()}/releases/latest"; + } + } + + [JsonSerializable(typeof(ReleaseChannelPair))] + partial class ReleaseChannelPairContext : JsonSerializerContext; + + class ReleaseChannelPair + { + [JsonPropertyName("stable")] + public string Stable { get; set; } + [JsonPropertyName("canary")] + public string Canary { get; set; } } } diff --git a/src/Ryujinx/Systems/Updater.cs b/src/Ryujinx/Systems/Updater.cs index a601123a7..faea18fd2 100644 --- a/src/Ryujinx/Systems/Updater.cs +++ b/src/Ryujinx/Systems/Updater.cs @@ -31,9 +31,9 @@ namespace Ryujinx.Ava.Systems { internal static class Updater { + private static ReleaseChannels.Channel? _currentReleaseChannel; + private const string GitHubApiUrl = "https://api.github.com"; - private const string LatestReleaseUrl = - $"{GitHubApiUrl}/repos/{ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}/releases/latest"; private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); @@ -70,13 +70,22 @@ namespace Ryujinx.Ava.Systems } Logger.Info?.Print(LogClass.Application, "Checking for updates."); - + // Get latest version number from GitHub API try { using HttpClient jsonClient = ConstructHttpClient(); - string fetchedJson = await jsonClient.GetStringAsync(LatestReleaseUrl); + if (_currentReleaseChannel == null) + { + ReleaseChannels releaseChannels = await ReleaseInformation.GetReleaseChannelsAsync(jsonClient); + + _currentReleaseChannel = ReleaseInformation.IsCanaryBuild + ? releaseChannels.Canary + : releaseChannels.Stable; + } + + string fetchedJson = await jsonClient.GetStringAsync(_currentReleaseChannel.Value.GetLatestReleaseApiUrl()); GithubReleasesJsonResponse fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse); _buildVer = fetched.TagName; @@ -122,7 +131,7 @@ namespace Ryujinx.Ava.Systems if (userResult is UserResult.Ok) { - OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion)); + OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion, _currentReleaseChannel.Value)); } }