handle download cancellation better
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user