下载修改

dev2.0
陈伟 2025-04-12 13:23:12 +08:00
parent d5ad1ebf9f
commit cfe2ccdf85
3 changed files with 74 additions and 143 deletions

View File

@ -1,7 +1,9 @@
using System.Windows;
using System.Configuration;
using System.Windows;
using System.Windows.Input;
using HeBianGu.Base.WpfBase;
using Hopetry.Models;
using Hopetry.Provider;
using SqlSugar;
namespace Hopetry.Services;
@ -30,7 +32,8 @@ public class MinioDownloadTask : INotifyPropertyChanged
private ManualResetEventSlim _pauseEvent = new(true);
// 任务属性绑定到UI
[SugarColumn(ColumnName = "task_id")] public int TaskId { get; set; }
[SugarColumn(ColumnName = "task_id", IsPrimaryKey = true, IsIdentity = true)]
public int TaskId { get; set; }
[SugarColumn(ColumnName = "file_name")]
public string FileName { get; set; }
@ -50,31 +53,30 @@ public class MinioDownloadTask : INotifyPropertyChanged
[SugarColumn(ColumnName = "file_path")]
public string FilePath { get; set; }
[SugarColumn(ColumnName = "status")]
public string Status { get; private set; } = "等待中";
[SugarColumn(ColumnName = "status")] public string Status { get; private set; } = "等待中";
[SugarColumn(IsIgnore = true)]
public string Progress
{
get { return TotalSize == 0 ? "0%" : $"{(Downloaded * 100 / TotalSize):0.0}%"; }
}
// 命令
public ICommand PauseCommand { get; }
public ICommand CancelCommand { get; }
[SugarColumn(IsIgnore = true)] public ICommand PauseCommand { get; }
[SugarColumn(IsIgnore = true)] public ICommand CancelCommand { get; }
public MinioDownloadTask()
{
PauseCommand = new CustomCommand(OnPause);
CancelCommand = new CustomCommand(OnCancel);
}
public MinioDownloadTask(MinioService minio, string bucket, string objectKey)
{
_minio = minio;
Bucket = bucket;
ObjectKey = objectKey;
TaskId = Interlocked.Increment(ref _globalId);
FileName = Path.GetFileName(objectKey);
FilePath = "f:\\dest";
PauseCommand = new CustomCommand(OnPause);
CancelCommand = new CustomCommand(OnCancel);
}
@ -83,30 +85,35 @@ public class MinioDownloadTask : INotifyPropertyChanged
/// 下载
/// </summary>
/// <param name="savePath"></param>
public async Task StartDownload(string savePath)
public async Task StartDownload()
{
Status = "初始化";
_cts = new CancellationTokenSource();
var tmpPath = $"{savePath}.download";
try
{
// 断点续传初始化
if (File.Exists(tmpPath))
Downloaded = new FileInfo(tmpPath).Length;
// 获取文件信息
var stat = await _minio.GetObjectMetadata(Bucket, ObjectKey);
TotalSize = stat.Size;
if (Downloaded >= TotalSize)
Status = "下载中";
var updateTask = new MinioDownloadTask
{
Status = "已完成";
return;
TaskId = TaskId,
Status = Status
};
using (var client = SqlSugarConfig.GetSqlSugarScope())
{
await client.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
}
// todo 下载逻辑
Console.WriteLine($"{ObjectKey}文件下载中...");
updateTask.Status = "下载中";
await _minio.DownLoadObject(Bucket, ObjectKey, FilePath, "");
Status = "已完成";
updateTask.Status = Status;
using (var client = SqlSugarConfig.GetSqlSugarScope())
{
await client.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
}
Console.WriteLine($"文件{ObjectKey}下载完成");
}
catch (OperationCanceledException)
{
@ -150,6 +157,4 @@ public class MinioDownloadTask : INotifyPropertyChanged
protected void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private static int _globalId;
}

View File

@ -16,6 +16,7 @@
<Button Grid.Column="0"
Margin="10,0"
Content="全部暂停"
Command="{Binding DownViewModel.AddTaskCommand}"
Style="{DynamicResource {x:Static h:ButtonKeys.BorderBrushTransparent}}" />
<Button Grid.Column="1" Content="全部取消"
Style="{DynamicResource {x:Static h:ButtonKeys.BorderBrushTransparent}}" />

View File

@ -25,6 +25,10 @@ public class DownViewModel : MvcViewModelBase
private SemaphoreSlim _concurrencySemaphore;
private CancellationTokenSource _processingCts = new();
public int count { get; set; }
private SemaphoreSlim _semaphore;
private readonly ReaderWriterLockSlim _lock = new();
/// <summary>
/// 全部任务动态标题
@ -66,7 +70,7 @@ public class DownViewModel : MvcViewModelBase
}
// 绑定属性
public ObservableCollection<MinioDownloadTask> AllTasks { get;set; } = new();
public ObservableCollection<MinioDownloadTask> AllTasks { get; set; } = new();
public ICollectionView RunningTasksView { get; set; }
@ -82,7 +86,7 @@ public class DownViewModel : MvcViewModelBase
if (_maxConcurrent == value) return;
_maxConcurrent = value;
AdjustConcurrency();
//AdjustConcurrency();
RaisePropertyChanged();
}
}
@ -100,37 +104,25 @@ public class DownViewModel : MvcViewModelBase
}
// 命令
public ICommand AddTaskCommand { get; }
public ICommand AddTaskCommand { get; set; }
public ICommand ClearFinishedCommand { get; }
private ObservableCollection<DownItem> _downItems;
public ObservableCollection<DownItem> DownItems
{
get => _downItems;
set
{
_downItems = value;
RaisePropertyChanged();
}
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="minioService"></param>
public DownViewModel(MinioService minioService)
public DownViewModel(MinioService minioService, SemaphoreSlim semaphore)
{
_minioService = minioService;
_semaphore = semaphore;
Console.WriteLine("初始化DownViewModel");
var client = SqlSugarConfig.GetSqlSugarScope();
using var client = SqlSugarConfig.GetSqlSugarScope();
var data = client.Ado.SqlQuery<MinioDownloadTask>($"select * from download_task");
//DownItems = new ObservableCollection<DownItem>(data);
AllTasks = new ObservableCollection<MinioDownloadTask>(data);
AllTaskHeader = $"全部({AllTasks.Count}";
Console.WriteLine(JsonConvert.SerializeObject(data));
//Console.WriteLine(JsonConvert.SerializeObject(data));
OpenDownItemFolder = new RelayCommand<MinioDownloadTask>(DoOpenDownItemFolder);
// 命令初始化
// AddTaskCommand = new RelayCommand(AddTask, CanAddTask);
@ -172,21 +164,28 @@ public class DownViewModel : MvcViewModelBase
// todo 删除已完成的下载记录
});
// 启动任务处理线程
_semaphore = new SemaphoreSlim(_maxConcurrent);
// 启动任务处理线程
_concurrencySemaphore = new SemaphoreSlim(_maxConcurrent);
new Thread(ProcessTasksLoop) { IsBackground = true }.Start();
AddTaskCommand = new ActionCommand(AddTask);
}
private void ProcessTasksLoop()
{
while (!_processingCts.IsCancellationRequested)
{
_semaphore.WaitAsync();
// 按当前并发数启动任务
for (int i = 0; i < _maxConcurrent; i++)
{
if (_taskQueue.TryDequeue(out var task))
{
_ = ExecuteTaskAsync(task);
// 启动新线程执行下载任务
_ = Task.Run(() => ExecuteTaskAsync(task));
}
}
@ -196,30 +195,25 @@ public class DownViewModel : MvcViewModelBase
private void AddTask()
{
var task = new MinioDownloadTask(_minioService, NewBucket, NewObjectName);
string[] objectKeys = { "demo/06.mp4", "demo/07.mp4", "demo/08.mp4", "demo/10.mp4" };
var task = new MinioDownloadTask(_minioService, "demo", objectKeys[count++]);
using var client = SqlSugarConfig.GetSqlSugarScope();
client.Insertable(task).ExecuteCommandIdentityIntoEntity();
AllTasks.Add(task);
_taskQueue.Enqueue(task);
RaisePropertyChanged(nameof(NewBucket));
RaisePropertyChanged(nameof(NewObjectName));
}
private bool CanAddTask() => !string.IsNullOrEmpty(NewBucket) && !string.IsNullOrEmpty(NewObjectName);
private async Task ExecuteTaskAsync(MinioDownloadTask task)
{
RunningTasks++;
try
{
// todo 配置下载路径
var savePath = Path.Combine(task.FileName);
await task.StartDownload(savePath);
await task.StartDownload();
// todo 任务完成下载
}
finally
{
RunningTasks--;
// 任务完成后自动处理下一个
if (!_processingCts.IsCancellationRequested)
ProcessTasksLoop();
_semaphore.Release();
}
}
@ -239,37 +233,24 @@ public class DownViewModel : MvcViewModelBase
}
}
// 绑定属性
private string _newBucket;
public string NewBucket
{
get => _newBucket;
set
{
_newBucket = value;
RaisePropertyChanged();
}
}
private string _newObjectName;
public string NewObjectName
{
get => _newObjectName;
set
{
_newObjectName = value;
RaisePropertyChanged();
}
}
public void DoOpenDownItemFolder(MinioDownloadTask para)
{
Console.WriteLine($"点击了什么值:{JsonConvert.SerializeObject(para)}");
Console.WriteLine($"点击item值{JsonConvert.SerializeObject(para)}");
Process.Start("explorer.exe", para.FilePath);
}
public void DoCancelDownItem(MinioDownloadTask item)
{
Console.WriteLine("取消下载");
// todo 实现取消下载
}
public void DoPauseDownItem(MinioDownloadTask item)
{
Console.WriteLine("暂停下载");
// todo 实现暂停下载
}
protected override void Init()
{
}
@ -277,60 +258,4 @@ public class DownViewModel : MvcViewModelBase
protected override void Loaded(string args)
{
}
[SugarTable("f_down_item")]
public class DownItem
{
public DownItem()
{
}
[SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
public long Id { get; set; }
// 进度 已下载 多久下载完成 下载速度
[SugarColumn(IsIgnore = true)] public int ProgressInt { get; set; }
/// <summary>
/// object key
/// </summary>
[SugarColumn(ColumnName = "object_key")]
public string ObjectKey { get; set; }
/// <summary>
/// 文件名称
/// </summary>
[SugarColumn(ColumnName = "file_name")]
public string FileName { get; set; }
/// <summary>
/// 文件类型
/// </summary>
[SugarColumn(ColumnName = "file_type")]
public string FileType { get; set; }
/// <summary>
/// 文件大小
/// </summary>
[SugarColumn(ColumnName = "file_size")]
public long FileSize { get; set; }
/// <summary>
/// 速度 100kb/s
/// </summary>
[SugarColumn(IsIgnore = true)]
public long Speed { get; set; }
/// <summary>
/// 本地保存路径
/// </summary>
[SugarColumn(ColumnName = "file_path")]
public string FilePath { get; set; }
/// <summary>
/// 文件的ETag
/// </summary>
[SugarColumn(ColumnName = "file_etag")]
public string FileETag { get; set; }
}
}