-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathPerfectCommsUpdateClient.cs
More file actions
118 lines (101 loc) · 4.83 KB
/
Copy pathPerfectCommsUpdateClient.cs
File metadata and controls
118 lines (101 loc) · 4.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using System;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace VoiceChatPlugin;
internal sealed class PerfectCommsUpdateInfo
{
[JsonPropertyName("enabled")] public bool Enabled { get; set; } = true;
[JsonPropertyName("latestVersion")] public string LatestVersion { get; set; } = "";
[JsonPropertyName("title")] public string Title { get; set; } = "Perfect Comms update available";
[JsonPropertyName("message")] public string Message { get; set; } = "";
[JsonPropertyName("releaseUrl")] public string ReleaseUrl { get; set; } = "";
[JsonPropertyName("showEveryMainMenu")] public bool ShowEveryMainMenu { get; set; }
}
internal sealed class GitHubReleaseInfo
{
[JsonPropertyName("tag_name")] public string TagName { get; set; } = "";
[JsonPropertyName("html_url")] public string HtmlUrl { get; set; } = "";
}
internal static class PerfectCommsUpdateClient
{
private const string GitHubLatestReleaseUrl = "https://api.github.com/repos/artriy/Perfect-Comms/releases/latest";
private const string LegacyCloudflareUpdateUrl = "https://perfect-comms-lobbies.edgetel.workers.dev/updates/latest";
private const string GitHubReleasesUrl = "https://github.com/artriy/Perfect-Comms/releases/latest";
private static readonly HttpClient Client = new()
{
Timeout = TimeSpan.FromSeconds(5)
};
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true
};
internal static async Task<PerfectCommsUpdateInfo?> GetLatestAsync(string configuredUrl)
{
var url = BuildUrl(configuredUrl);
using var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.TryAddWithoutValidation("Accept", "application/vnd.github+json");
request.Headers.TryAddWithoutValidation("User-Agent", $"PerfectComms/{VoiceChatPluginMain.Version}");
using var response = await Client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var text = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return ParseUpdateInfo(text);
}
internal static bool IsNewerThanCurrent(string latestVersion)
=> CompareVersions(latestVersion, VoiceChatPluginMain.Version) > 0;
private static string BuildUrl(string configuredUrl)
{
var url = string.IsNullOrWhiteSpace(configuredUrl) ? GitHubLatestReleaseUrl : configuredUrl.Trim();
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri) || uri.Scheme != Uri.UriSchemeHttps)
return GitHubLatestReleaseUrl;
if (url.StartsWith(LegacyCloudflareUpdateUrl, StringComparison.OrdinalIgnoreCase))
return GitHubLatestReleaseUrl;
if (string.Equals(uri.Host, "api.github.com", StringComparison.OrdinalIgnoreCase))
return url;
var separator = url.Contains('?') ? '&' : '?';
return url + separator + "current=" + Uri.EscapeDataString(VoiceChatPluginMain.Version);
}
private static PerfectCommsUpdateInfo? ParseUpdateInfo(string text)
{
var github = JsonSerializer.Deserialize<GitHubReleaseInfo>(text, JsonOptions);
if (!string.IsNullOrWhiteSpace(github?.TagName))
{
return new PerfectCommsUpdateInfo
{
Enabled = true,
LatestVersion = github.TagName,
Title = "Perfect Comms update available",
Message = "Click here to download the latest Perfect Comms release.",
ReleaseUrl = string.IsNullOrWhiteSpace(github.HtmlUrl) ? GitHubReleasesUrl : github.HtmlUrl,
ShowEveryMainMenu = false,
};
}
return JsonSerializer.Deserialize<PerfectCommsUpdateInfo>(text, JsonOptions);
}
private static int CompareVersions(string left, string right)
{
var leftParts = SplitVersion(left);
var rightParts = SplitVersion(right);
var count = Math.Max(leftParts.Length, rightParts.Length);
for (var i = 0; i < count; i++)
{
var a = i < leftParts.Length ? leftParts[i] : 0;
var b = i < rightParts.Length ? rightParts[i] : 0;
if (a != b) return a.CompareTo(b);
}
return 0;
}
private static int[] SplitVersion(string value)
{
value = (value ?? "").Trim();
if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) value = value[1..];
var dash = value.IndexOfAny(new[] { '-', '+' });
if (dash >= 0) value = value[..dash];
var parts = value.Split('.', StringSplitOptions.RemoveEmptyEntries);
var numbers = new int[Math.Min(parts.Length, 4)];
for (var i = 0; i < numbers.Length; i++)
numbers[i] = int.TryParse(parts[i], out var parsed) ? parsed : 0;
return numbers;
}
}