Last active
December 24, 2015 09:39
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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