Skip to content

Commit

Permalink
Refactor DownloadTarget and DownloadPart
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Jan 10, 2024
1 parent 62a0bc7 commit c197f23
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 184 deletions.
11 changes: 5 additions & 6 deletions Core/Net/AutoUpdate.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Diagnostics;
using System.Reflection;
Expand Down Expand Up @@ -146,15 +145,15 @@ public void StartUpdateProcess(bool launchCKANAfterUpdate, IUser user = null)
// download updater app and new ckan.exe
string updaterFilename = Path.GetTempPath() + Guid.NewGuid().ToString() + ".exe";
string ckanFilename = Path.GetTempPath() + Guid.NewGuid().ToString() + ".exe";
Net.DownloadWithProgress(
NetAsyncDownloader.DownloadWithProgress(
new[]
{
new Net.DownloadTarget(
new List<Uri> { latestUpdate.UpdaterDownload },
new NetAsyncDownloader.DownloadTarget(
latestUpdate.UpdaterDownload,
updaterFilename,
latestUpdate.UpdaterSize),
new Net.DownloadTarget(
new List<Uri> { latestUpdate.ReleaseDownload },
new NetAsyncDownloader.DownloadTarget(
latestUpdate.ReleaseDownload,
ckanFilename,
latestUpdate.ReleaseSize),
},
Expand Down
54 changes: 3 additions & 51 deletions Core/Net/Net.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace CKAN
public static class Net
{
// The user agent that we report to web sites
// Maybe overwritten by command line args
public static string UserAgentString = "Mozilla/4.0 (compatible; CKAN)";

private const int MaxRetries = 3;
Expand Down Expand Up @@ -76,14 +77,14 @@ public static string Download(string url, string filename = null, IUser user = n

public static string Download(string url, out string etag, string filename = null, IUser user = null)
{
TxFileManager FileTransaction = new TxFileManager();

user = user ?? new NullUser();
user.RaiseMessage(Properties.Resources.NetDownloading, url);
var FileTransaction = new TxFileManager();

// Generate a temporary file if none is provided.
if (filename == null)
{

filename = FileTransaction.GetTempFileName();
}

Expand Down Expand Up @@ -141,55 +142,6 @@ public static string Download(string url, out string etag, string filename = nul
return filename;
}

public class DownloadTarget
{
public List<Uri> urls { get; private set; }
public string filename { get; private set; }
public long size { get; set; }
public string mimeType { get; private set; }

public DownloadTarget(List<Uri> urls, string filename = null, long size = 0, string mimeType = "")
{
TxFileManager FileTransaction = new TxFileManager();

this.urls = urls;
this.filename = string.IsNullOrEmpty(filename)
? FileTransaction.GetTempFileName()
: filename;
this.size = size;
this.mimeType = mimeType;
}
}

public static string DownloadWithProgress(string url, string filename = null, IUser user = null)
=> DownloadWithProgress(new Uri(url), filename, user);

public static string DownloadWithProgress(Uri url, string filename = null, IUser user = null)
{
var targets = new[] {
new DownloadTarget(new List<Uri> { url }, filename)
};
DownloadWithProgress(targets, user);
return targets.First().filename;
}

public static void DownloadWithProgress(IList<DownloadTarget> downloadTargets, IUser user = null)
{
var downloader = new NetAsyncDownloader(user ?? new NullUser());
downloader.onOneCompleted += (url, filename, error, etag) =>
{
if (error != null)
{
user?.RaiseError(error.ToString());
}
else
{
File.Move(filename, downloadTargets.First(p => p.urls.Contains(url)).filename);
}
};
downloader.DownloadAndWait(downloadTargets);
}

/// <summary>
/// Download a string from a URL
/// </summary>
Expand Down
114 changes: 114 additions & 0 deletions Core/Net/NetAsyncDownloader.DownloadPart.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.IO;
using System.ComponentModel;

using Autofac;

using CKAN.Configuration;

namespace CKAN
{
public partial class NetAsyncDownloader
{
// Private utility class for tracking downloads
private class DownloadPart
{
public readonly DownloadTarget target;
public readonly string path;

public DateTime lastProgressUpdateTime;
public long lastProgressUpdateSize;
public long bytesLeft;
public long size;
public long bytesPerSecond;
public Exception error;

// Number of target URLs already tried and failed
private int triedDownloads;

/// <summary>
/// Percentage, bytes received, total bytes to receive
/// </summary>
public event Action<int, long, long> Progress;
public event Action<object, AsyncCompletedEventArgs, string> Done;

private string mimeType => target.mimeType;
private ResumingWebClient agent;

public DownloadPart(DownloadTarget target)
{
this.target = target;
path = target.filename ?? Path.GetTempFileName();
size = bytesLeft = target.size;
lastProgressUpdateTime = DateTime.Now;
triedDownloads = 0;
}

public void Download(Uri url, string path)
{
ResetAgent();
// Check whether to use an auth token for this host
if (url.IsAbsoluteUri
&& ServiceLocator.Container.Resolve<IConfiguration>().TryGetAuthToken(url.Host, out string token)
&& !string.IsNullOrEmpty(token))
{
log.InfoFormat("Using auth token for {0}", url.Host);
// Send our auth token to the GitHub API (or whoever else needs one)
agent.Headers.Add("Authorization", $"token {token}");
}
agent.DownloadFileAsyncWithResume(url, path);
}

public Uri CurrentUri => target.urls[triedDownloads];

public bool HaveMoreUris => triedDownloads + 1 < target.urls.Count;

public void NextUri()
{
if (HaveMoreUris)
{
++triedDownloads;
}
}

public void Abort()
{
agent?.CancelAsyncOverridden();
}

private void ResetAgent()
{
// This WebClient child class does some complicated stuff, let's keep using it for now
#pragma warning disable SYSLIB0014
agent = new ResumingWebClient();
#pragma warning restore SYSLIB0014

agent.Headers.Add("User-Agent", Net.UserAgentString);

// Tell the server what kind of files we want
if (!string.IsNullOrEmpty(mimeType))
{
log.InfoFormat("Setting MIME type {0}", mimeType);
agent.Headers.Add("Accept", mimeType);
}

// Forward progress and completion events to our listeners
agent.DownloadProgressChanged += (sender, args) =>
{
Progress?.Invoke(args.ProgressPercentage, args.BytesReceived, args.TotalBytesToReceive);
};
agent.DownloadProgress += (percent, bytesReceived, totalBytesToReceive) =>
{
Progress?.Invoke(percent, bytesReceived, totalBytesToReceive);
};
agent.DownloadFileCompleted += (sender, args) =>
{
Done?.Invoke(sender, args,
args.Cancelled || args.Error != null
? null
: agent.ResponseHeaders?.Get("ETag")?.Replace("\"", ""));
};
}
}
}
}
42 changes: 42 additions & 0 deletions Core/Net/NetAsyncDownloader.DownloadTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;

using ChinhDo.Transactions.FileManager;

namespace CKAN
{
public partial class NetAsyncDownloader
{
public class DownloadTarget
{
public List<Uri> urls { get; private set; }
public string filename { get; private set; }
public long size { get; set; }
public string mimeType { get; private set; }

public DownloadTarget(List<Uri> urls,
string filename = null,
long size = 0,
string mimeType = "")
{
var FileTransaction = new TxFileManager();

this.urls = urls;
this.filename = string.IsNullOrEmpty(filename)
? FileTransaction.GetTempFileName()
: filename;
this.size = size;
this.mimeType = mimeType;
}

public DownloadTarget(Uri url,
string filename = null,
long size = 0,
string mimeType = "")
: this(new List<Uri> { url },
filename, size, mimeType)
{
}
}
}
}
Loading

0 comments on commit c197f23

Please sign in to comment.