From 2307b43c65c2cc04085baf9ab6aee97cf0228ec6 Mon Sep 17 00:00:00 2001 From: Stanley Dimant Date: Sun, 10 Jul 2022 21:51:42 +0200 Subject: [PATCH] handle download cancellation better --- MareSynchronos/Managers/CachedPlayer.cs | 16 +++-- MareSynchronos/MareSynchronos.csproj | 2 +- MareSynchronos/UI/CompactUI.cs | 2 +- MareSynchronos/UI/DownloadUi.cs | 2 +- MareSynchronos/UI/SettingsUi.cs | 4 +- .../WebAPI/ApIController.Functions.Files.cs | 61 +++++++++---------- .../WebAPI/ApiController.Connectivity.cs | 2 +- 7 files changed, 47 insertions(+), 42 deletions(-) diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index 6feab20..4ed5d27 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -107,18 +107,20 @@ public class CachedPlayer _downloadCancellationTokenSource?.Cancel(); _downloadCancellationTokenSource = new CancellationTokenSource(); var downloadToken = _downloadCancellationTokenSource.Token; - + var downloadId = _apiController.GetDownloadId(); Task.Run(async () => { List toDownloadReplacements; Dictionary moddedPaths; - while ((toDownloadReplacements = TryCalculateModdedDictionary(_cache[_lastAppliedEquipmentHash], out moddedPaths)).Count > 0) + int attempts = 0; + while ((toDownloadReplacements = TryCalculateModdedDictionary(_cache[_lastAppliedEquipmentHash], out moddedPaths)).Count > 0 && attempts++ <= 10) { Logger.Debug("Downloading missing files for player " + PlayerName); - await _apiController.DownloadFiles(toDownloadReplacements, downloadToken); + await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken); if (downloadToken.IsCancellationRequested) { + Logger.Verbose("Detected cancellation"); return; } @@ -129,7 +131,13 @@ public class CachedPlayer } ApplyCharacterData(_cache[_lastAppliedEquipmentHash], moddedPaths); - }, downloadToken); + }, downloadToken).ContinueWith(task => + { + if (!task.IsCanceled) return; + + Logger.Debug("Download Task was cancelled"); + _apiController.CancelDownload(downloadId); + }); } private List TryCalculateModdedDictionary(CharacterCacheDto cache, diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index 1181e7c..4ceb396 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ - 0.1.8.0 + 0.1.9.0 https://github.com/Penumbra-Sync/client diff --git a/MareSynchronos/UI/CompactUI.cs b/MareSynchronos/UI/CompactUI.cs index 341531b..50f9ec2 100644 --- a/MareSynchronos/UI/CompactUI.cs +++ b/MareSynchronos/UI/CompactUI.cs @@ -367,7 +367,7 @@ namespace MareSynchronos.UI ImGui.Text("No uploads in progress"); } - var currentDownloads = _apiController.CurrentDownloads.ToList(); + var currentDownloads = _apiController.CurrentDownloads.SelectMany(k => k.Value).ToList(); ImGui.PushFont(UiBuilder.IconFont); ImGui.Text(FontAwesomeIcon.Download.ToIconString()); ImGui.PopFont(); diff --git a/MareSynchronos/UI/DownloadUi.cs b/MareSynchronos/UI/DownloadUi.cs index cb684c7..fe30ce1 100644 --- a/MareSynchronos/UI/DownloadUi.cs +++ b/MareSynchronos/UI/DownloadUi.cs @@ -101,7 +101,7 @@ public class DownloadUi : Window, IDisposable if (_apiController.CurrentDownloads.Any()) { - var currentDownloads = _apiController.CurrentDownloads.ToList(); + var currentDownloads = _apiController.CurrentDownloads.SelectMany(k => k.Value).ToList(); var multBase = currentDownloads.Any() ? 0 : 2; var doneDownloads = currentDownloads.Count(c => c.IsTransferred); var totalDownloads = currentDownloads.Count; diff --git a/MareSynchronos/UI/SettingsUi.cs b/MareSynchronos/UI/SettingsUi.cs index bc22638..c5e4738 100644 --- a/MareSynchronos/UI/SettingsUi.cs +++ b/MareSynchronos/UI/SettingsUi.cs @@ -518,7 +518,7 @@ namespace MareSynchronos.UI { ImGui.TableSetupColumn( $"Uploads ({UiShared.ByteToString(_apiController.CurrentUploads.Sum(a => a.Transferred))} / {UiShared.ByteToString(_apiController.CurrentUploads.Sum(a => a.Total))})"); - ImGui.TableSetupColumn($"Downloads ({UiShared.ByteToString(_apiController.CurrentDownloads.Sum(a => a.Transferred))} / {UiShared.ByteToString(_apiController.CurrentDownloads.Sum(a => a.Total))})"); + ImGui.TableSetupColumn($"Downloads ({UiShared.ByteToString(_apiController.CurrentDownloads.SelectMany(k => k.Value).ToList().Sum(a => a.Transferred))} / {UiShared.ByteToString(_apiController.CurrentDownloads.SelectMany(k => k.Value).ToList().Sum(a => a.Total))})"); ImGui.TableHeadersRow(); @@ -553,7 +553,7 @@ namespace MareSynchronos.UI ImGui.TableSetupColumn("Downloaded"); ImGui.TableSetupColumn("Size"); ImGui.TableHeadersRow(); - foreach (var transfer in _apiController.CurrentDownloads.ToArray()) + foreach (var transfer in _apiController.CurrentDownloads.SelectMany(k => k.Value).ToArray()) { var color = UiShared.UploadColor((transfer.Transferred, transfer.Total)); ImGui.PushStyleColor(ImGuiCol.Text, color); diff --git a/MareSynchronos/WebAPI/ApIController.Functions.Files.cs b/MareSynchronos/WebAPI/ApIController.Functions.Files.cs index ca48849..6524038 100644 --- a/MareSynchronos/WebAPI/ApIController.Functions.Files.cs +++ b/MareSynchronos/WebAPI/ApIController.Functions.Files.cs @@ -16,6 +16,7 @@ namespace MareSynchronos.WebAPI { public partial class ApiController { + private int _downloadId = 0; public void CancelUpload() { if (_uploadCancellationTokenSource != null) @@ -32,7 +33,7 @@ namespace MareSynchronos.WebAPI await _fileHub!.SendAsync(FilesHubAPI.SendDeleteAllFiles); } - private async Task DownloadFile(string hash, CancellationToken ct) + private async Task DownloadFile(int downloadId, string hash, CancellationToken ct) { var reader = _fileHub!.StreamAsync(FilesHubAPI.StreamDownloadFileAsync, hash, ct); string fileName = Path.GetTempFileName(); @@ -40,51 +41,44 @@ namespace MareSynchronos.WebAPI await foreach (var data in reader.WithCancellation(ct)) { //Logger.Debug("Getting chunk of " + hash); - CurrentDownloads.Single(f => f.Hash == hash).Transferred += data.Length; + CurrentDownloads[downloadId].Single(f => f.Hash == hash).Transferred += data.Length; await fs.WriteAsync(data, ct); } return fileName; } - public async Task DownloadFiles(List fileReplacementDto, CancellationToken ct) + public int GetDownloadId() => _downloadId++; + + public async Task DownloadFiles(int currentDownloadId, List fileReplacementDto, CancellationToken ct) { - Logger.Debug("Downloading files"); - List fileTransferList = new List(); - List downloadFiles = new List(); + Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")"); + + List downloadFileInfoFromService = new List(); foreach (var file in fileReplacementDto) { - downloadFiles.Add(await _fileHub!.InvokeAsync(FilesHubAPI.InvokeGetFileSize, file.Hash, ct)); + downloadFileInfoFromService.Add(await _fileHub!.InvokeAsync(FilesHubAPI.InvokeGetFileSize, file.Hash, ct)); } - downloadFiles = downloadFiles.Distinct().ToList(); + CurrentDownloads[currentDownloadId] = downloadFileInfoFromService.Distinct().Select(d => new DownloadFileTransfer(d)) + .Where(d => d.CanBeTransferred).ToList(); - foreach (var dto in downloadFiles) + foreach (var dto in downloadFileInfoFromService.Where(c => c.IsForbidden)) { - var downloadFileTransfer = new DownloadFileTransfer(dto); - if (CurrentDownloads.All(f => f.Hash != downloadFileTransfer.Hash)) + if (ForbiddenTransfers.All(f => f.Hash != dto.Hash)) { - CurrentDownloads.Add(downloadFileTransfer); - } - - fileTransferList.Add(downloadFileTransfer); - } - - foreach (var file in CurrentDownloads.Where(c => c.IsForbidden)) - { - if (ForbiddenTransfers.All(f => f.Hash != file.Hash)) - { - ForbiddenTransfers.Add(file); + ForbiddenTransfers.Add(new DownloadFileTransfer(dto)); } } - foreach (var file in fileTransferList.Where(f => f.CanBeTransferred)) + foreach (var file in CurrentDownloads[currentDownloadId].Where(f => f.CanBeTransferred)) { var hash = file.Hash; - var tempFile = await DownloadFile(hash, ct); + var tempFile = await DownloadFile(currentDownloadId, hash, ct); if (ct.IsCancellationRequested) { File.Delete(tempFile); - CurrentDownloads.RemoveAll(d => fileReplacementDto.Any(f => f.Hash == d.Hash)); + Logger.Verbose("Detected cancellation, removing " + currentDownloadId); + CurrentDownloads.Remove(currentDownloadId); break; } @@ -112,18 +106,16 @@ namespace MareSynchronos.WebAPI { await using (var db = new FileCacheContext()) { - allFilesInDb = fileTransferList.Where(c => c.CanBeTransferred).All(h => db.FileCaches.Any(f => f.Hash == h.Hash)); + allFilesInDb = CurrentDownloads[currentDownloadId] + .Where(c => c.CanBeTransferred) + .All(h => db.FileCaches.Any(f => f.Hash == h.Hash)); } await Task.Delay(250, ct); } - if (ct.IsCancellationRequested) - { - CurrentDownloads.RemoveAll(d => fileReplacementDto.Any(f => f.Hash == d.Hash)); - } - - CurrentDownloads.RemoveAll(d => d.Transferred == d.Total || !d.CanBeTransferred); + Logger.Verbose("Download complete, removing " + currentDownloadId); + CurrentDownloads.Remove(currentDownloadId); } public async Task PushCharacterData(CharacterCacheDto character, List visibleCharacterIds) @@ -244,6 +236,11 @@ namespace MareSynchronos.WebAPI await _fileHub!.SendAsync(FilesHubAPI.SendUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken); } + + public void CancelDownload(int downloadId) + { + CurrentDownloads.Remove(downloadId); + } } } diff --git a/MareSynchronos/WebAPI/ApiController.Connectivity.cs b/MareSynchronos/WebAPI/ApiController.Connectivity.cs index dc1ad69..e56222f 100644 --- a/MareSynchronos/WebAPI/ApiController.Connectivity.cs +++ b/MareSynchronos/WebAPI/ApiController.Connectivity.cs @@ -96,7 +96,7 @@ namespace MareSynchronos.WebAPI public event SimpleStringDelegate? UnpairedFromOther; - public List CurrentDownloads { get; } = new(); + public Dictionary> CurrentDownloads { get; } = new(); public List CurrentUploads { get; } = new();