Use HttpClient in FileDownloader class

This commit is contained in:
Jaex 2023-10-28 08:15:24 +03:00
parent 7085012fd4
commit bbb3d108f3
3 changed files with 100 additions and 118 deletions

View file

@ -26,21 +26,19 @@ You should have received a copy of the GNU General Public License
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Http;
using System.Threading.Tasks;
namespace ShareX.HelpersLib
{
public class FileDownloader
{
public event EventHandler FileSizeReceived, DownloadStarted, ProgressChanged, DownloadCompleted, ExceptionThrown;
public event Action FileSizeReceived, DownloadStarted, ProgressChanged, DownloadCompleted, ExceptionThrown;
public string URL { get; private set; }
public string DownloadLocation { get; private set; }
public bool IsDownloading { get; private set; }
public bool IsCanceled { get; private set; }
public bool IsPaused { get; private set; }
public long FileSize { get; private set; }
public long DownloadedSize { get; private set; }
public double DownloadSpeed { get; private set; }
@ -58,30 +56,25 @@ public double DownloadPercentage
}
}
public IWebProxy Proxy { get; set; }
public string AcceptHeader { get; set; }
public Exception LastException { get; private set; }
private const int bufferSize = 32768;
public FileDownloader(string url, string downloadLocation, IWebProxy proxy = null, string acceptHeader = null)
public FileDownloader(string url, string downloadLocation)
{
URL = url;
DownloadLocation = downloadLocation;
Proxy = proxy;
AcceptHeader = acceptHeader;
}
public void StartDownload()
public async Task StartDownload()
{
if (!IsDownloading && !string.IsNullOrEmpty(URL))
{
IsDownloading = true;
IsCanceled = false;
IsPaused = false;
Progress<EventHandler> progress = new Progress<EventHandler>(OnProgressChanged);
Task.Run(() => DoWork(progress));
await DoWork();
}
}
@ -90,110 +83,88 @@ public void StopDownload()
IsCanceled = true;
}
public void PauseDownload()
{
IsPaused = true;
}
public void ResumeDownload()
{
IsPaused = false;
}
private void OnProgressChanged(EventHandler eventHandler)
{
eventHandler?.Invoke(this, EventArgs.Empty);
}
private void DoWork(IProgress<EventHandler> progress)
private async Task DoWork()
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.UserAgent = ShareXResources.UserAgent;
request.Proxy = Proxy;
HttpClient client = HttpClientFactory.Create();
if (!string.IsNullOrEmpty(AcceptHeader))
using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, URL))
{
request.Accept = AcceptHeader;
}
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
FileSize = response.ContentLength;
progress.Report(FileSizeReceived);
if (FileSize > 0)
if (!string.IsNullOrEmpty(AcceptHeader))
{
Stopwatch timer = new Stopwatch();
Stopwatch progressEventTimer = new Stopwatch();
long speedTest = 0;
requestMessage.Headers.Accept.ParseAdd(AcceptHeader);
}
byte[] buffer = new byte[(int)Math.Min(bufferSize, FileSize)];
int bytesRead;
using (HttpResponseMessage responseMessage = await client.SendAsync(requestMessage, HttpCompletionOption.ResponseHeadersRead))
{
responseMessage.EnsureSuccessStatusCode();
using (FileStream fs = new FileStream(DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.Read))
using (Stream responseStream = response.GetResponseStream())
FileSize = responseMessage.Content.Headers.ContentLength ?? -1;
FileSizeReceived?.Invoke();
if (FileSize > 0)
{
progress.Report(DownloadStarted);
Stopwatch timer = new Stopwatch();
Stopwatch progressEventTimer = new Stopwatch();
long speedTest = 0;
while (DownloadedSize < FileSize && !IsCanceled)
byte[] buffer = new byte[(int)Math.Min(bufferSize, FileSize)];
int bytesRead;
using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
using (FileStream fileStream = new FileStream(DownloadLocation, FileMode.Create, FileAccess.Write, FileShare.Read))
{
while (IsPaused && !IsCanceled)
DownloadStarted?.Invoke();
while (DownloadedSize < FileSize && !IsCanceled)
{
timer.Reset();
Thread.Sleep(10);
}
if (!timer.IsRunning)
{
timer.Start();
}
if (IsCanceled)
{
return;
}
if (!progressEventTimer.IsRunning)
{
progressEventTimer.Start();
}
if (!timer.IsRunning)
{
timer.Start();
}
bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
await fileStream.WriteAsync(buffer, 0, bytesRead);
if (!progressEventTimer.IsRunning)
{
progressEventTimer.Start();
}
DownloadedSize += bytesRead;
speedTest += bytesRead;
bytesRead = responseStream.Read(buffer, 0, buffer.Length);
fs.Write(buffer, 0, bytesRead);
DownloadedSize += bytesRead;
speedTest += bytesRead;
if (timer.ElapsedMilliseconds > 500)
{
DownloadSpeed = (double)speedTest / timer.ElapsedMilliseconds * 1000;
speedTest = 0;
timer.Reset();
}
if (timer.ElapsedMilliseconds > 500)
{
DownloadSpeed = (double)speedTest / timer.ElapsedMilliseconds * 1000;
speedTest = 0;
timer.Reset();
}
if (progressEventTimer.ElapsedMilliseconds > 100)
{
ProgressChanged?.Invoke();
if (progressEventTimer.ElapsedMilliseconds > 100)
{
progress.Report(ProgressChanged);
progressEventTimer.Reset();
progressEventTimer.Reset();
}
}
}
}
progress.Report(ProgressChanged);
progress.Report(DownloadCompleted);
ProgressChanged?.Invoke();
DownloadCompleted?.Invoke();
}
}
}
}
catch (Exception ex)
catch (Exception e)
{
if (!IsCanceled)
{
LastException = ex;
LastException = e;
progress.Report(ExceptionThrown);
ExceptionThrown?.Invoke();
}
}
finally

