Skip to content

Commit f2ca34f

Browse files
committed
Improve UpdateHelper
1 parent 9997b93 commit f2ca34f

File tree

6 files changed

+437
-229
lines changed

6 files changed

+437
-229
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using System;
2+
3+
namespace HandyControl.Tools;
4+
5+
public readonly struct SystemVersionInfo
6+
{
7+
public SystemVersionInfo(int major, int minor, int build, int revision = 0)
8+
{
9+
Major = major;
10+
Minor = minor;
11+
Build = build;
12+
Revision = revision;
13+
}
14+
15+
public int Major { get; }
16+
17+
public int Minor { get; }
18+
19+
public int Build { get; }
20+
21+
public int Revision { get; }
22+
23+
public bool Equals(SystemVersionInfo other)
24+
{
25+
return Major == other.Major && Minor == other.Minor && Build == other.Build && Revision == other.Revision;
26+
}
27+
28+
public override bool Equals(object obj)
29+
{
30+
return obj is SystemVersionInfo other && Equals(other);
31+
}
32+
33+
public override int GetHashCode()
34+
{
35+
return Major.GetHashCode() ^ Minor.GetHashCode() ^ Build.GetHashCode() ^ Revision.GetHashCode();
36+
}
37+
38+
public static bool operator ==(SystemVersionInfo left, SystemVersionInfo right)
39+
{
40+
return left.Equals(right);
41+
}
42+
43+
public static bool operator !=(SystemVersionInfo left, SystemVersionInfo right)
44+
{
45+
return !(left == right);
46+
}
47+
48+
public int CompareTo(SystemVersionInfo other)
49+
{
50+
return Major != other.Major
51+
? Major.CompareTo(other.Major)
52+
: Minor != other.Minor
53+
? Minor.CompareTo(other.Minor)
54+
: Build != other.Build ? Build.CompareTo(other.Build) : Revision != other.Revision ? Revision.CompareTo(other.Revision) : 0;
55+
}
56+
57+
public int CompareTo(object obj)
58+
{
59+
return obj is not SystemVersionInfo other ? throw new ArgumentException() : CompareTo(other);
60+
}
61+
62+
public static bool operator <(SystemVersionInfo left, SystemVersionInfo right)
63+
{
64+
return left.CompareTo(right) < 0;
65+
}
66+
67+
public static bool operator <=(SystemVersionInfo left, SystemVersionInfo right)
68+
{
69+
return left.CompareTo(right) <= 0;
70+
}
71+
72+
public static bool operator >(SystemVersionInfo left, SystemVersionInfo right)
73+
{
74+
return left.CompareTo(right) > 0;
75+
}
76+
77+
public static bool operator >=(SystemVersionInfo left, SystemVersionInfo right)
78+
{
79+
return left.CompareTo(right) >= 0;
80+
}
81+
82+
public override string ToString()
83+
{
84+
return $"{Major}.{Minor}.{Build}.{Revision}";
85+
}
86+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#if !NET40
2+
using System;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net;
6+
using System.Net.Http;
7+
using System.Reflection;
8+
using System.Text;
9+
using System.Threading.Tasks;
10+
#if NETCOREAPP
11+
using System.Text.Json;
12+
#else
13+
using System.Web.Script.Serialization;
14+
#endif
15+
using HandyControl.Data;
16+
using HandyControl.Tools.Extension;
17+
using System.Collections.Generic;
18+
19+
namespace HandyControl.Tools;
20+
21+
public static partial class UpdateHelper
22+
{
23+
private const string GITHUB_API_RELEASES = "https://api.github.com/repos/{0}/{1}/releases";
24+
25+
/// <summary>
26+
/// Checks for updates to a specified repository and returns information about the latest stable and pre-release
27+
/// versions.
28+
/// </summary>
29+
/// <param name="username">Identifies the user or organization that owns the repository.</param>
30+
/// <param name="repository">Specifies the name of the repository to check for updates.</param>
31+
/// <param name="currentVersion">Represents the current version of the software to compare against available releases.</param>
32+
/// <returns>Returns a tuple containing information about the latest stable and pre-release updates.</returns>
33+
/// <exception cref="ArgumentNullException">Thrown when the username or repository is null or empty.</exception>
34+
public static async Task<(UpdateInfo StableRelease, UpdateInfo PreRelease)> CheckUpdateAsync(string username, string repository, Version currentVersion = null)
35+
{
36+
if (string.IsNullOrEmpty(username))
37+
throw new ArgumentNullException(nameof(username));
38+
39+
if (string.IsNullOrEmpty(repository))
40+
throw new ArgumentNullException(nameof(repository));
41+
42+
var notFoundUpdate = new UpdateInfo { IsExistNewVersion = false };
43+
using var client = new HttpClient();
44+
client.DefaultRequestHeaders.Add("User-Agent", username);
45+
46+
var url = string.Format(GITHUB_API_RELEASES, username, repository);
47+
var response = await client.GetAsync(url);
48+
49+
if (response.StatusCode == HttpStatusCode.NotFound)
50+
{
51+
// No releases found, return null for both stable and pre-release
52+
return (notFoundUpdate, notFoundUpdate);
53+
}
54+
55+
response.EnsureSuccessStatusCode();
56+
57+
var responseBody = await response.Content.ReadAsStringAsync();
58+
#if NETCOREAPP
59+
var releases = JsonSerializer.Deserialize<List<UpdateInfo>>(responseBody, UpdateHelperJsonContext.Default.ListUpdateInfo);
60+
#else
61+
JavaScriptSerializer javaScript = new JavaScriptSerializer();
62+
javaScript.RegisterConverters(new JavaScriptConverter[] { new DataContractJavaScriptConverter(true) });
63+
64+
var result = javaScript.Deserialize<List<UpdateInfo>>(reader.ReadToEnd());
65+
#endif
66+
if (releases == null || releases?.Count == 0)
67+
{
68+
return (notFoundUpdate, notFoundUpdate);
69+
}
70+
71+
if (currentVersion == null)
72+
{
73+
currentVersion = ProcessInfoHelper.GetVersion();
74+
}
75+
76+
// Find the latest stable release
77+
var latestStable = releases
78+
.Where(r => !r.IsPreRelease)
79+
.OrderByDescending(r => r.PublishedAt)
80+
.FirstOrDefault();
81+
82+
if (latestStable != null)
83+
{
84+
var newStableVersionInfo = GetAsVersionInfo(latestStable.TagName);
85+
var stableMajor = currentVersion.Major == -1 ? 0 : currentVersion.Major;
86+
var stableMinor = currentVersion.Minor == -1 ? 0 : currentVersion.Minor;
87+
var stableBuild = currentVersion.Build == -1 ? 0 : currentVersion.Build;
88+
var stableRevision = currentVersion.Revision == -1 ? 0 : currentVersion.Revision;
89+
var currentStableVersionInfo = new SystemVersionInfo(stableMajor, stableMinor, stableBuild, stableRevision);
90+
91+
latestStable.IsExistNewVersion = newStableVersionInfo > currentStableVersionInfo;
92+
}
93+
else
94+
{
95+
latestStable = new UpdateInfo { IsExistNewVersion = false };
96+
}
97+
98+
// Find the latest pre-release
99+
var latestPreRelease = releases
100+
.Where(r => r.IsPreRelease)
101+
.OrderByDescending(r => r.PublishedAt)
102+
.FirstOrDefault();
103+
104+
if (latestPreRelease != null)
105+
{
106+
var newPreReleaseVersionInfo = GetAsVersionInfo(latestPreRelease.TagName);
107+
var preReleaseMajor = currentVersion.Major == -1 ? 0 : currentVersion.Major;
108+
var preReleaseMinor = currentVersion.Minor == -1 ? 0 : currentVersion.Minor;
109+
var preReleaseBuild = currentVersion.Build == -1 ? 0 : currentVersion.Build;
110+
var preReleaseRevision = currentVersion.Revision == -1 ? 0 : currentVersion.Revision;
111+
var currentPreReleaseVersionInfo = new SystemVersionInfo(preReleaseMajor, preReleaseMinor, preReleaseBuild, preReleaseRevision);
112+
113+
latestPreRelease.IsExistNewVersion = newPreReleaseVersionInfo > currentPreReleaseVersionInfo;
114+
}
115+
else
116+
{
117+
latestPreRelease = new UpdateInfo { IsExistNewVersion = false };
118+
}
119+
120+
return (latestStable, latestPreRelease);
121+
}
122+
123+
private static SystemVersionInfo GetAsVersionInfo(string version)
124+
{
125+
var nums = GetVersionNumbers(version).Split('.').Select(int.Parse).ToList();
126+
127+
return nums.Count <= 1
128+
? new SystemVersionInfo(nums[0], 0, 0, 0)
129+
: nums.Count <= 2
130+
? new SystemVersionInfo(nums[0], nums[1], 0, 0)
131+
: nums.Count <= 3
132+
? new SystemVersionInfo(nums[0], nums[1], nums[2], 0)
133+
: new SystemVersionInfo(nums[0], nums[1], nums[2], nums[3]);
134+
}
135+
136+
private static string GetVersionNumbers(string version)
137+
{
138+
var allowedChars = "01234567890.";
139+
return new string(version.Where(c => allowedChars.Contains(c)).ToArray());
140+
}
141+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System.Collections.Generic;
2+
using System.Text.Json.Serialization;
3+
4+
namespace HandyControl.Tools;
5+
6+
[JsonSourceGenerationOptions()]
7+
[JsonSerializable(typeof(List<UpdateInfo>))]
8+
internal partial class UpdateHelperJsonContext : JsonSerializerContext
9+
{
10+
}

0 commit comments

Comments
 (0)