Initial upload
This commit is contained in:
@@ -4,9 +4,9 @@ using DownloadManager.Services;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace DownloadManager.DownloaderCore;
|
||||
public partial class DownloadManagerService()
|
||||
public partial class DownloadManagerService(HistoryStorageService historyService)
|
||||
{
|
||||
private readonly ConcurrentQueue<DownloadItemData> _queuedDownloadData = new();
|
||||
private ConcurrentQueue<DownloadItemData> _queuedDownloadData = new();
|
||||
private readonly ConcurrentDictionary<Guid, DownloadWorker> _activeWorkers = new();
|
||||
private List<CompletedItemData> _completedDownloadData = new();
|
||||
|
||||
@@ -16,9 +16,9 @@ public partial class DownloadManagerService()
|
||||
public Action<string, string>? OnWorkerFailed;
|
||||
public Action<string>? OnWorkerComplete;
|
||||
|
||||
public async Task LoadDownloadHistory()
|
||||
public void LoadDownloadHistory()
|
||||
{
|
||||
_completedDownloadData = new(await HistoryStorageService.LoadCompletedItemsAsync());
|
||||
_completedDownloadData = new(historyService.LoadCompletedItems());
|
||||
}
|
||||
|
||||
public void AddDownloadItem(DownloadItemData itemData)
|
||||
@@ -36,7 +36,7 @@ public partial class DownloadManagerService()
|
||||
OnQueuedItemChanged?.Invoke();
|
||||
}
|
||||
|
||||
public async Task FindNextDownloadAndStart()
|
||||
public async Task FindNextDownloadAndStartAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -48,31 +48,29 @@ public partial class DownloadManagerService()
|
||||
return;
|
||||
}
|
||||
|
||||
var downloadDataToStart = _queuedDownloadData.Take(workersToStart);
|
||||
var downloadDataToStart = _queuedDownloadData.Take(workersToStart).ToArray();
|
||||
|
||||
foreach (var downloadData in downloadDataToStart)
|
||||
await Parallel.ForEachAsync(downloadDataToStart, new ParallelOptions() { MaxDegreeOfParallelism = SettingService.Current.MaxActiveDownloadCount }, async (downloadData, cts) =>
|
||||
{
|
||||
var worker = new DownloadWorker(downloadData);
|
||||
if (_activeWorkers.TryAdd(downloadData.Id, worker))
|
||||
_activeWorkers.TryAdd(downloadData.Id, worker);
|
||||
_queuedDownloadData.TryDequeue(out _);
|
||||
|
||||
SetupDownloadWorkerCallbacks(worker);
|
||||
|
||||
if (await worker.BuildDownloadRequestAsync())
|
||||
{
|
||||
_queuedDownloadData.TryDequeue(out _);
|
||||
|
||||
SetupDownloadWorkerCallbacks(worker);
|
||||
|
||||
if (await worker.BuildDownloadRequestAsync())
|
||||
{
|
||||
worker.StartDownload();
|
||||
}
|
||||
else
|
||||
{
|
||||
_activeWorkers.Remove(downloadData.Id, out _);
|
||||
await AddCompletedItem(downloadData, DownloadStatus.Failed.ToString(), $"Not able to get file url using {downloadData.UrlGetterName} url getter");
|
||||
await FindNextDownloadAndStart();
|
||||
|
||||
OnWorkerFailed?.Invoke(downloadData.Url, $"Not able to get file url using {downloadData.UrlGetterName} url getter");
|
||||
}
|
||||
await worker.StartAsync();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_activeWorkers.Remove(downloadData.Id, out _);
|
||||
AddCompletedItem(downloadData, DownloadStatus.Failed.ToString(), $"Not able to get file url using {downloadData.UrlGetterName} url getter");
|
||||
await FindNextDownloadAndStartAsync();
|
||||
|
||||
OnWorkerFailed?.Invoke(downloadData.Url, $"Not able to get file url using {downloadData.UrlGetterName} url getter");
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -88,12 +86,12 @@ public partial class DownloadManagerService()
|
||||
OnQueuedItemChanged?.Invoke();
|
||||
};
|
||||
|
||||
worker.OnDownloadFileCompleted = async () =>
|
||||
worker.OnDownloadCompleted = async () =>
|
||||
{
|
||||
_activeWorkers.Remove(worker.DownloadData.Id, out _);
|
||||
|
||||
await AddCompletedItem(worker.DownloadData, worker.DownloadData.Status.ToString(), worker.errorMessage);
|
||||
await FindNextDownloadAndStart();
|
||||
AddCompletedItem(worker.DownloadData, worker.DownloadData.Status.ToString(), worker.errorMessage);
|
||||
await FindNextDownloadAndStartAsync();
|
||||
|
||||
OnActiveWorkerChanged?.Invoke();
|
||||
|
||||
@@ -110,12 +108,14 @@ public partial class DownloadManagerService()
|
||||
{
|
||||
OnAllWorkerCompleted?.Invoke();
|
||||
}
|
||||
|
||||
worker.Dispose();
|
||||
};
|
||||
|
||||
worker.OnDownloadStop = async () =>
|
||||
{
|
||||
_activeWorkers.Remove(worker.DownloadData.Id, out _);
|
||||
await FindNextDownloadAndStart();
|
||||
await FindNextDownloadAndStartAsync();
|
||||
|
||||
OnActiveWorkerChanged?.Invoke();
|
||||
};
|
||||
@@ -128,4 +128,10 @@ public partial class DownloadManagerService()
|
||||
worker.Value.StopDownload();
|
||||
}
|
||||
}
|
||||
|
||||
internal void RemoveTask(DownloadItemData task)
|
||||
{
|
||||
_queuedDownloadData = new(_queuedDownloadData.Where(x => x != task));
|
||||
OnQueuedItemChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
using Downloader;
|
||||
using DownloadManager.Models;
|
||||
using DownloadManager.Services;
|
||||
using LiteDB;
|
||||
|
||||
namespace DownloadManager.DownloaderCore
|
||||
{
|
||||
public partial class DownloadManagerService
|
||||
{
|
||||
private async Task AddCompletedItem(DownloadItemData downloadData, string status, string errorMessage)
|
||||
private void AddCompletedItem(DownloadItemData downloadData, string status, string errorMessage)
|
||||
{
|
||||
var completedItem = new CompletedItemData
|
||||
{
|
||||
@@ -15,16 +15,12 @@ namespace DownloadManager.DownloaderCore
|
||||
SavePath = downloadData.FilePath,
|
||||
FullName = System.IO.Path.Combine(downloadData.FilePath, downloadData.FileName),
|
||||
Status = status,
|
||||
CompletedDate = DateOnly.FromDateTime(DateTime.Now),
|
||||
ErrorMessage = errorMessage == string.Empty ? "No error" : errorMessage
|
||||
};
|
||||
|
||||
_completedDownloadData.Add(completedItem);
|
||||
await SaveCompletedItemsAsync();
|
||||
}
|
||||
|
||||
private async Task SaveCompletedItemsAsync()
|
||||
{
|
||||
await HistoryStorageService.SaveCompletedItemsAsync(_completedDownloadData);
|
||||
historyService.SaveCompletedItem(completedItem);
|
||||
}
|
||||
|
||||
public IEnumerable<DownloadItemData> GetDownloadingTask()
|
||||
@@ -42,31 +38,33 @@ namespace DownloadManager.DownloaderCore
|
||||
return _completedDownloadData;
|
||||
}
|
||||
|
||||
public async Task ClearCompletedTask()
|
||||
public void ClearCompletedTask()
|
||||
{
|
||||
var completedTasks = _completedDownloadData.Where(x => x.Status == DownloadStatus.Completed.ToString()).ToArray();
|
||||
_completedDownloadData.RemoveAll(x => x.Status == DownloadStatus.Completed.ToString());
|
||||
await SaveCompletedItemsAsync();
|
||||
historyService.RemoveCompletedItemList(completedTasks);
|
||||
}
|
||||
|
||||
public async Task ClearFailedTask()
|
||||
public void ClearFailedTask()
|
||||
{
|
||||
var failedTasks = _completedDownloadData.Where(x => x.Status == DownloadStatus.Failed.ToString()).ToArray();
|
||||
_completedDownloadData.RemoveAll(x => x.Status == DownloadStatus.Failed.ToString());
|
||||
await SaveCompletedItemsAsync();
|
||||
historyService.RemoveCompletedItemList(failedTasks);
|
||||
}
|
||||
|
||||
public async Task ClearAllTask()
|
||||
public void ClearAllTask()
|
||||
{
|
||||
_completedDownloadData.Clear();
|
||||
await SaveCompletedItemsAsync();
|
||||
historyService.ClearCompletedItems();
|
||||
}
|
||||
|
||||
public async Task RemoveCompletedTask(CompletedItemData completedItem)
|
||||
public void RemoveCompletedTask(CompletedItemData completedItem)
|
||||
{
|
||||
_completedDownloadData.Remove(completedItem);
|
||||
await SaveCompletedItemsAsync();
|
||||
historyService.RemoveCompletedItem(completedItem);
|
||||
}
|
||||
|
||||
public async Task RetryFailedTask()
|
||||
public void RetryFailedTask()
|
||||
{
|
||||
var failedTasks = _completedDownloadData.Where(x => x.Status == DownloadStatus.Failed.ToString()).ToArray();
|
||||
foreach (var failedTask in failedTasks)
|
||||
@@ -76,7 +74,7 @@ namespace DownloadManager.DownloaderCore
|
||||
_completedDownloadData.Remove(failedTask);
|
||||
}
|
||||
|
||||
await SaveCompletedItemsAsync();
|
||||
historyService.RemoveCompletedItemList(failedTasks);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using System.ComponentModel;
|
||||
using System.IO;
|
||||
|
||||
namespace DownloadManager.DownloaderCore;
|
||||
public class DownloadWorker(DownloadItemData itemData)
|
||||
public class DownloadWorker(DownloadItemData itemData) : IDisposable
|
||||
{
|
||||
private IDownload? _worker;
|
||||
private DownloadItemData _downloadData = itemData;
|
||||
@@ -15,12 +15,9 @@ public class DownloadWorker(DownloadItemData itemData)
|
||||
public string errorMessage = string.Empty;
|
||||
|
||||
public Action? OnDownloadStarted;
|
||||
public Action? OnDownloadFileCompleted;
|
||||
public Action<string>? OnDownloadFailed;
|
||||
public Action? OnDownloadCompleted;
|
||||
public Action? OnDownloadStop;
|
||||
|
||||
private int retryCount = 0;
|
||||
|
||||
public async Task<bool> BuildDownloadRequestAsync()
|
||||
{
|
||||
var urlGetter = UrlGetterUtilities.CreateUrlGetter(_downloadData.UrlGetterName);
|
||||
@@ -39,8 +36,6 @@ public class DownloadWorker(DownloadItemData itemData)
|
||||
_downloadData.FileName = fileUrl.Name;
|
||||
_downloadData.MD5 = fileUrl.MD5;
|
||||
|
||||
retryCount = _downloadData.DownloadConfiguration.MaxTryAgainOnFailover;
|
||||
|
||||
BuildWorker();
|
||||
|
||||
return true;
|
||||
@@ -81,8 +76,6 @@ public class DownloadWorker(DownloadItemData itemData)
|
||||
|
||||
private void DownloadFileCompleted(object? sender, AsyncCompletedEventArgs e)
|
||||
{
|
||||
_worker?.Dispose();
|
||||
|
||||
if (e.Error != null)
|
||||
{
|
||||
_downloadData.Status = DownloadStatus.Failed;
|
||||
@@ -97,8 +90,7 @@ public class DownloadWorker(DownloadItemData itemData)
|
||||
// Check md5
|
||||
if (_downloadData.MD5 != null)
|
||||
{
|
||||
var fileFullName = Path.Combine(_downloadData.FilePath, _downloadData.FileName!);
|
||||
var md5 = MD5Utilities.GetMD5HashFromFile(fileFullName);
|
||||
var md5 = MD5Utilities.GetMD5HashFromFile(_downloadData.FileFullName);
|
||||
if (md5 != _downloadData.MD5)
|
||||
{
|
||||
_downloadData.Status = DownloadStatus.Failed;
|
||||
@@ -108,37 +100,42 @@ public class DownloadWorker(DownloadItemData itemData)
|
||||
}
|
||||
}
|
||||
|
||||
OnDownloadFileCompleted?.Invoke();
|
||||
OnDownloadCompleted?.Invoke();
|
||||
}
|
||||
|
||||
private async Task<bool> RetryDownload()
|
||||
public async Task StartAsync()
|
||||
{
|
||||
if (retryCount > 0)
|
||||
if (_worker == null)
|
||||
{
|
||||
retryCount--;
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
await BuildDownloadRequestAsync();
|
||||
StartDownload();
|
||||
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (File.Exists(_downloadData.FileFullName))
|
||||
{
|
||||
_downloadData.Status = DownloadStatus.Failed;
|
||||
return false;
|
||||
if (SettingService.Current.FileOverwrite)
|
||||
{
|
||||
File.Delete(_downloadData.FileFullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
_downloadData.Status = DownloadStatus.Failed;
|
||||
errorMessage = "File already exists";
|
||||
OnDownloadCompleted?.Invoke();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void StartDownload()
|
||||
{
|
||||
_worker?.StartAsync();
|
||||
await _worker.StartAsync();
|
||||
}
|
||||
|
||||
public void PauseDownload()
|
||||
{
|
||||
_worker?.Pause();
|
||||
if (_worker == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_worker.Pause();
|
||||
OnDownloadStop?.Invoke();
|
||||
}
|
||||
|
||||
@@ -149,7 +146,18 @@ public class DownloadWorker(DownloadItemData itemData)
|
||||
|
||||
public void StopDownload()
|
||||
{
|
||||
_worker?.Stop();
|
||||
if (_worker == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_worker.Stop();
|
||||
OnDownloadStop?.Invoke();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_worker?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user