-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathUpdateCheckService.cs
More file actions
131 lines (111 loc) · 4.56 KB
/
Copy pathUpdateCheckService.cs
File metadata and controls
131 lines (111 loc) · 4.56 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
119
120
121
122
123
124
125
126
127
128
129
130
131
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace DropResize
{
public class UpdateCheckService
{
private const string LatestReleaseApiUrl = "https://api.github.com/repos/Weegley/Drop-Resize/releases/latest";
private const string UpdateApiUrlOverrideVariable = "DROPRESIZE_UPDATE_API_URL";
private static readonly HttpClient Client = CreateClient();
public async Task<UpdateInfo> CheckForUpdateAsync(CancellationToken cancellationToken)
{
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
using (var request = new HttpRequestMessage(HttpMethod.Get, GetLatestReleaseApiUrl()))
{
request.Headers.TryAddWithoutValidation("User-Agent", "DropResize");
request.Headers.TryAddWithoutValidation("Accept", "application/vnd.github+json");
using (var response = await Client.SendAsync(request, cancellationToken).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var latest = ParseLatestRelease(json);
var current = GetCurrentVersion();
if (latest.Version <= current)
{
return null;
}
return latest;
}
}
}
private static HttpClient CreateClient()
{
return new HttpClient
{
Timeout = TimeSpan.FromSeconds(15)
};
}
private static string GetLatestReleaseApiUrl()
{
var overrideUrl = Environment.GetEnvironmentVariable(UpdateApiUrlOverrideVariable);
return string.IsNullOrWhiteSpace(overrideUrl) ? LatestReleaseApiUrl : overrideUrl;
}
private static Version GetCurrentVersion()
{
var location = Assembly.GetExecutingAssembly().Location;
var fileVersion = FileVersionInfo.GetVersionInfo(location).FileVersion;
Version version;
return Version.TryParse(fileVersion, out version)
? version
: Assembly.GetExecutingAssembly().GetName().Version;
}
private static UpdateInfo ParseLatestRelease(string json)
{
var tagName = ReadJsonString(json, "tag_name");
var releaseUrl = ReadJsonString(json, "html_url");
var downloadUrl = ReadDownloadUrl(json);
if (string.IsNullOrWhiteSpace(tagName))
{
throw new InvalidOperationException("GitHub release response does not contain tag_name.");
}
var versionText = tagName.Trim();
if (versionText.StartsWith("v", StringComparison.OrdinalIgnoreCase))
{
versionText = versionText.Substring(1);
}
Version version;
if (!Version.TryParse(versionText, out version))
{
throw new InvalidOperationException("GitHub release version is invalid: " + tagName);
}
return new UpdateInfo
{
Version = version,
VersionText = versionText,
ReleaseUrl = releaseUrl,
DownloadUrl = downloadUrl
};
}
private static string ReadJsonString(string json, string propertyName)
{
var pattern = "\"" + Regex.Escape(propertyName) + "\"\\s*:\\s*\"(?<value>(?:\\\\.|[^\"])*)\"";
var match = Regex.Match(json, pattern);
return match.Success ? Regex.Unescape(match.Groups["value"].Value) : null;
}
private static string ReadDownloadUrl(string json)
{
var pattern = "\"browser_download_url\"\\s*:\\s*\"(?<value>(?:\\\\.|[^\"])*)\"";
var matches = Regex.Matches(json, pattern);
string firstUrl = null;
foreach (Match match in matches)
{
var url = Regex.Unescape(match.Groups["value"].Value);
if (firstUrl == null)
{
firstUrl = url;
}
if (url.EndsWith("DropResize-Windows.zip", StringComparison.OrdinalIgnoreCase))
{
return url;
}
}
return firstUrl;
}
}
}