Skip to content

Commit 38bb89b

Browse files
committed
ModApi.UpdateManager: use HttpClient instead of WebClient
1 parent d08dcec commit 38bb89b

4 files changed

Lines changed: 168 additions & 86 deletions

File tree

ModApi.UpdateManager/DllsUpdater.cs

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
using System.IO.Compression;
66
using System.Linq;
77
using System.Net;
8+
using System.Net.Http;
9+
using System.Net.Http.Headers;
810
using System.Reflection;
911
using System.Security.AccessControl;
1012
using System.Security.Principal;
@@ -30,18 +32,9 @@ public class GithubRelease
3032

3133
private static string GithubRequestGET(string uri)
3234
{
33-
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
34-
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
35-
request.Method = "GET";
36-
request.Accept = "application/vnd.github.v3+json";
37-
request.UserAgent = UpdateManager.HttpUserAgent;
38-
39-
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
40-
using (Stream stream = response.GetResponseStream())
41-
using (StreamReader reader = new StreamReader(stream))
42-
{
43-
return reader.ReadToEnd();
44-
}
35+
var downloadClient = new DownloadClient(uri);
36+
downloadClient.AddHeader("Accept", "application/vnd.github.v3+json");
37+
return downloadClient.DownloadString();
4538
}
4639

4740
private static GithubRelease GetLatestGithubRelease(string repoUser, string repoName)
@@ -90,11 +83,6 @@ public static bool HasDllsUpdate(out GithubRelease release)
9083

9184
static readonly string[] DLL_NAMES = { "SporeModAPI.combined.dll", "SporeModAPI.disk.dll", "SporeModAPI.march2017.dll", "SporeModAPI.lib" };
9285