View file

@ -594,10 +594,10 @@ public static async Task DownloadFileAsync(string url, string filePath)
{
if (responseMessage.IsSuccessStatusCode)
{
using (Stream stream = await responseMessage.Content.ReadAsStreamAsync())
using (Stream responseStream = await responseMessage.Content.ReadAsStreamAsync())
using (FileStream fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
await stream.CopyToAsync(fileStream);
await responseStream.CopyToAsync(fileStream);
}
}
}
@ -632,7 +632,7 @@ public static async Task<Bitmap> DownloadImageAsync(string url)
{
HttpClient client = HttpClientFactory.Create();
using (HttpResponseMessage responseMessage = await client.GetAsync(url))
using (HttpResponseMessage responseMessage = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
if (responseMessage.IsSuccessStatusCode && responseMessage.Content.Headers.ContentType != null)
{
@ -676,7 +676,8 @@ public static async Task<string> GetFileNameFromWebServerAsync(string url)
{
HttpClient client = HttpClientFactory.Create();
using (HttpResponseMessage responseMessage = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url)))
using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Head, url))
using (HttpResponseMessage responseMessage = await client.SendAsync(requestMessage))
{
if (responseMessage.Content.Headers.ContentDisposition != null)
{

View file

@ -28,8 +28,8 @@ You should have received a copy of the GNU General Public License
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ShareX.HelpersLib
@ -42,7 +42,6 @@ public partial class DownloaderForm : Form
public string URL { get; set; }
public string FileName { get; set; }
public string DownloadLocation { get; private set; }
public IWebProxy Proxy { get; set; }
public string AcceptHeader { get; set; }
public bool AutoStartDownload { get; set; }
public InstallType InstallType { get; set; }
@ -57,7 +56,6 @@ private DownloaderForm()
InitializeComponent();
ShareXResources.ApplyTheme(this);
Proxy = HelpersOptions.CurrentProxy.GetWebProxy();
ChangeStatus(Resources.DownloaderForm_DownloaderForm_Waiting_);
Status = DownloaderFormStatus.Waiting;
AutoStartDownload = true;
@ -81,21 +79,21 @@ public DownloaderForm(UpdateChecker updateChecker) : this(updateChecker.Download
}
}
private void DownloaderForm_Shown(object sender, EventArgs e)
private async void DownloaderForm_Shown(object sender, EventArgs e)
{
if (AutoStartDownload)
{
StartDownload();
await StartDownload();
}
}
private void btnAction_MouseClick(object sender, MouseEventArgs e)
private async void btnAction_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (Status == DownloaderFormStatus.Waiting)
{
StartDownload();
await StartDownload();
}
else if (Status == DownloaderFormStatus.DownloadCompleted)
{
@ -131,6 +129,7 @@ private void RunInstallerWithDelay(int delay = 1000)
Thread.Sleep(delay);
RunInstaller();
});
thread.Start();
}
else
@ -197,17 +196,7 @@ private void ChangeStatus(string status)
lblStatus.Text = Helpers.SafeStringFormat(Resources.DownloaderForm_ChangeStatus_Status___0_, status);
}
private void ChangeProgress()
{
if (fileDownloader != null)
{
pbProgress.Value = (int)Math.Round(fileDownloader.DownloadPercentage);
lblProgress.Text = Helpers.SafeStringFormat(CultureInfo.CurrentCulture, Resources.DownloaderForm_ChangeProgress_Progress,
fileDownloader.DownloadPercentage, fileDownloader.DownloadSpeed / 1024, fileDownloader.DownloadedSize / 1024, fileDownloader.FileSize / 1024);
}
}
private void StartDownload()
private async Task StartDownload()
{
if (!string.IsNullOrEmpty(URL) && Status == DownloaderFormStatus.Waiting)
{
@ -220,19 +209,35 @@ private void StartDownload()
DebugHelper.WriteLine($"Downloading: \"{URL}\" -> \"{DownloadLocation}\"");
fileDownloader = new FileDownloader(URL, DownloadLocation, Proxy, AcceptHeader);
fileDownloader.FileSizeReceived += (v1, v2) => ChangeProgress();
fileDownloader.DownloadStarted += (v1, v2) => ChangeStatus(Resources.DownloaderForm_StartDownload_Downloading_);
fileDownloader.ProgressChanged += (v1, v2) => ChangeProgress();
fileDownloader.DownloadCompleted += fileDownloader_DownloadCompleted;
fileDownloader.ExceptionThrown += (v1, v2) => ChangeStatus(fileDownloader.LastException.Message);
fileDownloader.StartDownload();
fileDownloader = new FileDownloader(URL, DownloadLocation);
fileDownloader.AcceptHeader = AcceptHeader;
fileDownloader.FileSizeReceived += FileDownloader_ProgressChanged;
fileDownloader.DownloadStarted += FileDownloader_DownloadStarted;
fileDownloader.ProgressChanged += FileDownloader_ProgressChanged;
fileDownloader.DownloadCompleted += FileDownloader_DownloadCompleted;
fileDownloader.ExceptionThrown += FileDownloader_ExceptionThrown;
await fileDownloader.StartDownload();
ChangeStatus(Resources.DownloaderForm_StartDownload_Getting_file_size_);
}
}
private void fileDownloader_DownloadCompleted(object sender, EventArgs e)
private void FileDownloader_DownloadStarted()
{
ChangeStatus(Resources.DownloaderForm_StartDownload_Downloading_);
}
private void FileDownloader_ProgressChanged()
{
if (fileDownloader != null)
{
pbProgress.Value = (int)Math.Round(fileDownloader.DownloadPercentage);
lblProgress.Text = Helpers.SafeStringFormat(CultureInfo.CurrentCulture, Resources.DownloaderForm_ChangeProgress_Progress,
fileDownloader.DownloadPercentage, fileDownloader.DownloadSpeed / 1024, fileDownloader.DownloadedSize / 1024, fileDownloader.FileSize / 1024);
}
}
private void FileDownloader_DownloadCompleted()
{
ChangeStatus(Resources.DownloaderForm_fileDownloader_DownloadCompleted_Download_completed_);
Status = DownloaderFormStatus.DownloadCompleted;
@ -244,6 +249,11 @@ private void fileDownloader_DownloadCompleted(object sender, EventArgs e)
}
}
private void FileDownloader_ExceptionThrown()
{
ChangeStatus(fileDownloader.LastException.Message);
}
private void DownloaderForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (Status == DownloaderFormStatus.DownloadStarted && fileDownloader != null)