handle download cancellation better

This commit is contained in:
Stanley Dimant
2022-07-10 21:51:42 +02:00
parent 98c1802d63
commit 2307b43c65
7 changed files with 47 additions and 42 deletions

View File

@@ -107,18 +107,20 @@ public class CachedPlayer
_downloadCancellationTokenSource?.Cancel(); _downloadCancellationTokenSource?.Cancel();
_downloadCancellationTokenSource = new CancellationTokenSource(); _downloadCancellationTokenSource = new CancellationTokenSource();
var downloadToken = _downloadCancellationTokenSource.Token; var downloadToken = _downloadCancellationTokenSource.Token;
var downloadId = _apiController.GetDownloadId();
Task.Run(async () => Task.Run(async () =>
{ {
List<FileReplacementDto> toDownloadReplacements; List<FileReplacementDto> toDownloadReplacements;
Dictionary<string, string> moddedPaths; Dictionary<string, string> 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); Logger.Debug("Downloading missing files for player " + PlayerName);
await _apiController.DownloadFiles(toDownloadReplacements, downloadToken); await _apiController.DownloadFiles(downloadId, toDownloadReplacements, downloadToken);
if (downloadToken.IsCancellationRequested) if (downloadToken.IsCancellationRequested)
{ {
Logger.Verbose("Detected cancellation");
return; return;
} }
@@ -129,7 +131,13 @@ public class CachedPlayer
} }
ApplyCharacterData(_cache[_lastAppliedEquipmentHash], moddedPaths); ApplyCharacterData(_cache[_lastAppliedEquipmentHash], moddedPaths);
}, downloadToken); }, downloadToken).ContinueWith(task =>
{
if (!task.IsCanceled) return;
Logger.Debug("Download Task was cancelled");
_apiController.CancelDownload(downloadId);
});
} }
private List<FileReplacementDto> TryCalculateModdedDictionary(CharacterCacheDto cache, private List<FileReplacementDto> TryCalculateModdedDictionary(CharacterCacheDto cache,

View File

@@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<Authors></Authors> <Authors></Authors>
<Company></Company> <Company></Company>
<Version>0.1.8.0</Version> <Version>0.1.9.0</Version>
<Description></Description> <Description></Description>
<Copyright></Copyright> <Copyright></Copyright>
<PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl> <PackageProjectUrl>https://github.com/Penumbra-Sync/client</PackageProjectUrl>

View File

@@ -367,7 +367,7 @@ namespace MareSynchronos.UI
ImGui.Text("No uploads in progress"); 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.PushFont(UiBuilder.IconFont);
ImGui.Text(FontAwesomeIcon.Download.ToIconString()); ImGui.Text(FontAwesomeIcon.Download.ToIconString());
ImGui.PopFont(); ImGui.PopFont();

View File

@@ -101,7 +101,7 @@ public class DownloadUi : Window, IDisposable
if (_apiController.CurrentDownloads.Any()) 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 multBase = currentDownloads.Any() ? 0 : 2;
var doneDownloads = currentDownloads.Count(c => c.IsTransferred); var doneDownloads = currentDownloads.Count(c => c.IsTransferred);
var totalDownloads = currentDownloads.Count; var totalDownloads = currentDownloads.Count;

View File

@@ -518,7 +518,7 @@ namespace MareSynchronos.UI
{ {
ImGui.TableSetupColumn( ImGui.TableSetupColumn(
$"Uploads ({UiShared.ByteToString(_apiController.CurrentUploads.Sum(a => a.Transferred))} / {UiShared.ByteToString(_apiController.CurrentUploads.Sum(a => a.Total))})"); $"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(); ImGui.TableHeadersRow();
@@ -553,7 +553,7 @@ namespace MareSynchronos.UI
ImGui.TableSetupColumn("Downloaded"); ImGui.TableSetupColumn("Downloaded");
ImGui.TableSetupColumn("Size"); ImGui.TableSetupColumn("Size");
ImGui.TableHeadersRow(); 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)); var color = UiShared.UploadColor((transfer.Transferred, transfer.Total));
ImGui.PushStyleColor(ImGuiCol.Text, color); ImGui.PushStyleColor(ImGuiCol.Text, color);

View File

@@ -16,6 +16,7 @@ namespace MareSynchronos.WebAPI
{ {
public partial class ApiController public partial class ApiController
{ {
private int _downloadId = 0;
public void CancelUpload() public void CancelUpload()
{ {
if (_uploadCancellationTokenSource != null) if (_uploadCancellationTokenSource != null)
@@ -32,7 +33,7 @@ namespace MareSynchronos.WebAPI
await _fileHub!.SendAsync(FilesHubAPI.SendDeleteAllFiles); await _fileHub!.SendAsync(FilesHubAPI.SendDeleteAllFiles);
} }
private async Task<string> DownloadFile(string hash, CancellationToken ct) private async Task<string> DownloadFile(int downloadId, string hash, CancellationToken ct)
{ {
var reader = _fileHub!.StreamAsync<byte[]>(FilesHubAPI.StreamDownloadFileAsync, hash, ct); var reader = _fileHub!.StreamAsync<byte[]>(FilesHubAPI.StreamDownloadFileAsync, hash, ct);
string fileName = Path.GetTempFileName(); string fileName = Path.GetTempFileName();
@@ -40,51 +41,44 @@ namespace MareSynchronos.WebAPI
await foreach (var data in reader.WithCancellation(ct)) await foreach (var data in reader.WithCancellation(ct))
{ {
//Logger.Debug("Getting chunk of " + hash); //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); await fs.WriteAsync(data, ct);
} }
return fileName; return fileName;
} }
public async Task DownloadFiles(List<FileReplacementDto> fileReplacementDto, CancellationToken ct) public int GetDownloadId() => _downloadId++;
public async Task DownloadFiles(int currentDownloadId, List<FileReplacementDto> fileReplacementDto, CancellationToken ct)
{ {
Logger.Debug("Downloading files"); Logger.Debug("Downloading files (Download ID " + currentDownloadId + ")");
List<FileTransfer> fileTransferList = new List<FileTransfer>();
List<DownloadFileDto> downloadFiles = new List<DownloadFileDto>(); List<DownloadFileDto> downloadFileInfoFromService = new List<DownloadFileDto>();
foreach (var file in fileReplacementDto) foreach (var file in fileReplacementDto)
{ {
downloadFiles.Add(await _fileHub!.InvokeAsync<DownloadFileDto>(FilesHubAPI.InvokeGetFileSize, file.Hash, ct)); downloadFileInfoFromService.Add(await _fileHub!.InvokeAsync<DownloadFileDto>(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 (ForbiddenTransfers.All(f => f.Hash != dto.Hash))
if (CurrentDownloads.All(f => f.Hash != downloadFileTransfer.Hash))
{ {
CurrentDownloads.Add(downloadFileTransfer); ForbiddenTransfers.Add(new DownloadFileTransfer(dto));
}
fileTransferList.Add(downloadFileTransfer);
}
foreach (var file in CurrentDownloads.Where(c => c.IsForbidden))
{
if (ForbiddenTransfers.All(f => f.Hash != file.Hash))
{
ForbiddenTransfers.Add(file);
} }
} }
foreach (var file in fileTransferList.Where(f => f.CanBeTransferred)) foreach (var file in CurrentDownloads[currentDownloadId].Where(f => f.CanBeTransferred))
{ {
var hash = file.Hash; var hash = file.Hash;
var tempFile = await DownloadFile(hash, ct); var tempFile = await DownloadFile(currentDownloadId, hash, ct);
if (ct.IsCancellationRequested) if (ct.IsCancellationRequested)
{ {
File.Delete(tempFile); File.Delete(tempFile);
CurrentDownloads.RemoveAll(d => fileReplacementDto.Any(f => f.Hash == d.Hash)); Logger.Verbose("Detected cancellation, removing " + currentDownloadId);
CurrentDownloads.Remove(currentDownloadId);
break; break;
} }
@@ -112,18 +106,16 @@ namespace MareSynchronos.WebAPI
{ {
await using (var db = new FileCacheContext()) 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); await Task.Delay(250, ct);
} }
if (ct.IsCancellationRequested) Logger.Verbose("Download complete, removing " + currentDownloadId);
{ CurrentDownloads.Remove(currentDownloadId);
CurrentDownloads.RemoveAll(d => fileReplacementDto.Any(f => f.Hash == d.Hash));
}
CurrentDownloads.RemoveAll(d => d.Transferred == d.Total || !d.CanBeTransferred);
} }
public async Task PushCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds) public async Task PushCharacterData(CharacterCacheDto character, List<string> visibleCharacterIds)
@@ -244,6 +236,11 @@ namespace MareSynchronos.WebAPI
await _fileHub!.SendAsync(FilesHubAPI.SendUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken); await _fileHub!.SendAsync(FilesHubAPI.SendUploadFileStreamAsync, fileHash, AsyncFileData(uploadToken), uploadToken);
} }
public void CancelDownload(int downloadId)
{
CurrentDownloads.Remove(downloadId);
}
} }
} }

View File

@@ -96,7 +96,7 @@ namespace MareSynchronos.WebAPI
public event SimpleStringDelegate? UnpairedFromOther; public event SimpleStringDelegate? UnpairedFromOther;
public List<FileTransfer> CurrentDownloads { get; } = new(); public Dictionary<int, List<DownloadFileTransfer>> CurrentDownloads { get; } = new();
public List<FileTransfer> CurrentUploads { get; } = new(); public List<FileTransfer> CurrentUploads { get; } = new();