2025-04-10 13:17:39 +08:00
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.ComponentModel;
|
|
|
|
|
|
using System.Diagnostics;
|
2025-04-14 13:52:04 +08:00
|
|
|
|
using System.Windows;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
using System.Windows.Data;
|
|
|
|
|
|
using System.Windows.Input;
|
2025-04-15 11:04:46 +08:00
|
|
|
|
using System.Windows.Shapes;
|
2025-04-15 14:05:06 +08:00
|
|
|
|
using System.Windows.Threading;
|
2025-04-08 16:22:25 +08:00
|
|
|
|
using HeBianGu.Base.WpfBase;
|
|
|
|
|
|
using HeBianGu.Service.Mvc;
|
|
|
|
|
|
using Hopetry.Models;
|
|
|
|
|
|
using Hopetry.Provider;
|
|
|
|
|
|
using Hopetry.Services;
|
|
|
|
|
|
using Newtonsoft.Json;
|
2025-04-15 11:04:46 +08:00
|
|
|
|
using Path = System.IO.Path;
|
2025-04-08 16:22:25 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Hopetry.ViewModel.Send;
|
|
|
|
|
|
|
|
|
|
|
|
[ViewModel("Down")]
|
|
|
|
|
|
public class DownViewModel : MvcViewModelBase
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly MinioService _minioService;
|
2025-04-12 13:23:12 +08:00
|
|
|
|
|
2025-04-10 16:51:35 +08:00
|
|
|
|
public RelayCommand<MinioDownloadTask> OpenDownItemFolder { get; set; }
|
2025-04-10 13:17:39 +08:00
|
|
|
|
private readonly ConcurrentQueue<MinioDownloadTask> _taskQueue = new();
|
2025-04-12 15:50:38 +08:00
|
|
|
|
private SemaphoreSlim _semaphore;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
private CancellationTokenSource _processingCts = new();
|
2025-04-12 13:23:12 +08:00
|
|
|
|
public int count { get; set; }
|
|
|
|
|
|
private readonly ReaderWriterLockSlim _lock = new();
|
2025-04-14 13:52:04 +08:00
|
|
|
|
|
|
|
|
|
|
private Visibility _tab0Visibility;
|
2025-04-14 15:56:38 +08:00
|
|
|
|
|
2025-04-14 13:52:04 +08:00
|
|
|
|
public Visibility Tab0Visibility
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _tab0Visibility;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_tab0Visibility = value;
|
|
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Visibility _tab1Visibility;
|
2025-04-14 15:56:38 +08:00
|
|
|
|
|
2025-04-14 13:52:04 +08:00
|
|
|
|
public Visibility Tab1Visibility
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _tab1Visibility;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_tab1Visibility = value;
|
|
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-14 15:56:38 +08:00
|
|
|
|
|
2025-04-14 13:52:04 +08:00
|
|
|
|
private int _tabIndex;
|
|
|
|
|
|
|
|
|
|
|
|
public int TabIndex
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _tabIndex;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_tabIndex = value;
|
|
|
|
|
|
if (_tabIndex == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Tab0Visibility = Visibility.Visible;
|
|
|
|
|
|
Tab1Visibility = Visibility.Hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_tabIndex == 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Tab0Visibility = Visibility.Hidden;
|
|
|
|
|
|
Tab1Visibility = Visibility.Visible;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
2025-04-10 16:51:35 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 全部任务动态标题
|
|
|
|
|
|
/// </summary>
|
2025-04-10 14:31:05 +08:00
|
|
|
|
private string _allTaskHeader;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
public string AllTaskHeader
|
|
|
|
|
|
{
|
2025-04-10 14:31:05 +08:00
|
|
|
|
get => _allTaskHeader;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_allTaskHeader = value;
|
|
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _runningTaskHeader;
|
|
|
|
|
|
|
|
|
|
|
|
public string RunningTaskHeader
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _runningTaskHeader;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
set
|
|
|
|
|
|
{
|
2025-04-10 14:31:05 +08:00
|
|
|
|
_runningTaskHeader = value;
|
|
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string _finishedTaskHeader;
|
|
|
|
|
|
|
|
|
|
|
|
public string FinishedTaskHeader
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _finishedTaskHeader;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_finishedTaskHeader = value;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定属性
|
2025-04-14 15:56:38 +08:00
|
|
|
|
//public ObservableCollection<MinioDownloadTask> AllTasks { get; set; }
|
|
|
|
|
|
private ObservableCollection<MinioDownloadTask> _runningTasks;
|
2025-04-12 13:23:12 +08:00
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
public ObservableCollection<MinioDownloadTask> RunningTasks
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _runningTasks;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_runningTasks = value;
|
|
|
|
|
|
RaisePropertyChanged(); // 触发INotifyPropertyChanged通知
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
private ObservableCollection<MinioDownloadTask> _finishedTasks;
|
2025-04-15 14:05:06 +08:00
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
public ObservableCollection<MinioDownloadTask> FinishedTasks
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _finishedTasks;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_finishedTasks = value;
|
|
|
|
|
|
RaisePropertyChanged(); // 触发INotifyPropertyChanged通知
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-15 14:05:06 +08:00
|
|
|
|
|
2025-04-10 13:17:39 +08:00
|
|
|
|
private int _maxConcurrent = 3;
|
|
|
|
|
|
|
|
|
|
|
|
public int MaxConcurrent
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _maxConcurrent;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value < 1) value = 1;
|
|
|
|
|
|
if (_maxConcurrent == value) return;
|
|
|
|
|
|
|
|
|
|
|
|
_maxConcurrent = value;
|
2025-04-12 13:23:12 +08:00
|
|
|
|
//AdjustConcurrency();
|
2025-04-10 13:17:39 +08:00
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public ICommand ClearFinishedCommand { get; }
|
2025-04-15 14:05:06 +08:00
|
|
|
|
public RelayCommand<MinioDownloadTask> StartOrPauseDown { get; }
|
2025-04-14 15:56:38 +08:00
|
|
|
|
|
2025-04-08 16:22:25 +08:00
|
|
|
|
|
2025-04-10 14:31:05 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构造函数
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="minioService"></param>
|
2025-04-14 15:56:38 +08:00
|
|
|
|
public DownViewModel(MinioService minioService)
|
2025-04-08 16:22:25 +08:00
|
|
|
|
{
|
|
|
|
|
|
_minioService = minioService;
|
|
|
|
|
|
Console.WriteLine("初始化DownViewModel");
|
2025-04-12 13:23:12 +08:00
|
|
|
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
2025-04-10 16:51:35 +08:00
|
|
|
|
OpenDownItemFolder = new RelayCommand<MinioDownloadTask>(DoOpenDownItemFolder);
|
2025-04-15 14:05:06 +08:00
|
|
|
|
StartOrPauseDown = new RelayCommand<MinioDownloadTask>(DoStartOrPauseDown);
|
2025-04-14 15:56:38 +08:00
|
|
|
|
LoadFinishedTasks();
|
|
|
|
|
|
LoadRunningTasks();
|
|
|
|
|
|
ClearFinishedCommand = new CustomCommand(DoClearFinishedCommand);
|
|
|
|
|
|
// 启动任务处理线程
|
|
|
|
|
|
_semaphore = new SemaphoreSlim(MaxConcurrent);
|
|
|
|
|
|
new Thread(ProcessTasksLoop) { IsBackground = true }.Start();
|
|
|
|
|
|
}
|
2025-04-10 14:31:05 +08:00
|
|
|
|
|
2025-04-15 14:05:06 +08:00
|
|
|
|
private void DoStartOrPauseDown(MinioDownloadTask item)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item.Status == "下载中")
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Status = "已暂停";
|
|
|
|
|
|
// TODO 暂停下载
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (item.Status == "已暂停")
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Status = "下载中";
|
|
|
|
|
|
_taskQueue.Enqueue(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
private void DoClearFinishedCommand()
|
|
|
|
|
|
{
|
|
|
|
|
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
|
|
|
|
|
client.Deleteable<MinioDownloadTask>().Where(x => x.Status == "已完成").ExecuteCommand();
|
|
|
|
|
|
FinishedTasks.Clear();
|
|
|
|
|
|
FinishedTaskHeader = $"已完成(0)";
|
|
|
|
|
|
}
|
2025-04-14 13:52:04 +08:00
|
|
|
|
|
2025-04-15 16:13:12 +08:00
|
|
|
|
public void RefreshHeader()
|
|
|
|
|
|
{
|
|
|
|
|
|
RunningTaskHeader = $"下载中({RunningTasks.Count})";
|
|
|
|
|
|
FinishedTaskHeader = $"已完成({FinishedTasks.Count})";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
public void LoadRunningTasks()
|
|
|
|
|
|
{
|
2025-04-15 14:05:06 +08:00
|
|
|
|
// todo 队列中有几种任务状态 数据库中应该有几种任务状态
|
|
|
|
|
|
//
|
2025-04-14 15:56:38 +08:00
|
|
|
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
|
|
|
|
|
var data = client.Ado
|
|
|
|
|
|
.SqlQuery<MinioDownloadTask>(
|
|
|
|
|
|
$"select * from download_task where status='下载中' or status='等待中' or status='已暂停' order by task_id desc");
|
|
|
|
|
|
RunningTasks = new ObservableCollection<MinioDownloadTask>(data);
|
|
|
|
|
|
RunningTaskHeader = $"下载中({RunningTasks.Count})";
|
|
|
|
|
|
}
|
2025-04-12 13:23:12 +08:00
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
public void LoadFinishedTasks()
|
|
|
|
|
|
{
|
|
|
|
|
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
|
|
|
|
|
var data = client.Ado
|
2025-04-15 14:05:06 +08:00
|
|
|
|
.SqlQuery<MinioDownloadTask>(
|
|
|
|
|
|
$"select * from download_task where status='已完成' order by datetime(finished_time) desc");
|
2025-04-14 15:56:38 +08:00
|
|
|
|
FinishedTasks = new ObservableCollection<MinioDownloadTask>(data);
|
|
|
|
|
|
FinishedTaskHeader = $"已完成({FinishedTasks.Count})";
|
2025-04-12 15:50:38 +08:00
|
|
|
|
}
|
2025-04-12 13:23:12 +08:00
|
|
|
|
|
2025-04-12 15:50:38 +08:00
|
|
|
|
private async void ProcessTasksLoop()
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-12 15:50:38 +08:00
|
|
|
|
int c1 = 1;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
while (!_processingCts.IsCancellationRequested)
|
|
|
|
|
|
{
|
2025-04-12 15:50:38 +08:00
|
|
|
|
if (_taskQueue.TryDequeue(out var task))
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-14 13:52:04 +08:00
|
|
|
|
Console.WriteLine("存在可下载任务,正在申请许可...");
|
|
|
|
|
|
await _semaphore.WaitAsync();
|
|
|
|
|
|
Console.WriteLine("申请下载许可成功!马上开启下载");
|
2025-04-12 15:50:38 +08:00
|
|
|
|
// 启动新线程执行下载任务
|
2025-04-12 16:24:15 +08:00
|
|
|
|
// _ = Task.Run(() => ExecuteTaskAsync(task));
|
|
|
|
|
|
_ = ExecuteTaskAsync(task).ContinueWith(_ => _semaphore.Release());
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
2025-04-14 13:52:04 +08:00
|
|
|
|
// 无任务时,进入低功耗轮询
|
|
|
|
|
|
Thread.Sleep(500);
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 17:05:48 +08:00
|
|
|
|
public void AddTask(string bucketName, string objectKey, string size)
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-12 16:24:15 +08:00
|
|
|
|
var downDir = ViewModelLocator.SyncViewModel.SyncDir;
|
2025-04-14 17:05:48 +08:00
|
|
|
|
var task = new MinioDownloadTask(_minioService, bucketName, objectKey, downDir, size);
|
2025-04-12 13:23:12 +08:00
|
|
|
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
|
|
|
|
|
client.Insertable(task).ExecuteCommandIdentityIntoEntity();
|
2025-04-15 16:13:12 +08:00
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
RunningTasks.Add(task);
|
|
|
|
|
|
RefreshHeader();
|
|
|
|
|
|
});
|
2025-04-14 17:05:48 +08:00
|
|
|
|
Console.WriteLine($"文件大小:{size} ");
|
2025-04-10 13:17:39 +08:00
|
|
|
|
_taskQueue.Enqueue(task);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private async Task ExecuteTaskAsync(MinioDownloadTask task)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-04-15 09:40:29 +08:00
|
|
|
|
// todo 下载失败3次,停止下载
|
2025-04-12 13:23:12 +08:00
|
|
|
|
await task.StartDownload();
|
2025-04-15 16:13:12 +08:00
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
RunningTasks.Remove(task);
|
|
|
|
|
|
FinishedTasks.Add(task);
|
|
|
|
|
|
RefreshHeader();
|
|
|
|
|
|
});
|
|
|
|
|
|
//LoadRunningTasks();
|
|
|
|
|
|
//LoadFinishedTasks();
|
2025-04-12 15:50:38 +08:00
|
|
|
|
Console.WriteLine($"异步下载完成:{task.FileName}");
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AdjustConcurrency()
|
|
|
|
|
|
{
|
2025-04-12 15:50:38 +08:00
|
|
|
|
lock (_semaphore)
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 调整信号量容量
|
2025-04-12 15:50:38 +08:00
|
|
|
|
var delta = _maxConcurrent - _semaphore.CurrentCount;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
if (delta > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i < delta; i++)
|
|
|
|
|
|
{
|
2025-04-12 15:50:38 +08:00
|
|
|
|
_semaphore.Release();
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-12 13:23:12 +08:00
|
|
|
|
public void DoOpenDownItemFolder(MinioDownloadTask para)
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-12 13:23:12 +08:00
|
|
|
|
Console.WriteLine($"点击item值:{JsonConvert.SerializeObject(para)}");
|
2025-04-15 11:04:46 +08:00
|
|
|
|
//Process.Start("explorer.exe", para.FilePath);
|
|
|
|
|
|
var file = Path.Combine(para.FilePath, para.FileName);
|
|
|
|
|
|
Process.Start("explorer.exe", $"/select,\"{file}\"");
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-12 13:23:12 +08:00
|
|
|
|
public void DoCancelDownItem(MinioDownloadTask item)
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-12 13:23:12 +08:00
|
|
|
|
Console.WriteLine("取消下载");
|
|
|
|
|
|
// todo 实现取消下载
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-12 13:23:12 +08:00
|
|
|
|
public void DoPauseDownItem(MinioDownloadTask item)
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-12 13:23:12 +08:00
|
|
|
|
Console.WriteLine("暂停下载");
|
|
|
|
|
|
// todo 实现暂停下载
|
2025-04-08 16:22:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override void Init()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override void Loaded(string args)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|