diff --git a/client/src/app/navbar/settings/settings.component.ts b/client/src/app/navbar/settings/settings.component.ts
index 42a8b52..dc79e1c 100644
--- a/client/src/app/navbar/settings/settings.component.ts
+++ b/client/src/app/navbar/settings/settings.component.ts
@@ -39,6 +39,7 @@ export class SettingsComponent implements OnInit {
public settingDownloadPath: string;
public settingMappedPath: string;
public settingTempPath: string;
+ public settingDownloadClient: string;
public settingDownloadLimit: number;
public settingDownloadChunkCount: number;
public settingDownloadMaxSpeed: number;
@@ -59,6 +60,7 @@ export class SettingsComponent implements OnInit {
this.settingDownloadPath = this.getSetting(results, 'DownloadPath');
this.settingMappedPath = this.getSetting(results, 'MappedPath');
this.settingTempPath = this.getSetting(results, 'TempPath');
+ this.settingDownloadClient = this.getSetting(results, 'DownloadClient');
this.settingDownloadLimit = parseInt(this.getSetting(results, 'DownloadLimit'), 10);
this.settingDownloadChunkCount = parseInt(this.getSetting(results, 'DownloadChunkCount'), 10);
this.settingDownloadMaxSpeed = parseInt(this.getSetting(results, 'DownloadMaxSpeed'), 10);
@@ -92,6 +94,10 @@ export class SettingsComponent implements OnInit {
settingId: 'TempPath',
value: this.settingTempPath,
},
+ {
+ settingId: 'DownloadClient',
+ value: this.settingDownloadClient,
+ },
{
settingId: 'DownloadLimit',
value: (this.settingDownloadLimit ?? 10).toString(),
diff --git a/server/RdtClient.Data/Data/DataContext.cs b/server/RdtClient.Data/Data/DataContext.cs
index eb98f52..254991b 100644
--- a/server/RdtClient.Data/Data/DataContext.cs
+++ b/server/RdtClient.Data/Data/DataContext.cs
@@ -57,6 +57,12 @@ namespace RdtClient.Data.Data
#endif
},
new Setting
+ {
+ SettingId = "DownloadClient",
+ Type = "String",
+ Value = @"Simple"
+ },
+ new Setting
{
SettingId = "TempPath",
Type = "String",
diff --git a/server/RdtClient.Service/Services/DownloadClient.cs b/server/RdtClient.Service/Services/DownloadClient.cs
index d3e9c63..e492071 100644
--- a/server/RdtClient.Service/Services/DownloadClient.cs
+++ b/server/RdtClient.Service/Services/DownloadClient.cs
@@ -1,11 +1,12 @@
using System;
-using System.Collections.Concurrent;
+using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Downloader;
using RdtClient.Data.Models.Data;
+using RdtClient.Service.Helpers;
namespace RdtClient.Service.Services
{
@@ -17,6 +18,7 @@ namespace RdtClient.Service.Services
private readonly Torrent _torrent;
private DownloadService _downloader;
+ private SimpleDownloader _simpleDownloader;
public DownloadClient(Download download, String destinationPath)
{
@@ -33,10 +35,7 @@ namespace RdtClient.Service.Services
public Int64 BytesTotal { get; private set; }
public Int64 BytesDone { get; private set; }
- private Int64 LastTick { get; set; }
- private ConcurrentBag
AverageSpeed { get; } = new ConcurrentBag();
-
- public async Task Start(Boolean onTheFlyDownload, String tempDirectory, Int32 chunkCount, Int64 maximumBytesPerSecond)
+ public async Task Start(IList settings)
{
BytesDone = 0;
BytesTotal = 0;
@@ -44,6 +43,8 @@ namespace RdtClient.Service.Services
try
{
+ var downloadClientSetting = settings.GetString("DownloadClient");
+
var fileUrl = _download.Link;
if (String.IsNullOrWhiteSpace(fileUrl))
@@ -69,7 +70,17 @@ namespace RdtClient.Service.Services
await Task.Factory.StartNew(async delegate
{
- await Download(filePath, onTheFlyDownload, tempDirectory, chunkCount, maximumBytesPerSecond);
+ switch (downloadClientSetting)
+ {
+ case "Simple":
+ await DownloadSimple(uri, filePath);
+ break;
+ case "MultiPart":
+ await DownloadMultiPart(filePath, settings);
+ break;
+ default:
+ throw new Exception($"Unknown download client {downloadClientSetting}");
+ }
});
}
catch (Exception ex)
@@ -82,24 +93,82 @@ namespace RdtClient.Service.Services
public void Cancel()
{
_downloader?.CancelAsync();
+ _simpleDownloader?.Cancel();
}
- private async Task Download(String filePath, Boolean onTheFlyDownload, String tempDirectory, Int32 chunkCount, Int64 maximumBytesPerSecond)
+ private async Task DownloadSimple(Uri uri, String filePath)
{
try
{
- LastTick = 0;
+ _simpleDownloader = new SimpleDownloader();
+ _simpleDownloader.DownloadProgressChanged += (_, args) =>
+ {
+ Speed = (Int64) args.BytesPerSecondSpeed;
+ BytesDone = args.ReceivedBytesSize;
+ BytesTotal = args.TotalBytesToReceive;
+ };
+
+ _simpleDownloader.DownloadFileCompleted += (_, args) =>
+ {
+ if (args.Cancelled)
+ {
+ Error = $"The download was cancelled";
+ }
+ else if (args.Error != null)
+ {
+ Error = args.Error.Message;
+ }
+
+ Finished = true;
+ };
+
+ Speed = 0;
+ BytesDone = 0;
+ BytesTotal = 0;
+
+ await _simpleDownloader.Download(uri, filePath);
+ }
+ catch (Exception ex)
+ {
+ Error = $"An unexpected error occurred downloading {_download.Link} for torrent {_torrent.RdName}: {ex.Message}";
+ Finished = true;
+ }
+ }
+
+ private async Task DownloadMultiPart(String filePath, IList settings)
+ {
+ try
+ {
+ var settingTempPath = settings.GetString("TempPath");
+ if (String.IsNullOrWhiteSpace(settingTempPath))
+ {
+ settingTempPath = Path.GetTempPath();
+ }
+
+ var settingDownloadChunkCount = settings.GetNumber("DownloadChunkCount");
+ if (settingDownloadChunkCount <= 0)
+ {
+ settingDownloadChunkCount = 1;
+ }
+
+ var settingDownloadMaxSpeed = settings.GetNumber("DownloadMaxSpeed");
+ if (settingDownloadMaxSpeed <= 0)
+ {
+ settingDownloadMaxSpeed = 0;
+ }
+ settingDownloadMaxSpeed = settingDownloadMaxSpeed * 1024 * 1024;
+
var downloadOpt = new DownloadConfiguration
{
MaxTryAgainOnFailover = Int32.MaxValue,
- ParallelDownload = chunkCount > 1,
- ChunkCount = chunkCount,
+ ParallelDownload = settingDownloadChunkCount > 1,
+ ChunkCount = settingDownloadChunkCount,
Timeout = 1000,
- OnTheFlyDownload = onTheFlyDownload,
+ OnTheFlyDownload = false,
BufferBlockSize = 1024 * 8,
- MaximumBytesPerSecond = maximumBytesPerSecond,
- TempDirectory = tempDirectory,
+ MaximumBytesPerSecond = settingDownloadMaxSpeed,
+ TempDirectory = settingTempPath,
RequestConfiguration =
{
Accept = "*/*",
@@ -115,31 +184,11 @@ namespace RdtClient.Service.Services
_downloader.DownloadProgressChanged += (_, args) =>
{
- var isElapsedTimeMoreThanOneSecond = Environment.TickCount - LastTick >= 1000;
-
- if (isElapsedTimeMoreThanOneSecond)
- {
- AverageSpeed.Add(args.BytesPerSecondSpeed);
- LastTick = Environment.TickCount;
- }
-
- if (AverageSpeed.Count > 0)
- {
- Speed = (Int64) AverageSpeed.Average();
- }
-
+ Speed = (Int64) args.BytesPerSecondSpeed;
BytesDone = args.ReceivedBytesSize;
BytesTotal = args.TotalBytesToReceive;
};
-
- _downloader.DownloadStarted += (_, args) =>
- {
- AverageSpeed?.Clear();
- Speed = 0;
- BytesDone = 0;
- BytesTotal = args.TotalBytesToReceive;
- };
-
+
_downloader.DownloadFileCompleted += (_, args) =>
{
if (args.Cancelled)
diff --git a/server/RdtClient.Service/Services/Settings.cs b/server/RdtClient.Service/Services/Settings.cs
index eed52ec..e77e95a 100644
--- a/server/RdtClient.Service/Services/Settings.cs
+++ b/server/RdtClient.Service/Services/Settings.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -30,10 +29,7 @@ namespace RdtClient.Service.Services
{
_settingData = settingData;
}
-
- private static Int64 LastTick { get; set; }
- private static ConcurrentBag AverageSpeed { get; } = new ConcurrentBag();
-
+
public async Task> GetAll()
{
return await _settingData.GetAll();
@@ -91,7 +87,8 @@ namespace RdtClient.Service.Services
public async Task TestDownloadSpeed(CancellationToken cancellationToken)
{
var downloadPath = await GetString("DownloadPath");
- var tempPath = await GetString("TempPath");
+
+ var settings = await GetAll();
var testFilePath = Path.Combine(downloadPath, "testDefault.rar");
@@ -111,7 +108,7 @@ namespace RdtClient.Service.Services
var downloadClient = new DownloadClient(download, downloadPath);
- await downloadClient.Start(false, tempPath, 8, 0);
+ await downloadClient.Start(settings);
while (!downloadClient.Finished)
{
diff --git a/server/RdtClient.Service/Services/SimpleDownloader.cs b/server/RdtClient.Service/Services/SimpleDownloader.cs
new file mode 100644
index 0000000..6d062c3
--- /dev/null
+++ b/server/RdtClient.Service/Services/SimpleDownloader.cs
@@ -0,0 +1,127 @@
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Net;
+using System.Threading.Tasks;
+using DownloadProgressChangedEventArgs = Downloader.DownloadProgressChangedEventArgs;
+
+namespace RdtClient.Service.Services
+{
+ public class SimpleDownloader
+ {
+ public Int64 Speed { get; private set; }
+ public Int64 BytesTotal { get; private set; }
+ public Int64 BytesDone { get; private set; }
+
+ public event EventHandler DownloadFileCompleted;
+ public event EventHandler DownloadProgressChanged;
+
+ private Boolean _cancelled = false;
+
+ private Int64 _bytesLastUpdate;
+ private DateTime _nextUpdate;
+
+ public async Task Download(Uri uri, String filePath)
+ {
+ try
+ {
+ _bytesLastUpdate = 0;
+ _nextUpdate = DateTime.UtcNow.AddSeconds(1);
+
+ // Determine the file size
+ var webRequest = WebRequest.Create(uri);
+ webRequest.Method = "HEAD";
+ webRequest.Timeout = 5000;
+ Int64 responseLength;
+
+ using (var webResponse = await webRequest.GetResponseAsync())
+ {
+ responseLength = Int64.Parse(webResponse.Headers.Get("Content-Length"));
+ }
+
+ var timeout = DateTimeOffset.UtcNow.AddHours(1);
+
+ while (timeout > DateTimeOffset.UtcNow && !_cancelled)
+ {
+ try
+ {
+ var request = WebRequest.Create(uri);
+ using var response = await request.GetResponseAsync();
+
+ await using var stream = response.GetResponseStream();
+
+ if (stream == null)
+ {
+ throw new IOException("No stream");
+ }
+
+ await using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write);
+ var buffer = new Byte[64 * 1024];
+
+ while (fileStream.Length < response.ContentLength && !_cancelled)
+ {
+ var read = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length));
+
+ if (read > 0)
+ {
+ fileStream.Write(buffer, 0, read);
+
+ BytesDone = fileStream.Length;
+ BytesTotal = responseLength;
+
+ if (DateTime.UtcNow > _nextUpdate)
+ {
+ Speed = fileStream.Length - _bytesLastUpdate;
+
+ _nextUpdate = DateTime.UtcNow.AddSeconds(1);
+ _bytesLastUpdate = fileStream.Length;
+
+ timeout = DateTimeOffset.UtcNow.AddHours(1);
+
+ DownloadProgressChanged?.Invoke(this, new DownloadProgressChangedEventArgs(null)
+ {
+ BytesPerSecondSpeed = Speed,
+ ProgressedByteSize = _bytesLastUpdate,
+ TotalBytesToReceive = BytesTotal,
+ AverageBytesPerSecondSpeed = Speed,
+ ReceivedBytesSize = BytesDone,
+ });
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ break;
+ }
+ catch (IOException)
+ {
+ await Task.Delay(1000);
+ }
+ catch (WebException)
+ {
+ await Task.Delay(1000);
+ }
+ }
+
+ if (timeout <= DateTimeOffset.UtcNow)
+ {
+ throw new Exception($"Download timed out");
+ }
+
+ DownloadFileCompleted?.Invoke(this, new AsyncCompletedEventArgs(null, false, null));
+ }
+ catch (Exception ex)
+ {
+ DownloadFileCompleted?.Invoke(this, new AsyncCompletedEventArgs(ex, false, null));
+ }
+ }
+
+ public void Cancel()
+ {
+ _cancelled = true;
+ }
+ }
+}
diff --git a/server/RdtClient.Service/Services/TorrentRunner.cs b/server/RdtClient.Service/Services/TorrentRunner.cs
index 37b7d09..434541f 100644
--- a/server/RdtClient.Service/Services/TorrentRunner.cs
+++ b/server/RdtClient.Service/Services/TorrentRunner.cs
@@ -96,25 +96,6 @@ namespace RdtClient.Service.Services
return;
}
- var settingTempPath = settings.GetString("TempPath");
- if (String.IsNullOrWhiteSpace(settingTempPath))
- {
- settingTempPath = Path.GetTempPath();
- }
-
- var settingDownloadChunkCount = settings.GetNumber("DownloadChunkCount");
- if (settingDownloadChunkCount <= 0)
- {
- settingDownloadChunkCount = 1;
- }
-
- var settingDownloadMaxSpeed = settings.GetNumber("DownloadMaxSpeed");
- if (settingDownloadMaxSpeed <= 0)
- {
- settingDownloadMaxSpeed = 0;
- }
- settingDownloadMaxSpeed = settingDownloadMaxSpeed * 1024 * 1024;
-
// Check if any torrents are finished downloading to the host, remove them from the active download list.
var completedActiveDownloads = ActiveDownloadClients.Where(m => m.Value.Finished).ToList();
@@ -213,7 +194,7 @@ namespace RdtClient.Service.Services
if (TorrentRunner.ActiveDownloadClients.TryAdd(download.DownloadId, downloadClient))
{
- await downloadClient.Start(false, settingTempPath, settingDownloadChunkCount, settingDownloadMaxSpeed);
+ await downloadClient.Start(settings);
}
}