Use a new Downloader from https://github.com/bezzad/Downloader, add a write and download speed test to the settings interface.
This commit is contained in:
parent
49071a7f48
commit
19e5e5eb10
12 changed files with 301 additions and 185 deletions
|
|
@ -64,22 +64,84 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="notification is-danger is-light" *ngIf="error?.length > 0">Error saving settings: {{ error }}</div>
|
||||
<div class="field">
|
||||
<label class="label">Test download path permissions</label>
|
||||
<div class="control">
|
||||
<button
|
||||
class="button is-warning"
|
||||
(click)="testDownloadPath()"
|
||||
[disabled]="saving"
|
||||
[ngClass]="{ 'is-loading': saving }"
|
||||
*ngIf="!testPathError && !testPathSuccess"
|
||||
>
|
||||
Test permissions
|
||||
</button>
|
||||
<div class="notification is-danger is-light" *ngIf="testPathError">
|
||||
Could not test your download path<br />
|
||||
{{ testPathError }}
|
||||
</div>
|
||||
|
||||
<div class="notification is-danger is-light" *ngIf="testPathError?.length > 0">
|
||||
Could not test your download path<br />
|
||||
{{ testPathError }}
|
||||
<div class="notification is-success is-light" *ngIf="testPathSuccess">Your download path looks good!</div>
|
||||
</div>
|
||||
<div class="help">This will check if the download folder has write permissions.</div>
|
||||
</div>
|
||||
|
||||
<div class="notification is-success is-light" *ngIf="testPathSuccess">Successfully tested your download path</div>
|
||||
<div class="field">
|
||||
<label class="label">Test RealDebrid download speed</label>
|
||||
<div class="control">
|
||||
<button
|
||||
class="button is-warning"
|
||||
(click)="testDownloadSpeed()"
|
||||
[disabled]="saving"
|
||||
[ngClass]="{ 'is-loading': saving }"
|
||||
*ngIf="!testDownloadSpeedError && !testDownloadSpeedSuccess"
|
||||
>
|
||||
Test download speed
|
||||
</button>
|
||||
<div class="notification is-danger is-light" *ngIf="testDownloadSpeedError">
|
||||
Could not test your download speed<br />
|
||||
{{ testDownloadSpeedError }}
|
||||
</div>
|
||||
|
||||
<div class="notification is-success is-light" *ngIf="testDownloadSpeedSuccess">
|
||||
Download speed {{ testDownloadSpeedSuccess | filesize }}/s
|
||||
</div>
|
||||
</div>
|
||||
<div class="help">
|
||||
This will download a 10GB test file from RealDebrid. Hit cancel when you have seen enough.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="label">Test download folder write speed</label>
|
||||
<div class="control">
|
||||
<button
|
||||
class="button is-warning"
|
||||
(click)="testWriteSpeed()"
|
||||
[disabled]="saving"
|
||||
[ngClass]="{ 'is-loading': saving }"
|
||||
*ngIf="!testWriteSpeedError && !testWriteSpeedSuccess"
|
||||
>
|
||||
Test write speed
|
||||
</button>
|
||||
<div class="notification is-danger is-light" *ngIf="testWriteSpeedError">
|
||||
Could not test your download speed<br />
|
||||
{{ testWriteSpeedError }}
|
||||
</div>
|
||||
|
||||
<div class="notification is-success is-light" *ngIf="testWriteSpeedSuccess">
|
||||
Write speed {{ testWriteSpeedSuccess | filesize }}/s
|
||||
</div>
|
||||
</div>
|
||||
<div class="help">This will write a small file to your download folder to see how fast it can write to it.</div>
|
||||
</div>
|
||||
|
||||
<div class="notification is-danger is-light" *ngIf="error?.length > 0">Error saving settings: {{ error }}</div>
|
||||
</section>
|
||||
<footer class="modal-card-foot">
|
||||
<button class="button is-success" (click)="ok()" [disabled]="saving" [ngClass]="{ 'is-loading': saving }">
|
||||
Save Settings
|
||||
</button>
|
||||
<button class="button is-warning" (click)="test()" [disabled]="saving" [ngClass]="{ 'is-loading': saving }">
|
||||
Test permissions
|
||||
</button>
|
||||
<button class="button" (click)="cancel()" [disabled]="saving" [ngClass]="{ 'is-loading': saving }">Cancel</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -25,9 +25,16 @@ export class SettingsComponent implements OnInit {
|
|||
|
||||
public saving = false;
|
||||
public error: string;
|
||||
|
||||
public testPathError: string;
|
||||
public testPathSuccess: boolean;
|
||||
|
||||
public testDownloadSpeedError: string;
|
||||
public testDownloadSpeedSuccess: number;
|
||||
|
||||
public testWriteSpeedError: string;
|
||||
public testWriteSpeedSuccess: number;
|
||||
|
||||
public settingRealDebridApiKey: string;
|
||||
public settingDownloadPath: string;
|
||||
public settingMappedPath: string;
|
||||
|
|
@ -100,7 +107,7 @@ export class SettingsComponent implements OnInit {
|
|||
);
|
||||
}
|
||||
|
||||
public test(): void {
|
||||
public testDownloadPath(): void {
|
||||
this.saving = true;
|
||||
this.testPathError = null;
|
||||
this.testPathSuccess = false;
|
||||
|
|
@ -111,13 +118,45 @@ export class SettingsComponent implements OnInit {
|
|||
this.testPathSuccess = true;
|
||||
},
|
||||
(err) => {
|
||||
console.log(err);
|
||||
this.testPathError = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public testDownloadSpeed(): void {
|
||||
this.saving = true;
|
||||
this.testDownloadSpeedError = null;
|
||||
this.testDownloadSpeedSuccess = 0;
|
||||
|
||||
this.settingsService.testDownloadSpeed().subscribe(
|
||||
(result) => {
|
||||
this.saving = false;
|
||||
this.testDownloadSpeedSuccess = result;
|
||||
},
|
||||
(err) => {
|
||||
this.testDownloadSpeedError = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
public testWriteSpeed(): void {
|
||||
this.saving = true;
|
||||
this.testWriteSpeedError = null;
|
||||
this.testWriteSpeedSuccess = 0;
|
||||
|
||||
this.settingsService.testWriteSpeed().subscribe(
|
||||
(result) => {
|
||||
this.saving = false;
|
||||
this.testWriteSpeedSuccess = result;
|
||||
},
|
||||
(err) => {
|
||||
this.testWriteSpeedError = err.error;
|
||||
this.saving = false;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.isActive = false;
|
||||
this.openChange.emit(this.open);
|
||||
|
|
|
|||
|
|
@ -25,4 +25,12 @@ export class SettingsService {
|
|||
public testPath(path: string): Observable<void> {
|
||||
return this.http.post<void>(`/Api/Settings/TestPath`, { path });
|
||||
}
|
||||
|
||||
public testDownloadSpeed(): Observable<number> {
|
||||
return this.http.get<number>(`/Api/Settings/TestDownloadSpeed`);
|
||||
}
|
||||
|
||||
public testWriteSpeed(): Observable<number> {
|
||||
return this.http.get<number>(`/Api/Settings/TestWriteSpeed`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
|
|
|
|||
|
|
@ -12,10 +12,11 @@
|
|||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
<PackageReference Include="Serilog.Exceptions" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="4.1.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.26.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.27.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Downloader\Downloader.csproj" />
|
||||
<ProjectReference Include="..\RdtClient.Data\RdtClient.Data.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,30 +1,22 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Downloader;
|
||||
using RdtClient.Data.Models.Data;
|
||||
|
||||
namespace RdtClient.Service.Services
|
||||
{
|
||||
public class DownloadClient
|
||||
{
|
||||
public Boolean Finished { get; private set; }
|
||||
|
||||
public String Error { get; private set; }
|
||||
|
||||
public Int64 Speed { get; private set; }
|
||||
public Int64 BytesTotal { get; private set; }
|
||||
public Int64 BytesDone { get; private set; }
|
||||
private readonly String _destinationPath;
|
||||
|
||||
private readonly Download _download;
|
||||
private readonly String _destinationPath;
|
||||
private readonly Torrent _torrent;
|
||||
|
||||
private Boolean _cancelled = false;
|
||||
|
||||
private Int64 _bytesLastUpdate;
|
||||
private DateTime _nextUpdate;
|
||||
private DownloadService _downloader;
|
||||
|
||||
public DownloadClient(Download download, String destinationPath)
|
||||
{
|
||||
|
|
@ -33,7 +25,18 @@ namespace RdtClient.Service.Services
|
|||
_torrent = download.Torrent;
|
||||
}
|
||||
|
||||
public async Task Start()
|
||||
public Boolean Finished { get; private set; }
|
||||
|
||||
public String Error { get; private set; }
|
||||
|
||||
public Int64 Speed { get; private set; }
|
||||
public Int64 BytesTotal { get; private set; }
|
||||
public Int64 BytesDone { get; private set; }
|
||||
|
||||
private static Int64 LastTick { get; set; }
|
||||
private static ConcurrentBag<Int64> AverageSpeed { get; } = new ConcurrentBag<Int64>();
|
||||
|
||||
public async Task Start(Boolean writeToMemory)
|
||||
{
|
||||
BytesDone = 0;
|
||||
BytesTotal = 0;
|
||||
|
|
@ -58,7 +61,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
var fileName = uri.Segments.Last();
|
||||
var filePath = Path.Combine(torrentPath, fileName);
|
||||
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
|
|
@ -66,10 +69,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
await Task.Factory.StartNew(async delegate
|
||||
{
|
||||
if (!_cancelled)
|
||||
{
|
||||
await Download(uri, filePath);
|
||||
}
|
||||
await Download(filePath, writeToMemory);
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -81,98 +81,80 @@ namespace RdtClient.Service.Services
|
|||
|
||||
public void Cancel()
|
||||
{
|
||||
_cancelled = true;
|
||||
_downloader?.CancelAsync();
|
||||
}
|
||||
|
||||
private async Task Download(Uri uri, String filePath)
|
||||
private async Task Download(String filePath, Boolean writeToMemory)
|
||||
{
|
||||
try
|
||||
{
|
||||
_bytesLastUpdate = 0;
|
||||
_nextUpdate = DateTime.UtcNow.AddSeconds(1);
|
||||
LastTick = 0;
|
||||
|
||||
// Determine the file size
|
||||
var webRequest = WebRequest.Create(uri);
|
||||
webRequest.Method = "HEAD";
|
||||
webRequest.Timeout = 5000;
|
||||
Int64 responseLength;
|
||||
|
||||
using (var webResponse = await webRequest.GetResponseAsync())
|
||||
var downloadOpt = new DownloadConfiguration
|
||||
{
|
||||
responseLength = Int64.Parse(webResponse.Headers.Get("Content-Length"));
|
||||
}
|
||||
MaxTryAgainOnFailover = Int32.MaxValue,
|
||||
ParallelDownload = true,
|
||||
ChunkCount = 8,
|
||||
Timeout = 100,
|
||||
OnTheFlyDownload = writeToMemory,
|
||||
BufferBlockSize = 1024 * 8,
|
||||
MaximumBytesPerSecond = 100 * 1024 * 1024,
|
||||
TempDirectory = @"C:\temp",
|
||||
RequestConfiguration =
|
||||
{
|
||||
Accept = "*/*",
|
||||
UserAgent = $"rdt-client",
|
||||
ProtocolVersion = HttpVersion.Version11,
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate,
|
||||
KeepAlive = true,
|
||||
UseDefaultCredentials = false
|
||||
}
|
||||
};
|
||||
|
||||
var timeout = DateTimeOffset.UtcNow.AddHours(1);
|
||||
_downloader = new DownloadService(downloadOpt);
|
||||
|
||||
while (timeout > DateTimeOffset.UtcNow && !_cancelled)
|
||||
_downloader.DownloadProgressChanged += (_, args) =>
|
||||
{
|
||||
try
|
||||
var isElapsedTimeMoreThanOneSecond = Environment.TickCount - LastTick >= 1000;
|
||||
|
||||
if (isElapsedTimeMoreThanOneSecond)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
AverageSpeed.Add(args.BytesPerSecondSpeed);
|
||||
LastTick = Environment.TickCount;
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout <= DateTimeOffset.UtcNow)
|
||||
Speed = (Int64) AverageSpeed.Average();
|
||||
BytesDone = args.BytesReceived;
|
||||
BytesTotal = args.TotalBytesToReceive;
|
||||
};
|
||||
|
||||
_downloader.DownloadStarted += (_, args) =>
|
||||
{
|
||||
throw new Exception($"Download timed out");
|
||||
}
|
||||
AverageSpeed?.Clear();
|
||||
Speed = 0;
|
||||
BytesDone = 0;
|
||||
BytesTotal = args.TotalBytesToReceive;
|
||||
};
|
||||
|
||||
Speed = 0;
|
||||
_downloader.DownloadFileCompleted += (_, args) =>
|
||||
{
|
||||
if (args.Cancelled)
|
||||
{
|
||||
Error = $"The download was cancelled";
|
||||
}
|
||||
else if (args.Error != null)
|
||||
{
|
||||
Error = args.Error.Message;
|
||||
}
|
||||
|
||||
Finished = true;
|
||||
};
|
||||
|
||||
await _downloader.DownloadFileAsync(_download.Link, filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Error = $"An unexpected error occurred downloading {_download.Link} for torrent {_torrent.RdName}: {ex.Message}";
|
||||
}
|
||||
finally
|
||||
{
|
||||
Finished = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using RdtClient.Data.Data;
|
||||
using RdtClient.Data.Models.Data;
|
||||
|
|
@ -16,8 +17,8 @@ namespace RdtClient.Service.Services
|
|||
Task<String> GetString(String key);
|
||||
Task<Int32> GetNumber(String key);
|
||||
Task TestPath(String path);
|
||||
Task<Double> TestDownloadSpeed();
|
||||
Task<Double> TestWriteSpeed(String path);
|
||||
Task<Double> TestDownloadSpeed(CancellationToken cancellationToken);
|
||||
Task<Double> TestWriteSpeed();
|
||||
}
|
||||
|
||||
public class Settings : ISettings
|
||||
|
|
@ -29,6 +30,9 @@ namespace RdtClient.Service.Services
|
|||
_settingData = settingData;
|
||||
}
|
||||
|
||||
private static Int64 LastTick { get; set; }
|
||||
private static ConcurrentBag<Int64> AverageSpeed { get; } = new ConcurrentBag<Int64>();
|
||||
|
||||
public async Task<IList<Setting>> GetAll()
|
||||
{
|
||||
return await _settingData.GetAll();
|
||||
|
|
@ -83,78 +87,93 @@ namespace RdtClient.Service.Services
|
|||
File.Delete(testFile);
|
||||
}
|
||||
|
||||
public async Task<Double> TestDownloadSpeed()
|
||||
public async Task<Double> TestDownloadSpeed(CancellationToken cancellationToken)
|
||||
{
|
||||
var watch = new Stopwatch();
|
||||
var downloadPath = await GetString("DownloadPath");
|
||||
|
||||
var request = WebRequest.Create(new Uri("https://34.download.real-debrid.com/speedtest/testDefault.rar/" + DateTime.Now.Ticks));
|
||||
|
||||
watch.Start();
|
||||
|
||||
using var response = await request.GetResponseAsync();
|
||||
|
||||
await using var stream = response.GetResponseStream();
|
||||
|
||||
if (stream == null)
|
||||
{
|
||||
throw new IOException("No stream");
|
||||
}
|
||||
|
||||
var buffer = new Byte[64 * 1024];
|
||||
Int64 totalRead = 0;
|
||||
|
||||
while (totalRead < response.ContentLength)
|
||||
{
|
||||
var read = await stream.ReadAsync(buffer.AsMemory(0, buffer.Length));
|
||||
|
||||
if (read > 0)
|
||||
{
|
||||
totalRead += read;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
watch.Stop();
|
||||
|
||||
var downloadSpeed = totalRead / watch.Elapsed.TotalSeconds;
|
||||
|
||||
return downloadSpeed;
|
||||
}
|
||||
|
||||
public async Task<Double> TestWriteSpeed(String path)
|
||||
{
|
||||
var testFilePath = Path.Combine(path, "test.tmp");
|
||||
|
||||
const Int32 testFileSize = 1024 * 1024 * 1024;
|
||||
|
||||
var watch = new Stopwatch();
|
||||
var testFilePath = Path.Combine(downloadPath, "testDefault.rar");
|
||||
|
||||
if (File.Exists(testFilePath))
|
||||
{
|
||||
File.Delete(testFilePath);
|
||||
}
|
||||
|
||||
|
||||
var download = new Download
|
||||
{
|
||||
Link = "https://34.download.real-debrid.com/speedtest/testDefault.rar",
|
||||
Torrent = new Torrent
|
||||
{
|
||||
RdName = ""
|
||||
}
|
||||
};
|
||||
|
||||
var downloadClient = new DownloadClient(download, downloadPath);
|
||||
|
||||
await downloadClient.Start(true);
|
||||
|
||||
while (!downloadClient.Finished)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
downloadClient.Cancel();
|
||||
}
|
||||
|
||||
if (downloadClient.BytesDone > 1024 * 1024 * 100)
|
||||
{
|
||||
downloadClient.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(testFilePath))
|
||||
{
|
||||
File.Delete(testFilePath);
|
||||
}
|
||||
|
||||
return downloadClient.Speed;
|
||||
}
|
||||
|
||||
public async Task<Double> TestWriteSpeed()
|
||||
{
|
||||
var downloadPath = await GetString("DownloadPath");
|
||||
|
||||
var testFilePath = Path.Combine(downloadPath, "test.tmp");
|
||||
|
||||
if (File.Exists(testFilePath))
|
||||
{
|
||||
File.Delete(testFilePath);
|
||||
}
|
||||
|
||||
const Int32 testFileSize = 64 * 1024 * 1024;
|
||||
|
||||
var watch = new Stopwatch();
|
||||
|
||||
watch.Start();
|
||||
|
||||
var rnd = new Random();
|
||||
|
||||
|
||||
await using var fileStream = new FileStream(testFilePath, FileMode.Create, FileAccess.Write, FileShare.Write);
|
||||
|
||||
var buffer = new Byte[64 * 1024];
|
||||
|
||||
|
||||
while (fileStream.Length < testFileSize)
|
||||
{
|
||||
rnd.NextBytes(buffer);
|
||||
|
||||
fileStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
|
||||
watch.Stop();
|
||||
|
||||
var writeSpeed = fileStream.Length / watch.Elapsed.TotalSeconds;
|
||||
|
||||
fileStream.Close();
|
||||
|
||||
if (File.Exists(testFilePath))
|
||||
{
|
||||
File.Delete(testFilePath);
|
||||
}
|
||||
|
||||
return writeSpeed;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ namespace RdtClient.Service.Services
|
|||
|
||||
if (TorrentRunner.ActiveDownloadClients.TryAdd(download.DownloadId, downloadClient))
|
||||
{
|
||||
await downloadClient.Start();
|
||||
await downloadClient.Start(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
@ -58,24 +59,21 @@ namespace RdtClient.Web.Controllers
|
|||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("TestSpeed")]
|
||||
public async Task<ActionResult> TestSpeed()
|
||||
[Route("TestDownloadSpeed")]
|
||||
public async Task<ActionResult> TestDownloadSpeed(CancellationToken cancellationToken)
|
||||
{
|
||||
var downloadPath = await _settings.GetString("DownloadPath");
|
||||
var mappedPath = await _settings.GetString("MappedPath");
|
||||
var downloadSpeed = await _settings.TestDownloadSpeed(cancellationToken);
|
||||
|
||||
return Ok(downloadSpeed);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[Route("TestWriteSpeed")]
|
||||
public async Task<ActionResult> TestWriteSpeed()
|
||||
{
|
||||
var writeSpeed = await _settings.TestWriteSpeed();
|
||||
|
||||
var downloadSpeed = await _settings.TestDownloadSpeed();
|
||||
var containerWriteSpeed = await _settings.TestWriteSpeed(downloadPath);
|
||||
var remoteWriteSpeed = await _settings.TestWriteSpeed(mappedPath);
|
||||
|
||||
var result = new
|
||||
{
|
||||
downloadSpeed,
|
||||
containerWriteSpeed,
|
||||
remoteWriteSpeed
|
||||
};
|
||||
|
||||
return Ok(result);
|
||||
return Ok(writeSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,16 +7,16 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1">
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.2">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="5.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Identity.Core" Version="5.0.2" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.1.1" />
|
||||
<PackageReference Include="Serilog" Version="2.10.0" />
|
||||
|
|
|
|||
|
|
@ -5,9 +5,11 @@ VisualStudioVersion = 16.0.29911.84
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RdtClient.Web", "RdtClient.Web\RdtClient.Web.csproj", "{A8C7F095-89C6-4CD1-AFB2-27106F470D62}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RdtClient.Service", "RdtClient.Service\RdtClient.Service.csproj", "{06D27710-AE9A-4FA2-B043-1A4303561716}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RdtClient.Service", "RdtClient.Service\RdtClient.Service.csproj", "{06D27710-AE9A-4FA2-B043-1A4303561716}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RdtClient.Data", "RdtClient.Data\RdtClient.Data.csproj", "{92EF8817-AD73-4301-93BD-745D7D61DD74}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RdtClient.Data", "RdtClient.Data\RdtClient.Data.csproj", "{92EF8817-AD73-4301-93BD-745D7D61DD74}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Downloader", "Downloader\Downloader.csproj", "{48FF995D-AD14-4E41-BC69-7A144C84E3B6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
|
@ -27,6 +29,10 @@ Global
|
|||
{92EF8817-AD73-4301-93BD-745D7D61DD74}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{92EF8817-AD73-4301-93BD-745D7D61DD74}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{92EF8817-AD73-4301-93BD-745D7D61DD74}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{48FF995D-AD14-4E41-BC69-7A144C84E3B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{48FF995D-AD14-4E41-BC69-7A144C84E3B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{48FF995D-AD14-4E41-BC69-7A144C84E3B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{48FF995D-AD14-4E41-BC69-7A144C84E3B6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/Browsers/Enable/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=48FF995D_002DAD14_002D4E41_002DBC69_002D7A144C84E3B6/@EntryIndexedValue">ExplicitlyExcluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=92EF8817_002DAD73_002D4301_002D93BD_002D745D7D61DD74_002Fd_003AMigrations/@EntryIndexedValue">ExplicitlyExcluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=_002A_002Eappxmanifest/@EntryIndexedValue">*.appxmanifest</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/GeneratedCode/GeneratedCodeRegions/=_002A_002Ed_002Ets/@EntryIndexedValue">*.d.ts</s:String>
|
||||
|
|
|
|||
Loading…
Reference in a new issue