diff --git a/Knossos.NET/Classes/ThrottledStream.cs b/Knossos.NET/Classes/ThrottledStream.cs index 93d1cbfa..e1dbb6ea 100644 --- a/Knossos.NET/Classes/ThrottledStream.cs +++ b/Knossos.NET/Classes/ThrottledStream.cs @@ -1,6 +1,7 @@ -using System.Threading; +using System; using System.IO; -using System; +using System.Threading; +using System.Threading.Tasks; namespace Knossos.NET.Classes @@ -150,5 +151,11 @@ public override long Seek(long offset, SeekOrigin origin) { return stream.Seek(offset, origin); } + + public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + Limit(buffer.Length); + return stream.ReadAsync(buffer, cancellationToken); + } } } diff --git a/Knossos.NET/ViewModels/Templates/Tasks/DownloadFile.cs b/Knossos.NET/ViewModels/Templates/Tasks/DownloadFile.cs index 5e7b341b..d7c9bcf4 100644 --- a/Knossos.NET/ViewModels/Templates/Tasks/DownloadFile.cs +++ b/Knossos.NET/ViewModels/Templates/Tasks/DownloadFile.cs @@ -238,7 +238,32 @@ private async Task Download(Uri downloadUrl, string destinationFilePath, F throw new TaskCanceledException(); } - var bytesRead = await contentStream.ReadAsync(buffer); + int bytesRead = 0; + if (Knossos.globalSettings.antiStuck) + { + //If there is zero progress, cancel (throws exception) + using var readTimeoutCts = new CancellationTokenSource(TimeSpan.FromSeconds(ANTI_STUCK_CHECK_SECONDS)); + using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource!.Token, readTimeoutCts.Token); + try + { + bytesRead = await contentStream.ReadAsync(buffer.AsMemory(), linkedCts.Token); + } + catch (OperationCanceledException) + { + if (readTimeoutCts.IsCancellationRequested) + { + Log.Add(Log.LogSeverity.Warning, "TaskItemViewModel.Download", + $"[ANTI-STUCK] Mirror {CurrentMirror ?? downloadUrl.Host} is stuck. " + + "Changing to a diferent mirror..."); + } + return false; + } + } + else + { + bytesRead = await contentStream.ReadAsync(buffer.AsMemory(), cancellationTokenSource!.Token); + } + if (bytesRead == 0) { isMoreToRead = false;