Skip to content

Instantly share code, notes, and snippets.

@jmgomez
Last active December 24, 2015 09:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmgomez/6779191 to your computer and use it in GitHub Desktop.
Save jmgomez/6779191 to your computer and use it in GitHub Desktop.
A simple download manager to download files via http. Feature to show percentage and resume downloads.
public interface IDownloadManager {
event DownloadManager.PercentageChangedDelegate OnPercentageChanged;
event DownloadManager.DownloadErrorDelegate OnDownloadError;
event DownloadManager.DownloadCompleteDelegate OnDownloadComplete;
Task DownloadFileAsync(string url, string localPath);
void AbortDownload();
bool IsTheSameFile(string expectedMD5, string filePath);
double Percentage { get; }
}
public class DownloadManager : IDownloadManager {
const int BlockSize = 512;
HttpWebRequest request;
public delegate void PercentageChangedDelegate(double percentage);
public event PercentageChangedDelegate OnPercentageChanged = delegate {};
public delegate void DownloadCompleteDelegate();
public event DownloadCompleteDelegate OnDownloadComplete = delegate { };
public delegate void DownloadErrorDelegate(string error);
public event DownloadErrorDelegate OnDownloadError = delegate { };
public double Percentage { get; private set; }
public async Task DownloadFileAsync(string url, string localPath) {
try {
PrepareDownload(url, localPath);
await StartDownload(localPath);
}
catch (Exception e) {
OnDownloadError.Invoke(e.Message);
}
}
void PrepareDownload(string url, string localPath) {
request = (HttpWebRequest)HttpWebRequest.Create(url);
ResumeDownload(localPath);
Percentage = 0;
}
void ResumeDownload(string localPath) {
if (!File.Exists(localPath)) return;
using (var file = File.OpenRead(localPath))
request.AddRange(file.Length);
}
async Task StartDownload(string localPath) {
var response = await request.GetResponseAsync();
using (var responseStream = response.GetResponseStream())
using (var fileStream = new FileStream(localPath, FileMode.Append))
DownloadAndStoreBlocks(responseStream, fileStream, response.ContentLength);
OnDownloadComplete.Invoke();
}
void DownloadAndStoreBlocks(Stream origin, Stream destiny, long totalSize) {
var bytes = new byte[BlockSize];
while (true) {
var readSize = origin.Read(bytes, 0, BlockSize);
if (readSize <= 0) break;
destiny.Write(bytes, 0, readSize);
CalculateAndRaisePercentage(destiny.Length, totalSize);
}
}
void CalculateAndRaisePercentage(long sizeDownloaded, long totalSize) {
Percentage = Math.Round(((double)sizeDownloaded / (double)totalSize) * 100f,2);
OnPercentageChanged.Invoke(Percentage);
}
public void AbortDownload() {
request.Abort();
}
public bool IsTheSameFile(string expectedMD5, string filePath) {
using (var hash = MD5.Create())
using (var fs = File.OpenRead(filePath)) {
var md5 = BitConverter.ToString(hash.ComputeHash(fs)).Replace("-", "").ToLower();
return md5.Equals(expectedMD5);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment