下载修改
parent
d5ad1ebf9f
commit
cfe2ccdf85
|
|
@ -1,7 +1,9 @@
|
||||||
using System.Windows;
|
using System.Configuration;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using HeBianGu.Base.WpfBase;
|
using HeBianGu.Base.WpfBase;
|
||||||
using Hopetry.Models;
|
using Hopetry.Models;
|
||||||
|
using Hopetry.Provider;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
|
|
||||||
namespace Hopetry.Services;
|
namespace Hopetry.Services;
|
||||||
|
|
@ -30,7 +32,8 @@ public class MinioDownloadTask : INotifyPropertyChanged
|
||||||
private ManualResetEventSlim _pauseEvent = new(true);
|
private ManualResetEventSlim _pauseEvent = new(true);
|
||||||
|
|
||||||
// 任务属性(绑定到UI)
|
// 任务属性(绑定到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")]
|
[SugarColumn(ColumnName = "file_name")]
|
||||||
public string FileName { get; set; }
|
public string FileName { get; set; }
|
||||||
|
|
@ -50,31 +53,30 @@ public class MinioDownloadTask : INotifyPropertyChanged
|
||||||
[SugarColumn(ColumnName = "file_path")]
|
[SugarColumn(ColumnName = "file_path")]
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
|
|
||||||
[SugarColumn(ColumnName = "status")]
|
[SugarColumn(ColumnName = "status")] public string Status { get; private set; } = "等待中";
|
||||||
public string Status { get; private set; } = "等待中";
|
|
||||||
|
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
public string Progress
|
public string Progress
|
||||||
{
|
{
|
||||||
get { return TotalSize == 0 ? "0%" : $"{(Downloaded * 100 / TotalSize):0.0}%"; }
|
get { return TotalSize == 0 ? "0%" : $"{(Downloaded * 100 / TotalSize):0.0}%"; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 命令
|
[SugarColumn(IsIgnore = true)] public ICommand PauseCommand { get; }
|
||||||
public ICommand PauseCommand { get; }
|
[SugarColumn(IsIgnore = true)] public ICommand CancelCommand { get; }
|
||||||
public ICommand CancelCommand { get; }
|
|
||||||
|
|
||||||
public MinioDownloadTask()
|
public MinioDownloadTask()
|
||||||
{
|
{
|
||||||
PauseCommand = new CustomCommand(OnPause);
|
PauseCommand = new CustomCommand(OnPause);
|
||||||
CancelCommand = new CustomCommand(OnCancel);
|
CancelCommand = new CustomCommand(OnCancel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MinioDownloadTask(MinioService minio, string bucket, string objectKey)
|
public MinioDownloadTask(MinioService minio, string bucket, string objectKey)
|
||||||
{
|
{
|
||||||
_minio = minio;
|
_minio = minio;
|
||||||
Bucket = bucket;
|
Bucket = bucket;
|
||||||
ObjectKey = objectKey;
|
ObjectKey = objectKey;
|
||||||
TaskId = Interlocked.Increment(ref _globalId);
|
|
||||||
FileName = Path.GetFileName(objectKey);
|
FileName = Path.GetFileName(objectKey);
|
||||||
|
FilePath = "f:\\dest";
|
||||||
PauseCommand = new CustomCommand(OnPause);
|
PauseCommand = new CustomCommand(OnPause);
|
||||||
CancelCommand = new CustomCommand(OnCancel);
|
CancelCommand = new CustomCommand(OnCancel);
|
||||||
}
|
}
|
||||||
|
|
@ -83,30 +85,35 @@ public class MinioDownloadTask : INotifyPropertyChanged
|
||||||
/// 下载
|
/// 下载
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="savePath"></param>
|
/// <param name="savePath"></param>
|
||||||
public async Task StartDownload(string savePath)
|
public async Task StartDownload()
|
||||||
{
|
{
|
||||||
Status = "初始化";
|
|
||||||
_cts = new CancellationTokenSource();
|
_cts = new CancellationTokenSource();
|
||||||
var tmpPath = $"{savePath}.download";
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 断点续传初始化
|
Status = "下载中";
|
||||||
if (File.Exists(tmpPath))
|
var updateTask = new MinioDownloadTask
|
||||||
Downloaded = new FileInfo(tmpPath).Length;
|
|
||||||
|
|
||||||
// 获取文件信息
|
|
||||||
var stat = await _minio.GetObjectMetadata(Bucket, ObjectKey);
|
|
||||||
TotalSize = stat.Size;
|
|
||||||
|
|
||||||
if (Downloaded >= TotalSize)
|
|
||||||
{
|
{
|
||||||
Status = "已完成";
|
TaskId = TaskId,
|
||||||
return;
|
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 = "已完成";
|
Status = "已完成";
|
||||||
|
updateTask.Status = Status;
|
||||||
|
using (var client = SqlSugarConfig.GetSqlSugarScope())
|
||||||
|
{
|
||||||
|
await client.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"文件{ObjectKey}下载完成");
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
|
@ -150,6 +157,4 @@ public class MinioDownloadTask : INotifyPropertyChanged
|
||||||
|
|
||||||
protected void OnPropertyChanged(string propertyName)
|
protected void OnPropertyChanged(string propertyName)
|
||||||
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
|
||||||
private static int _globalId;
|
|
||||||
}
|
}
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
Margin="10,0"
|
Margin="10,0"
|
||||||
Content="全部暂停"
|
Content="全部暂停"
|
||||||
|
Command="{Binding DownViewModel.AddTaskCommand}"
|
||||||
Style="{DynamicResource {x:Static h:ButtonKeys.BorderBrushTransparent}}" />
|
Style="{DynamicResource {x:Static h:ButtonKeys.BorderBrushTransparent}}" />
|
||||||
<Button Grid.Column="1" Content="全部取消"
|
<Button Grid.Column="1" Content="全部取消"
|
||||||
Style="{DynamicResource {x:Static h:ButtonKeys.BorderBrushTransparent}}" />
|
Style="{DynamicResource {x:Static h:ButtonKeys.BorderBrushTransparent}}" />
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,16 @@ namespace Hopetry.ViewModel.Send;
|
||||||
public class DownViewModel : MvcViewModelBase
|
public class DownViewModel : MvcViewModelBase
|
||||||
{
|
{
|
||||||
private readonly MinioService _minioService;
|
private readonly MinioService _minioService;
|
||||||
|
|
||||||
public RelayCommand<MinioDownloadTask> OpenDownItemFolder { get; set; }
|
public RelayCommand<MinioDownloadTask> OpenDownItemFolder { get; set; }
|
||||||
private readonly ConcurrentQueue<MinioDownloadTask> _taskQueue = new();
|
private readonly ConcurrentQueue<MinioDownloadTask> _taskQueue = new();
|
||||||
private SemaphoreSlim _concurrencySemaphore;
|
private SemaphoreSlim _concurrencySemaphore;
|
||||||
|
|
||||||
private CancellationTokenSource _processingCts = new();
|
private CancellationTokenSource _processingCts = new();
|
||||||
|
public int count { get; set; }
|
||||||
|
|
||||||
|
private SemaphoreSlim _semaphore;
|
||||||
|
private readonly ReaderWriterLockSlim _lock = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 全部任务动态标题
|
/// 全部任务动态标题
|
||||||
|
|
@ -66,8 +70,8 @@ public class DownViewModel : MvcViewModelBase
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绑定属性
|
// 绑定属性
|
||||||
public ObservableCollection<MinioDownloadTask> AllTasks { get;set; } = new();
|
public ObservableCollection<MinioDownloadTask> AllTasks { get; set; } = new();
|
||||||
|
|
||||||
|
|
||||||
public ICollectionView RunningTasksView { get; set; }
|
public ICollectionView RunningTasksView { get; set; }
|
||||||
public ICollectionView FinishedTasksView { get; set; }
|
public ICollectionView FinishedTasksView { get; set; }
|
||||||
|
|
@ -82,7 +86,7 @@ public class DownViewModel : MvcViewModelBase
|
||||||
if (_maxConcurrent == value) return;
|
if (_maxConcurrent == value) return;
|
||||||
|
|
||||||
_maxConcurrent = value;
|
_maxConcurrent = value;
|
||||||
AdjustConcurrency();
|
//AdjustConcurrency();
|
||||||
RaisePropertyChanged();
|
RaisePropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -100,37 +104,25 @@ public class DownViewModel : MvcViewModelBase
|
||||||
}
|
}
|
||||||
|
|
||||||
// 命令
|
// 命令
|
||||||
public ICommand AddTaskCommand { get; }
|
public ICommand AddTaskCommand { get; set; }
|
||||||
public ICommand ClearFinishedCommand { get; }
|
public ICommand ClearFinishedCommand { get; }
|
||||||
|
|
||||||
|
|
||||||
private ObservableCollection<DownItem> _downItems;
|
|
||||||
|
|
||||||
|
|
||||||
public ObservableCollection<DownItem> DownItems
|
|
||||||
{
|
|
||||||
get => _downItems;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_downItems = value;
|
|
||||||
RaisePropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 构造函数
|
/// 构造函数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="minioService"></param>
|
/// <param name="minioService"></param>
|
||||||
public DownViewModel(MinioService minioService)
|
public DownViewModel(MinioService minioService, SemaphoreSlim semaphore)
|
||||||
{
|
{
|
||||||
_minioService = minioService;
|
_minioService = minioService;
|
||||||
|
_semaphore = semaphore;
|
||||||
Console.WriteLine("初始化DownViewModel");
|
Console.WriteLine("初始化DownViewModel");
|
||||||
var client = SqlSugarConfig.GetSqlSugarScope();
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
||||||
var data = client.Ado.SqlQuery<MinioDownloadTask>($"select * from download_task");
|
var data = client.Ado.SqlQuery<MinioDownloadTask>($"select * from download_task");
|
||||||
//DownItems = new ObservableCollection<DownItem>(data);
|
//DownItems = new ObservableCollection<DownItem>(data);
|
||||||
AllTasks = new ObservableCollection<MinioDownloadTask>(data);
|
AllTasks = new ObservableCollection<MinioDownloadTask>(data);
|
||||||
AllTaskHeader = $"全部({AllTasks.Count})";
|
AllTaskHeader = $"全部({AllTasks.Count})";
|
||||||
Console.WriteLine(JsonConvert.SerializeObject(data));
|
//Console.WriteLine(JsonConvert.SerializeObject(data));
|
||||||
OpenDownItemFolder = new RelayCommand<MinioDownloadTask>(DoOpenDownItemFolder);
|
OpenDownItemFolder = new RelayCommand<MinioDownloadTask>(DoOpenDownItemFolder);
|
||||||
// 命令初始化
|
// 命令初始化
|
||||||
// AddTaskCommand = new RelayCommand(AddTask, CanAddTask);
|
// AddTaskCommand = new RelayCommand(AddTask, CanAddTask);
|
||||||
|
|
@ -166,27 +158,34 @@ public class DownViewModel : MvcViewModelBase
|
||||||
RunningTasksView.Refresh();
|
RunningTasksView.Refresh();
|
||||||
FinishedTasksView.Refresh();
|
FinishedTasksView.Refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
ClearFinishedCommand = new CustomCommand(() =>
|
ClearFinishedCommand = new CustomCommand(() =>
|
||||||
{
|
{
|
||||||
// todo 删除已完成的下载记录
|
// todo 删除已完成的下载记录
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 启动任务处理线程
|
||||||
|
_semaphore = new SemaphoreSlim(_maxConcurrent);
|
||||||
// 启动任务处理线程
|
// 启动任务处理线程
|
||||||
_concurrencySemaphore = new SemaphoreSlim(_maxConcurrent);
|
_concurrencySemaphore = new SemaphoreSlim(_maxConcurrent);
|
||||||
new Thread(ProcessTasksLoop) { IsBackground = true }.Start();
|
new Thread(ProcessTasksLoop) { IsBackground = true }.Start();
|
||||||
|
|
||||||
|
|
||||||
|
AddTaskCommand = new ActionCommand(AddTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessTasksLoop()
|
private void ProcessTasksLoop()
|
||||||
{
|
{
|
||||||
while (!_processingCts.IsCancellationRequested)
|
while (!_processingCts.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
|
_semaphore.WaitAsync();
|
||||||
// 按当前并发数启动任务
|
// 按当前并发数启动任务
|
||||||
for (int i = 0; i < _maxConcurrent; i++)
|
for (int i = 0; i < _maxConcurrent; i++)
|
||||||
{
|
{
|
||||||
if (_taskQueue.TryDequeue(out var task))
|
if (_taskQueue.TryDequeue(out var task))
|
||||||
{
|
{
|
||||||
_ = ExecuteTaskAsync(task);
|
// 启动新线程执行下载任务
|
||||||
|
_ = Task.Run(() => ExecuteTaskAsync(task));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -196,30 +195,25 @@ public class DownViewModel : MvcViewModelBase
|
||||||
|
|
||||||
private void AddTask()
|
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);
|
AllTasks.Add(task);
|
||||||
_taskQueue.Enqueue(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)
|
private async Task ExecuteTaskAsync(MinioDownloadTask task)
|
||||||
{
|
{
|
||||||
RunningTasks++;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// todo 配置下载路径
|
await task.StartDownload();
|
||||||
var savePath = Path.Combine(task.FileName);
|
// todo 任务完成下载
|
||||||
await task.StartDownload(savePath);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
RunningTasks--;
|
_semaphore.Release();
|
||||||
// 任务完成后自动处理下一个
|
|
||||||
if (!_processingCts.IsCancellationRequested)
|
|
||||||
ProcessTasksLoop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -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)
|
public void DoOpenDownItemFolder(MinioDownloadTask para)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"点击了什么值:{JsonConvert.SerializeObject(para)}");
|
Console.WriteLine($"点击item值:{JsonConvert.SerializeObject(para)}");
|
||||||
Process.Start("explorer.exe", para.FilePath);
|
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()
|
protected override void Init()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -277,60 +258,4 @@ public class DownViewModel : MvcViewModelBase
|
||||||
protected override void Loaded(string args)
|
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; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue