228 lines
5.7 KiB
C#
228 lines
5.7 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright 2007-2010 The OpenRA Developers (see AUTHORS)
|
|
* This file is part of OpenRA, which is free software. It is made
|
|
* available to you under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation. For more information,
|
|
* see LICENSE.
|
|
*/
|
|
#endregion
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.IO;
|
|
using System.IO.Pipes;
|
|
using System.Text.RegularExpressions;
|
|
using System.Windows.Forms;
|
|
|
|
namespace OpenRA.Launcher
|
|
{
|
|
public enum DownloadStatus
|
|
{
|
|
NOT_REGISTERED, AVAILABLE, DOWNLOADING, DOWNLOADED, EXTRACTING, EXTRACTED, ERROR
|
|
}
|
|
|
|
class Download : IDisposable
|
|
{
|
|
DownloadStatus status = DownloadStatus.NOT_REGISTERED;
|
|
string url = "", target = "", key = "";
|
|
BackgroundWorker downloadBGWorker, extractBGWorker;
|
|
int bytesTotal = 0, bytesDone = 0;
|
|
string errorMessage = "";
|
|
HtmlDocument document;
|
|
|
|
public string ErrorMessage
|
|
{
|
|
get { return errorMessage; }
|
|
}
|
|
|
|
public int BytesDone
|
|
{
|
|
get { return bytesDone; }
|
|
}
|
|
|
|
public int BytesTotal
|
|
{
|
|
get { return bytesTotal; }
|
|
}
|
|
|
|
public DownloadStatus Status
|
|
{
|
|
get { return status; }
|
|
}
|
|
|
|
public Download(HtmlDocument document, string key, string url, string filename)
|
|
{
|
|
this.url = url;
|
|
this.key = key;
|
|
this.document = document;
|
|
target = Path.Combine(Path.GetTempPath(), filename);
|
|
if (File.Exists(target))
|
|
status = DownloadStatus.DOWNLOADED;
|
|
else
|
|
status = DownloadStatus.AVAILABLE;
|
|
|
|
downloadBGWorker = new BackgroundWorker()
|
|
{
|
|
WorkerReportsProgress = true,
|
|
WorkerSupportsCancellation = true
|
|
};
|
|
|
|
downloadBGWorker.DoWork += RunDownload;
|
|
downloadBGWorker.ProgressChanged += UpdateProgress;
|
|
downloadBGWorker.RunWorkerCompleted += DownloadFinished;
|
|
|
|
extractBGWorker = new BackgroundWorker();
|
|
|
|
extractBGWorker.DoWork += DoExtraction;
|
|
extractBGWorker.RunWorkerCompleted += ExtractionFinished;
|
|
}
|
|
|
|
public void StartDownload()
|
|
{
|
|
if (!downloadBGWorker.IsBusy)
|
|
{
|
|
status = DownloadStatus.DOWNLOADING;
|
|
downloadBGWorker.RunWorkerAsync(new string[] { url, target });
|
|
}
|
|
}
|
|
|
|
public void CancelDownload()
|
|
{
|
|
if (downloadBGWorker.IsBusy)
|
|
downloadBGWorker.CancelAsync();
|
|
}
|
|
|
|
public void ExtractDownload(string destPath)
|
|
{
|
|
if (!extractBGWorker.IsBusy)
|
|
{
|
|
status = DownloadStatus.EXTRACTING;
|
|
extractBGWorker.RunWorkerAsync(new string[] { target, destPath });
|
|
}
|
|
}
|
|
|
|
static void RunDownload(object sender, DoWorkEventArgs e)
|
|
{
|
|
var bgWorker = sender as BackgroundWorker;
|
|
string[] args = e.Argument as string[];
|
|
string url = args[0];
|
|
string dest = args[1];
|
|
string pipename = UtilityProgram.GetPipeName();
|
|
var p = UtilityProgram.Call("--download-url", pipename, null, url, dest);
|
|
Regex r = new Regex(@"(\d{1,3})% (\d+)/(\d+) bytes");
|
|
|
|
NamedPipeClientStream pipe = new NamedPipeClientStream(".", pipename, PipeDirection.In);
|
|
pipe.Connect();
|
|
|
|
using (var response = new StreamReader(pipe))
|
|
{
|
|
while (!p.HasExited)
|
|
{
|
|
string s = response.ReadLine();
|
|
if (string.IsNullOrEmpty(s)) continue;
|
|
if (Util.IsError(ref s))
|
|
throw new Exception(s);
|
|
|
|
if (bgWorker.CancellationPending)
|
|
{
|
|
e.Cancel = true;
|
|
p.Kill();
|
|
return;
|
|
}
|
|
if (!r.IsMatch(s)) continue;
|
|
var m = r.Match(s);
|
|
bgWorker.ReportProgress(int.Parse(m.Groups[1].Value),
|
|
new string[] { m.Groups[2].Value, m.Groups[3].Value });
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdateProgress(object sender, ProgressChangedEventArgs e)
|
|
{
|
|
string[] s = e.UserState as string[];
|
|
bytesDone = int.Parse(s[0]);
|
|
bytesTotal = int.Parse(s[1]);
|
|
document.InvokeScript("downloadProgressed", new object[] { key });
|
|
}
|
|
|
|
void DownloadFinished(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
if (e.Error != null)
|
|
{
|
|
status = DownloadStatus.ERROR;
|
|
errorMessage = e.Error.Message;
|
|
//if (File.Exists(target))
|
|
// File.Delete(target);
|
|
document.InvokeScript("downloadProgressed", new object[] { key });
|
|
return;
|
|
}
|
|
|
|
if (e.Cancelled)
|
|
{
|
|
status = DownloadStatus.ERROR;
|
|
errorMessage = "Download Cancelled";
|
|
//if (File.Exists(target))
|
|
// File.Delete(target);
|
|
document.InvokeScript("downloadProgressed", new object[] { key });
|
|
return;
|
|
}
|
|
|
|
status = DownloadStatus.DOWNLOADED;
|
|
document.InvokeScript("downloadProgressed", new object[] { key });
|
|
}
|
|
|
|
void DoExtraction(object sender, DoWorkEventArgs e)
|
|
{
|
|
string[] args = e.Argument as string[];
|
|
string zipFile = args[0];
|
|
string destPath = args[1];
|
|
|
|
string pipename = UtilityProgram.GetPipeName();
|
|
var p = UtilityProgram.CallWithAdmin("--extract-zip", pipename, zipFile, destPath);
|
|
var pipe = new NamedPipeClientStream(".", pipename, PipeDirection.In);
|
|
|
|
pipe.Connect();
|
|
|
|
using (var reader = new StreamReader(pipe))
|
|
{
|
|
while (!p.HasExited)
|
|
{
|
|
string s = reader.ReadLine();
|
|
if (string.IsNullOrEmpty(s)) continue;
|
|
if (Util.IsError(ref s))
|
|
throw new Exception(s);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ExtractionFinished(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
if (e.Error != null)
|
|
{
|
|
status = DownloadStatus.ERROR;
|
|
errorMessage = e.Error.Message;
|
|
document.InvokeScript("extractProgressed", new object[] { key });
|
|
}
|
|
|
|
|
|
status = DownloadStatus.EXTRACTED;
|
|
document.InvokeScript("extractProgressed", new object[] { key });
|
|
}
|
|
|
|
bool disposed = false;
|
|
|
|
~Download()
|
|
{
|
|
if (!disposed)
|
|
Dispose();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (status == DownloadStatus.DOWNLOADING && File.Exists(target))
|
|
File.Delete(target);
|
|
disposed = true;
|
|
}
|
|
}
|
|
}
|