Optimize Download

pull/367/head
NextTurn 2019-02-13 00:00:00 +08:00
parent 33da176920
commit ba328e3162
No known key found for this signature in database
GPG Key ID: 17A0D50ADDE1A0C4
2 changed files with 85 additions and 29 deletions

View File

@ -8,6 +8,9 @@ using System.Runtime.InteropServices;
using System.ServiceProcess; using System.ServiceProcess;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
#if VNEXT
using System.Threading.Tasks;
#endif
using log4net; using log4net;
using log4net.Appender; using log4net.Appender;
using log4net.Config; using log4net.Config;
@ -199,23 +202,54 @@ namespace winsw
HandleFileCopies(); HandleFileCopies();
// handle downloads // handle downloads
foreach (Download d in _descriptor.Downloads) #if VNEXT
List<Download> downloads = _descriptor.Downloads;
Task[] tasks = new Task[downloads.Count];
for (int i = 0; i < downloads.Count; i++)
{ {
string downloadMsg = "Downloading: " + d.From + " to " + d.To + ". failOnError=" + d.FailOnError; Download download = downloads[i];
LogEvent(downloadMsg); string downloadMessage = $"Downloading: {download.From} to {download.To}. failOnError={download.FailOnError.ToString()}";
Log.Info(downloadMsg); LogEvent(downloadMessage);
Log.Info(downloadMessage);
tasks[i] = download.PerformAsync();
}
Task.WhenAll(tasks);
for (int i = 0; i < tasks.Length; i++)
{
if (tasks[i].IsFaulted)
{
Download download = downloads[i];
string errorMessage = $"Failed to download {download.From} to {download.To}";
AggregateException exception = tasks[i].Exception!;
LogEvent($"{errorMessage}. {exception.Message}");
Log.Error(errorMessage, exception);
// TODO: move this code into the download logic
if (download.FailOnError)
{
throw new IOException(errorMessage, exception);
}
}
}
#else
foreach (Download download in _descriptor.Downloads)
{
string downloadMessage = $"Downloading: {download.From} to {download.To}. failOnError={download.FailOnError.ToString()}";
LogEvent(downloadMessage);
Log.Info(downloadMessage);
try try
{ {
d.Perform(); download.Perform();
} }
catch (Exception e) catch (Exception e)
{ {
string errorMessage = "Failed to download " + d.From + " to " + d.To; string errorMessage = $"Failed to download {download.From} to {download.To}";
LogEvent(errorMessage + ". " + e.Message); LogEvent($"{errorMessage}. {e.Message}");
Log.Error(errorMessage, e); Log.Error(errorMessage, e);
// TODO: move this code into the download logic // TODO: move this code into the download logic
if (d.FailOnError) if (download.FailOnError)
{ {
throw new IOException(errorMessage, e); throw new IOException(errorMessage, e);
} }
@ -223,6 +257,7 @@ namespace winsw
// Else just keep going // Else just keep going
} }
} }
#endif
string? startarguments = _descriptor.Startarguments; string? startarguments = _descriptor.Startarguments;

View File

@ -2,6 +2,9 @@ using System;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text; using System.Text;
#if VNEXT
using System.Threading.Tasks;
#endif
using System.Xml; using System.Xml;
using winsw.Util; using winsw.Util;
@ -103,9 +106,13 @@ namespace winsw
/// <exception cref="WebException"> /// <exception cref="WebException">
/// Download failure. FailOnError flag should be processed outside. /// Download failure. FailOnError flag should be processed outside.
/// </exception> /// </exception>
#if VNEXT
public async Task PerformAsync()
#else
public void Perform() public void Perform()
#endif
{ {
WebRequest req = WebRequest.Create(From); WebRequest request = WebRequest.Create(From);
switch (Auth) switch (Auth)
{ {
@ -114,43 +121,57 @@ namespace winsw
break; break;
case AuthType.sspi: case AuthType.sspi:
req.UseDefaultCredentials = true; request.UseDefaultCredentials = true;
req.PreAuthenticate = true; request.PreAuthenticate = true;
req.Credentials = CredentialCache.DefaultCredentials; request.Credentials = CredentialCache.DefaultCredentials;
break; break;
case AuthType.basic: case AuthType.basic:
SetBasicAuthHeader(req, Username!, Password!); SetBasicAuthHeader(request, Username!, Password!);
break; break;
default: default:
throw new WebException("Code defect. Unsupported authentication type: " + Auth); throw new WebException("Code defect. Unsupported authentication type: " + Auth);
} }
WebResponse rsp = req.GetResponse(); string tmpFilePath = To + ".tmp";
FileStream tmpstream = new FileStream(To + ".tmp", FileMode.Create); #if VNEXT
CopyStream(rsp.GetResponseStream(), tmpstream); using (WebResponse response = await request.GetResponseAsync())
// only after we successfully downloaded a file, overwrite the existing one #else
using (WebResponse response = request.GetResponse())
#endif
using (Stream responseStream = response.GetResponseStream())
using (FileStream tmpStream = new FileStream(tmpFilePath, FileMode.Create))
{
#if VNEXT
await responseStream.CopyToAsync(tmpStream);
#elif NET20
CopyStream(responseStream, tmpStream);
#else
responseStream.CopyTo(tmpStream);
#endif
}
#if NETCOREAPP
File.Move(tmpFilePath, To, true);
#else
if (File.Exists(To)) if (File.Exists(To))
File.Delete(To); File.Delete(To);
File.Move(To + ".tmp", To); File.Move(tmpFilePath, To);
#endif
} }
#if NET20
private static void CopyStream(Stream i, Stream o) private static void CopyStream(Stream source, Stream destination)
{ {
byte[] buf = new byte[8192]; byte[] buffer = new byte[8192];
while (true) int read;
while ((read = source.Read(buffer, 0, buffer.Length)) != 0)
{ {
int len = i.Read(buf, 0, buf.Length); destination.Write(buffer, 0, read);
if (len <= 0)
break;
o.Write(buf, 0, len);
} }
i.Close();
o.Close();
} }
#endif
} }
} }