-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathFormDownload.cs
197 lines (177 loc) · 7.11 KB
/
FormDownload.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows.Forms;
namespace GitForce
{
public partial class FormDownload : Form
{
private readonly BackgroundWorker worker = new BackgroundWorker();
private readonly WebClient client = new WebClient();
private readonly AutoResetEvent inProgress = new AutoResetEvent(false);
private bool isCompleted;
private readonly string webPage;
private readonly string regEx;
private readonly string mergeWebPath;
/// <summary>
/// Local path and name of the file that was downloaded
/// </summary>
public string TargetFile { get; private set; }
public FormDownload(string title, string webPageArg, string regExArg, string mergeWebPathArg)
{
InitializeComponent();
Text = title;
webPage = webPageArg;
regEx = regExArg;
mergeWebPath = mergeWebPathArg;
Work();
}
/// <summary>
/// Initiate download of a file through a separate thread
/// </summary>
private void Work()
{
labelInfo.Text = "Searching for the latest installer...";
worker.DoWork += delegate
{
string webName;
if (GetTargetFile(out webName))
{
UIThread(() => labelInfo.Text = "Downloading file " + webName);
UIThread(() => btCancel.Enabled = true);
// Download the remote file into local temp directory and keep the file name
TargetFile = Path.Combine(Path.GetTempPath(), Path.GetFileName(webName));
string response = Download(TargetFile, webName);
if (response == String.Empty)
{
UIThread(() => labelInfo.Text = "SUCCESS");
}
else
{
UIThread(() => labelInfo.Text = response);
}
}
else
{
UIThread(() => labelInfo.Text = webName);
}
};
worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerAsync();
}
/// <summary>
/// This is a final function that gets invoked on a job completion
/// </summary>
void WorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Remove temporary file if we did not complete the download
if (!isCompleted)
{
if (!String.IsNullOrEmpty(TargetFile))
File.Delete(TargetFile);
DialogResult = DialogResult.Cancel;
}
else
DialogResult = DialogResult.OK;
}
/// <summary>
/// A helper function that lets us update controls in the GUI thread
/// </summary>
private void UIThread(Action code)
{
if (InvokeRequired)
BeginInvoke(code);
else
code.Invoke();
}
/// <summary>
/// Returns the web path of the target file to download.
/// Returns String.Empty if the file could not be itentified.
/// </summary>
private bool GetTargetFile(out string targetFile)
{
try
{
WebRequest request = WebRequest.Create(webPage);
request.Timeout = 4000;
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
StringBuilder file = new StringBuilder();
file.Append(reader.ReadToEnd());
// Find the first executable
Regex r = new Regex(regEx, RegexOptions.Compiled);
if (r.IsMatch(file.ToString()))
{
targetFile = r.Match(file.ToString()).Result("${file}");
// Optionally merge the root of the target web page with the name of the file to download
if (!string.IsNullOrEmpty(mergeWebPath))
targetFile = webPage + mergeWebPath + targetFile;
return true;
}
targetFile = "Could not find a target file matching a pattern!";
}
catch (Exception ex)
{
targetFile = ex.Message;
}
return false;
}
/// <summary>
/// Download a file from the web path
/// </summary>
private string Download(string target, string webPath)
{
try
{
UriBuilder url = new UriBuilder(webPath);
client.Proxy = null;
client.DownloadProgressChanged += ClientDownloadProgressChanged;
client.DownloadFileCompleted += ClientDownloadFileCompleted;
client.DownloadFileAsync(url.Uri, target);
inProgress.WaitOne(); // Wait until download completes or user cancels
if (isCompleted==false)
return String.Empty;
return "Download has been cancelled.";
}
catch (Exception ex)
{
return ex.Message;
}
}
/// <summary>
/// Callback by the web client class when the download finish (completed or cancelled)
/// </summary>
void ClientDownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
// The class is done downloading, print a message which may be seen if there is a pause
// after a file has been downloaded (seen that happen with virus scanners active)
UIThread(() => labelInfo.Text = labelInfo.Text + Environment.NewLine + "Preparing to install...");
UIThread(() => btCancel.Enabled = false);
Thread.Sleep(500); // Pause a bit for a better visual (to show the progress bar at 100%)
inProgress.Set();
isCompleted = !e.Cancelled;
}
/// <summary>
/// Callback by the web client when a new piece of file has been incrementally downloaded
/// </summary>
void ClientDownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
string progress = String.Format("Downloaded {0} of {1} Kb", e.BytesReceived / 1024, e.TotalBytesToReceive / 1024);
UIThread(() => labelProgress.Text = progress);
UIThread(() => progressBar.Maximum = (int) e.TotalBytesToReceive);
UIThread(() => progressBar.Value = (int) e.BytesReceived);
}
/// <summary>
/// User clicked on the Cancel button. Abort the download.
/// </summary>
private void BtCancelClick(object sender, EventArgs e)
{
client.CancelAsync();
}
}
}