93-
public class UpdateProgressEventArgs : EventArgs
94-
{
95-
public float Progress { get; set; }
96-
}
97-
9886
/// <summary>
9987
/// How much of the progress is spent on download (the rest on copying the files)
10088
/// </summary>
@@ -114,17 +102,16 @@ public static void UpdateDlls(GithubRelease release, Action<int> progressHandler
114102
{
115103
throw new InvalidOperationException("Invalid update: no 'SporeModAPIdlls.zip' asset");
116104
}
117-
using (var client = new WebClient())
105+
using (var downloadClient = new DownloadClient(asset.browser_download_url))
118106
{
119-
client.Headers.Add("User-Agent", UpdateManager.HttpUserAgent);
120-
client.DownloadProgressChanged += (s, e) =>
107+
downloadClient.DownloadProgressChanged += (s, progress) =>
121108
{
122109
if (progressHandler != null)
123-
progressHandler((int)(e.ProgressPercentage * DOWNLOAD_PROGRESS));
110+
progressHandler((int)(progress * DOWNLOAD_PROGRESS));
124111
};
125112

126113
string zipName = Path.GetTempFileName();
127-
client.DownloadFile(asset.browser_download_url, zipName);
114+
downloadClient.DownloadFile(zipName);
128115

129116
using (var zip = ZipFile.Open(zipName, ZipArchiveMode.Read))
130117
{
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Net.Http;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using System.Windows.Forms;
9+
10+
namespace ModApi.UpdateManager
11+
{
12+
public class DownloadClient : IDisposable
13+
{
14+
private HttpClient httpClient = new HttpClient();
15+
private HttpRequestMessage httpRequestMessage = new HttpRequestMessage();
16+
private static string httpUserAgent = "Spore-ModAPI-Launcher-Kit/" + UpdateManager.CurrentVersion.ToString();
17+
18+
19+
public delegate void DownloadClientEventHandler(object source, int percentage);
20+
public event DownloadClientEventHandler DownloadProgressChanged;
21+
22+
public DownloadClient(string url)
23+
{
24+
httpClient.Timeout = TimeSpan.FromMinutes(5);
25+
httpRequestMessage.RequestUri = new Uri(url);
26+
httpRequestMessage.Headers.Add("User-Agent", httpUserAgent);
27+
}
28+
29+
public void SetTimeout(TimeSpan timeout)
30+
{
31+
httpClient.Timeout = timeout;
32+
}
33+
34+
public void AddHeader(string key, string value)
35+
{
36+
httpRequestMessage.Headers.Add(key, value);
37+
}
38+
39+
public string DownloadString()
40+
{
41+
var response = httpClient.SendAsync(httpRequestMessage).Result;
42+
43+
if (!response.IsSuccessStatusCode)
44+
{
45+
throw new HttpRequestException($"Received unsuccessful status code: {(int)response.StatusCode} {response.StatusCode}");
46+
}
47+
48+
return response.Content.ReadAsStringAsync().Result;
49+
}
50+
51+
public void DownloadFile(string file)
52+
{
53+
var response = httpClient.SendAsync(httpRequestMessage).Result;
54+
55+
if (!response.IsSuccessStatusCode)
56+
{
57+
throw new HttpRequestException($"Received unsuccessful status code: {(int)response.StatusCode} {response.StatusCode}");
58+
}
59+
60+
using (var downloadStream = response.Content.ReadAsStreamAsync().Result)
61+
using (var fileStream = new FileStream(file, FileMode.Create))
62+
{
63+
long streamLength = downloadStream.Length;
64+
long totalBytesRead = 0;
65+
byte[] buffer = new byte[1024];
66+
int bufferLength = 0;
67+
int percentageDownloaded = 0;
68+
int percentage = 0;
69+
70+
while ((bufferLength = downloadStream.Read(buffer, 0, buffer.Length)) > 0)
71+
{
72+
fileStream.Write(buffer, 0, bufferLength);
73+
74+
// only trigger event when percentage has changed
75+
percentage = (int)(totalBytesRead / streamLength * 100);
76+
if (percentageDownloaded != percentage)
77+
{
78+
percentageDownloaded = percentage;
79+
DownloadProgressChanged?.Invoke(this, percentage);
80+
}
81+
82+
totalBytesRead += bufferLength;
83+
}
84+
}
85+
}
86+
87+
public void Dispose()
88+
{
89+
Dispose(true);
90+
GC.SuppressFinalize(this);
91+
}
92+
93+
protected virtual void Dispose(bool disposing)
94+
{
95+
if (disposing)
96+
{
97+
httpClient.Dispose();
98+
httpRequestMessage.Dispose();
99+
100+
httpClient = null;
101+
httpRequestMessage = null;
102+
}
103+
}
104+
}
105+
}

ModApi.UpdateManager/ModApi.UpdateManager.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<Reference Include="System.Drawing" />
5050
<Reference Include="System.IO.Compression" />
5151
<Reference Include="System.IO.Compression.FileSystem" />
52+
<Reference Include="System.Net.Http" />
5253
<Reference Include="System.Windows.Forms" />
5354
<Reference Include="System.Xml.Linq" />
5455
<Reference Include="System.Data.DataSetExtensions" />
@@ -58,6 +59,7 @@
5859
</ItemGroup>
5960
<ItemGroup>
6061
<Compile Include="DllsUpdater.cs" />
62+
<Compile Include="DownloadClient.cs" />
6163
<Compile Include="ProgressDialog.cs">
6264
<SubType>Form</SubType>
6365
</Compile>

ModApi.UpdateManager/UpdateManager.cs

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -134,73 +134,79 @@ public static void CheckForUpdates()
134134
}
135135
}
136136

137-
if (!File.Exists(UpdaterBlockPath) && HasInternetConnection())
137+
if (!File.Exists(UpdaterBlockPath))
138138
{
139139
try
140140
{
141-
using (var infoClient = new WebClient())
141+
List<Exception> exceptions = new List<Exception>();
142+
bool didDownload = false;
143+
144+
// Try to download the update info file from the override path first
145+
if (File.Exists(UpdaterOverridePath))
142146
{
143-
infoClient.Headers.Add("User-Agent", HttpUserAgent);
147+
PathPrefix = File.ReadAllText(UpdaterOverridePath);
144148

145-
List<Exception> exceptions = new List<Exception>();
146-
bool didDownload = false;
147-
148-
// Try to download the update info file from the override path first
149-
if (File.Exists(UpdaterOverridePath))
149+
// remove override if the URL is in our URL list
150+
foreach (string url in LauncherKitUpdateUrls)
150151
{
151-
PathPrefix = File.ReadAllText(UpdaterOverridePath);
152+
if (url == PathPrefix)
153+
{
154+
File.Delete(UpdaterOverridePath);
155+
break;
156+
}
157+
}
152158

153-
// remove override if the URL is in our URL list
154-
foreach (string url in LauncherKitUpdateUrls)
159+
try
160+
{
161+
using (var downloadClient = new DownloadClient(Path.Combine(PathPrefix, "update.info")))
155162
{
156-
if (url == PathPrefix)
157-
{
158-
File.Delete(UpdaterOverridePath);
159-
break;
160-
}
163+
downloadClient.SetTimeout(TimeSpan.FromSeconds(10));
164+
downloadClient.DownloadFile(UpdateInfoDestPath);
161165
}
162166

167+
// Hides exceptions if the download was successful
168+
didDownload = true;
169+
}
170+
catch (Exception ex)
171+
{
172+
exceptions.Add(ex);
173+
}
174+
}
175+
// Try to download the update info file from each URL in the list
176+
else
177+
{
178+
foreach (string url in LauncherKitUpdateUrls)
179+
{
163180
try
164181
{
165-
infoClient.DownloadFile(Path.Combine(PathPrefix, "update.info"), UpdateInfoDestPath);
182+
using (var downloadClient = new DownloadClient(Path.Combine(PathPrefix, "update.info")))
183+
{
184+
downloadClient.SetTimeout(TimeSpan.FromSeconds(10));
185+
downloadClient.DownloadFile(UpdateInfoDestPath);
186+
}
166187

167188
// Hides exceptions if the download was successful
168189
didDownload = true;
190+
PathPrefix = url;
191+
break;
169192
}
170193
catch (Exception ex)
171194
{
172195
exceptions.Add(ex);
173196
}
174197
}
175-
// Try to download the update info file from each URL in the list
176-
else
177-
{
178-
foreach (string url in LauncherKitUpdateUrls)
179-
{
180-
try
181-
{
182-
infoClient.DownloadFile(Path.Combine(url, "update.info"), UpdateInfoDestPath);
183-
184-
// Hides exceptions if the download was successful
185-
didDownload = true;
186-
PathPrefix = url;
187-
break;
188-
}
189-
catch (Exception ex)
190-
{
191-
exceptions.Add(ex);
192-
}
193-
}
194-
}
198+
}
195199

196-
// If no download was successful, show all exceptions, one at a time
197-
if (!didDownload)
200+
// If no download was successful, show all exceptions, one at a time
201+
if (!didDownload)
202+
{
203+
foreach (var ex in exceptions)
198204
{
199-
foreach (var ex in exceptions)
200-
{
201-
ShowUpdateCheckFailedMessage(ex);
202-
}
205+
ShowUpdateCheckFailedMessage(ex);
203206
}
207+
208+
// early return when failed
209+
return;
204210
}
205211

206212
if (File.Exists(UpdateInfoDestPath))
@@ -221,13 +227,13 @@ public static void CheckForUpdates()
221227
}
222228
else
223229
{
224-
var installerClient = new WebClient();
225-
installerClient.Headers.Add("User-Agent", HttpUserAgent);
226230

227231
if (File.Exists(UpdaterDestPath))
228232
File.Delete(UpdaterDestPath);
229233

230-
installerClient.DownloadFile(updateInfoLines[3], UpdaterDestPath);
234+
var downloadClient = new DownloadClient(updateInfoLines[3]);
235+
downloadClient.SetTimeout(TimeSpan.FromMinutes(5));
236+
downloadClient.DownloadFile(UpdaterDestPath);
231237

232238
if (File.Exists(UpdaterDestPath))
233239
{
@@ -301,23 +307,5 @@ static void ShowUnrecognizedUpdateInfoVersionMessage()
301307
{
302308
MessageBox.Show("This update to the Spore ModAPI Launcher Kit must be downloaded manually.");
303309
}
304-
305-
static bool HasInternetConnection()
306-
{
307-
try
308-
{
309-
using (var client = new WebClient())
310-
{
311-
client.Headers.Add("User-Agent", HttpUserAgent);
312-
client.DownloadString("https://1.1.1.1");
313-
return true;
314-
}
315-
}
316-
catch (Exception ex)
317-
{
318-
MessageBox.Show("The Launcher Kit could not connect to the internet to check for updates. The Launcher Kit will still work, but you may be missing the latest features and improvements.\n\nCurrent version: " + CurrentVersion + "\n\n" + ex.ToString());
319-
return false;
320-
}
321-
}
322310
}
323311
}

0 commit comments

Comments
 (0)