2026-01-15 09:46:48 +08:00
|
|
|
|
using System;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
using System.Collections.ObjectModel;
|
2025-03-20 16:08:11 +08:00
|
|
|
|
using System.ComponentModel;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
|
using System.Security.AccessControl;
|
2025-03-17 10:58:59 +08:00
|
|
|
|
using System.Windows;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
using System.Windows.Documents;
|
|
|
|
|
|
using System.Windows.Input;
|
2025-03-17 10:58:59 +08:00
|
|
|
|
using System.Windows.Threading;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
using HeBianGu.Base.WpfBase;
|
2025-04-18 16:38:37 +08:00
|
|
|
|
using HeBianGu.General.WpfControlLib;
|
2025-04-26 10:53:46 +08:00
|
|
|
|
using HeBianGu.Service.Mvc;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
using Hopetry.Provider;
|
|
|
|
|
|
using Hopetry.Provider.Behaviors;
|
|
|
|
|
|
using Hopetry.Services;
|
2025-04-26 10:53:46 +08:00
|
|
|
|
using Hopetry.ViewModel.Send;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
using Microsoft.Extensions.Configuration;
|
|
|
|
|
|
using Minio.DataModel.Args;
|
|
|
|
|
|
using Minio.DataModel;
|
|
|
|
|
|
using Minio;
|
|
|
|
|
|
using Newtonsoft.Json.Linq;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Timers;
|
2026-01-15 09:46:48 +08:00
|
|
|
|
using Hopetry.Services;
|
2025-03-17 10:58:59 +08:00
|
|
|
|
|
|
|
|
|
|
namespace HeBianGu.App.Disk
|
|
|
|
|
|
{
|
|
|
|
|
|
[ViewModel("Send")]
|
|
|
|
|
|
internal class SendViewModel : MvcViewModelBase
|
|
|
|
|
|
{
|
2025-04-18 16:38:37 +08:00
|
|
|
|
private LinkAction _uploadingAction; //正在上传
|
|
|
|
|
|
private LinkAction _completeAction; //上传完成
|
2025-04-26 10:53:46 +08:00
|
|
|
|
public LinkAction DownLinkAction;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
public LinkAction _waituploadAction;
|
|
|
|
|
|
private readonly FileUploadService _uploadService;
|
|
|
|
|
|
public ICommand WaitUpLoadCommand { get; }
|
|
|
|
|
|
public ICommand DeleteWaitUpLoadCommand { get; }
|
|
|
|
|
|
public bool _isUploading = false;
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
public string CurrentMinIOPath;
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 分页相关字段
|
|
|
|
|
|
private int _waitUploadCurrentPage = 1;
|
|
|
|
|
|
private int _completedCurrentPage = 1;
|
|
|
|
|
|
private const int PAGE_SIZE = 50;
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 上传完成事件
|
|
|
|
|
|
public event Action<string> FileUploadCompleted;
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
public SendViewModel()
|
|
|
|
|
|
{
|
|
|
|
|
|
_uploadService = new FileUploadService();
|
|
|
|
|
|
// 初始化Timer
|
|
|
|
|
|
_progressTimer = new System.Timers.Timer(1000);
|
|
|
|
|
|
_progressTimer.Elapsed += UpdateProgress;
|
|
|
|
|
|
_heartbeatTimer = new System.Timers.Timer(30_000);
|
|
|
|
|
|
//_heartbeatTimer.Elapsed += async (s, e) => await SendHeartbeatAsync();
|
|
|
|
|
|
DeleteWaitUpLoadCommand = new AsyncRelayCommand(async () => await DeleteFile());
|
|
|
|
|
|
WaitUpLoadCommand = new AsyncRelayCommand(async () => await UploadWaitItems());
|
|
|
|
|
|
systemInfo = SystemInfoCollector.Collect();
|
|
|
|
|
|
//加载待上传列表
|
2026-01-15 09:46:48 +08:00
|
|
|
|
GetWaitUploadItems(1); // 从第一页开始加载
|
2025-06-04 17:20:25 +08:00
|
|
|
|
//加载上传完成列表
|
2026-01-17 09:29:03 +08:00
|
|
|
|
GetCompletedFiles(1); // 从第一页开始加载
|
|
|
|
|
|
//new Thread(ProcessUploadTasks) { IsBackground = true }.Start();
|
|
|
|
|
|
Task.Run(() => ProcessUploadTasks()); // 启动文件上传线程
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-04-18 14:04:28 +08:00
|
|
|
|
protected override void Init()
|
2025-03-17 10:58:59 +08:00
|
|
|
|
{
|
2025-04-18 16:38:37 +08:00
|
|
|
|
ITransitionWipe wipe = new CircleWipe();
|
2025-04-26 10:53:46 +08:00
|
|
|
|
|
|
|
|
|
|
DownLinkAction = new LinkAction()
|
2026-01-15 09:46:48 +08:00
|
|
|
|
{ Action = "Down", Controller = "Send", DisplayName = "下载 0", Logo = "\xe891", TransitionWipe = wipe };
|
2025-04-26 10:53:46 +08:00
|
|
|
|
LinkActions.Add(DownLinkAction);
|
2025-04-15 09:14:45 +08:00
|
|
|
|
// 正在上传
|
|
|
|
|
|
_uploadingAction = new LinkAction()
|
|
|
|
|
|
{
|
|
|
|
|
|
Action = "UpLoad",
|
|
|
|
|
|
Controller = "Send",
|
|
|
|
|
|
DisplayName = "正在上传",
|
2025-06-04 17:20:25 +08:00
|
|
|
|
Logo = "\xe6f3",
|
|
|
|
|
|
TransitionWipe = wipe
|
2025-04-15 09:14:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
LinkActions.Add(_uploadingAction);
|
|
|
|
|
|
|
|
|
|
|
|
_completeAction = new LinkAction()
|
|
|
|
|
|
{
|
|
|
|
|
|
Action = "CompleteUpload",
|
|
|
|
|
|
Controller = "Send",
|
|
|
|
|
|
DisplayName = "上传完成",
|
2025-06-04 17:20:25 +08:00
|
|
|
|
Logo = "\xe613",
|
|
|
|
|
|
TransitionWipe = wipe
|
2025-04-15 09:14:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
LinkActions.Add(_completeAction);
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
|
|
|
|
|
_waituploadAction = new LinkAction()
|
|
|
|
|
|
{
|
|
|
|
|
|
Action = "WaitUpload",
|
|
|
|
|
|
Controller = "Send",
|
|
|
|
|
|
DisplayName = "待上传",
|
|
|
|
|
|
Logo = "\xe613",
|
|
|
|
|
|
TransitionWipe = wipe
|
|
|
|
|
|
};
|
|
|
|
|
|
LinkActions.Add(_waituploadAction);
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-04-18 16:38:37 +08:00
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
|
|
|
|
|
|
new Action(() => { SelectLink = LinkActions[0]; }));
|
2025-04-18 16:23:55 +08:00
|
|
|
|
UpLoadItems.CollectionChanged += (s, e) => { UpdateUploadingItems(); };
|
2025-03-17 10:58:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected override void Loaded(string args)
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
2025-03-20 16:08:11 +08:00
|
|
|
|
|
|
|
|
|
|
#region 文件上传
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#region 参数
|
|
|
|
|
|
|
2025-04-07 11:30:57 +08:00
|
|
|
|
//上传文件总数
|
2025-03-24 10:09:10 +08:00
|
|
|
|
private ObservableCollection<UpLoadItems> _upLoadItems = new ObservableCollection<UpLoadItems>();
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-03-24 10:09:10 +08:00
|
|
|
|
/// <summary> 说明 </summary>
|
|
|
|
|
|
public ObservableCollection<UpLoadItems> UpLoadItems
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _upLoadItems; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_upLoadItems = value;
|
2025-04-07 11:30:57 +08:00
|
|
|
|
//UpdateUploadingItems();
|
2025-03-24 10:09:10 +08:00
|
|
|
|
RaisePropertyChanged("UpLoadItems");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 11:30:57 +08:00
|
|
|
|
//已上传完成文件
|
2025-03-27 09:32:04 +08:00
|
|
|
|
private ObservableCollection<UpLoadItems> _completeItems = new ObservableCollection<UpLoadItems>();
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-03-27 09:32:04 +08:00
|
|
|
|
public ObservableCollection<UpLoadItems> CompleteItems
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _completeItems; }
|
2025-04-07 11:30:57 +08:00
|
|
|
|
private set
|
2025-03-27 09:32:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
_completeItems = value;
|
|
|
|
|
|
RaisePropertyChanged("CompleteItems");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
//待上传文件
|
|
|
|
|
|
private ObservableCollection<UpLoadItems> _waitUpLoadItems = new ObservableCollection<UpLoadItems>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 说明 </summary>
|
|
|
|
|
|
public ObservableCollection<UpLoadItems> WaitUpLoadItems
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _waitUpLoadItems; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_waitUpLoadItems = value;
|
|
|
|
|
|
RaisePropertyChanged("WaitUpLoadItems");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-07 11:30:57 +08:00
|
|
|
|
|
2025-07-05 13:59:04 +08:00
|
|
|
|
private bool? _isAllSelected;
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-07-05 13:59:04 +08:00
|
|
|
|
public bool? IsAllSelected
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _isAllSelected;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_isAllSelected = value;
|
|
|
|
|
|
// 全选/取消全选逻辑
|
|
|
|
|
|
if (value.HasValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in WaitUpLoadItems)
|
|
|
|
|
|
{
|
2025-07-05 16:46:35 +08:00
|
|
|
|
item.IsSelect = value.Value;
|
2025-07-05 13:59:04 +08:00
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
}
|
2025-07-05 13:59:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-07 11:30:57 +08:00
|
|
|
|
// 只读属性,返回过滤后的集合(动态计算)
|
|
|
|
|
|
private ObservableCollection<UpLoadItems> _uploadingItems = new ObservableCollection<UpLoadItems>();
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-04-07 11:30:57 +08:00
|
|
|
|
public ObservableCollection<UpLoadItems> UploadingItems
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _uploadingItems; }
|
|
|
|
|
|
private set
|
|
|
|
|
|
{
|
|
|
|
|
|
_uploadingItems = value;
|
|
|
|
|
|
RaisePropertyChanged("UploadingItems");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 在 UpLoadItems 变化时更新 UploadingItems
|
|
|
|
|
|
public void UpdateUploadingItems()
|
|
|
|
|
|
{
|
|
|
|
|
|
UploadingItems = new ObservableCollection<UpLoadItems>(
|
|
|
|
|
|
UpLoadItems?.Where(item => item.Value3 != "已完成") ?? Enumerable.Empty<UpLoadItems>()
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//文件上传进度
|
2026-01-20 10:45:58 +08:00
|
|
|
|
private decimal _progress;
|
2025-03-20 16:08:11 +08:00
|
|
|
|
|
2026-01-20 10:45:58 +08:00
|
|
|
|
public decimal Progress
|
2025-03-20 16:08:11 +08:00
|
|
|
|
{
|
|
|
|
|
|
get { return _progress; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_progress != value)
|
|
|
|
|
|
{
|
|
|
|
|
|
_progress = value;
|
2025-04-18 16:38:37 +08:00
|
|
|
|
RaisePropertyChanged("Progress");
|
2025-03-20 16:08:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-07 11:30:57 +08:00
|
|
|
|
|
|
|
|
|
|
//上传文件个数
|
|
|
|
|
|
private string _filecount;
|
|
|
|
|
|
|
|
|
|
|
|
public string FileCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _filecount; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_filecount != value)
|
|
|
|
|
|
{
|
|
|
|
|
|
_filecount = value;
|
|
|
|
|
|
RaisePropertyChanged("FileCount");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-04-15 09:14:45 +08:00
|
|
|
|
//上传完成文件个数
|
|
|
|
|
|
private int _uploadingcount;
|
|
|
|
|
|
|
|
|
|
|
|
public int UploadingCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _uploadingcount; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_uploadingcount != value)
|
2025-04-18 16:38:37 +08:00
|
|
|
|
{
|
2025-04-15 09:14:45 +08:00
|
|
|
|
_uploadingcount = value;
|
|
|
|
|
|
_uploadingAction.FullName = "(" + _uploadingcount + ")";
|
|
|
|
|
|
RaisePropertyChanged("UploadingCount");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-04-15 09:14:45 +08:00
|
|
|
|
//上传文件个数
|
|
|
|
|
|
private int _completecount;
|
|
|
|
|
|
|
|
|
|
|
|
public int CompleteCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _completecount; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_completecount != value)
|
|
|
|
|
|
{
|
|
|
|
|
|
_completecount = value;
|
2025-04-18 16:38:37 +08:00
|
|
|
|
_completeAction.FullName = "(" + _completecount + ")";
|
2025-04-15 09:14:45 +08:00
|
|
|
|
RaisePropertyChanged("CompleteCount");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 内存使用监控
|
|
|
|
|
|
private long _lastMemoryUsage = GC.GetTotalMemory(false);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
public long MemoryUsage
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return GC.GetTotalMemory(false); }
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
public double MemoryUsageMB
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0, 2); }
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
//等待上传文件个数
|
|
|
|
|
|
private int _waitcount;
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
public int WaitCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _waitcount; }
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_waitcount != value)
|
|
|
|
|
|
{
|
|
|
|
|
|
_waitcount = value;
|
|
|
|
|
|
_waituploadAction.FullName = "(" + _waitcount + ")";
|
|
|
|
|
|
RaisePropertyChanged("WaitCount");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region PropertyChanged
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-03-20 16:08:11 +08:00
|
|
|
|
public event PropertyChangedEventHandler PropertyChanged;
|
|
|
|
|
|
|
|
|
|
|
|
protected void OnPropertyChanged(string propertyName)
|
|
|
|
|
|
{
|
|
|
|
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#endregion
|
2025-04-18 16:38:37 +08:00
|
|
|
|
|
2025-03-20 16:08:11 +08:00
|
|
|
|
#endregion
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
|
|
|
|
|
#region 删除等待上传文件
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
private async Task DeleteFile()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-07-05 16:46:35 +08:00
|
|
|
|
var items = WaitUpLoadItems.Where(r => r.IsSelect == true).ToList();
|
2025-06-04 17:20:25 +08:00
|
|
|
|
if (items == null || !items.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
await MessageProxy.Messager.ShowResult("请先选择要删除的项目");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var message = $"确定要删除选中的 {items.Count} 个项目吗?";
|
|
|
|
|
|
var result = MessageBox.Show(message, "确认删除", MessageBoxButton.YesNo);
|
|
|
|
|
|
|
|
|
|
|
|
if (result == MessageBoxResult.Yes)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<string> list = new List<string>();
|
2026-01-15 09:46:48 +08:00
|
|
|
|
list = items.Select(r => r.Value4).ToList();
|
|
|
|
|
|
var flag = _uploadService.DeleteFiles(list);
|
|
|
|
|
|
WaitUpLoadItems.RemoveAll(r => r.IsSelect == true);
|
|
|
|
|
|
WaitCount = WaitUpLoadItems.Count;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
if (flag == true)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"已成功删除 {items.Count} 个项目");
|
2025-07-05 13:59:04 +08:00
|
|
|
|
IsAllSelected = false;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"删除失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"删除失败: {ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 上传待上传文件
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
public async Task UploadWaitItems()
|
|
|
|
|
|
{
|
2025-07-05 16:46:35 +08:00
|
|
|
|
var items = WaitUpLoadItems.Where(r => r.IsSelect == true).ToList();
|
2025-06-04 17:20:25 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in items)
|
|
|
|
|
|
{
|
|
|
|
|
|
FileInfo fileInfo = new FileInfo(item.Value5);
|
|
|
|
|
|
string sizeText = fileInfo.Length < 1024 * 1024
|
|
|
|
|
|
? $"{Math.Ceiling((decimal)fileInfo.Length / 1024)}KB"
|
|
|
|
|
|
: $"{Math.Ceiling((decimal)fileInfo.Length / (1024 * 1024))}MB";
|
|
|
|
|
|
UpLoadItems ut = new UpLoadItems();
|
|
|
|
|
|
ut.Value = item.Value;
|
|
|
|
|
|
ut.Value3 = "等待上传";
|
|
|
|
|
|
ut.Value4 = item.Value4; //唯一标识,与数据库一致
|
|
|
|
|
|
ut.Value5 = item.Value5; //文件名称
|
|
|
|
|
|
ut.Value6 = item.Value6; //文件地址
|
2025-07-05 16:46:35 +08:00
|
|
|
|
ut.Value9 = item.Value9;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
ut.Double1 = fileInfo.Length;
|
|
|
|
|
|
ut.Double2 = 0.0;
|
|
|
|
|
|
ut.Bool1 = false;
|
|
|
|
|
|
ut.Value1 = $"0{(fileInfo.Length < 1024 * 1024 ? "KB" : "MB")}/{sizeText}";
|
|
|
|
|
|
UpLoadItems.Add(ut);
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
_uploadCount = UpLoadItems.Count;
|
|
|
|
|
|
_completeCount = UpLoadItems.Where(r => r.Value3 == "已完成").Count();
|
2026-01-19 15:07:36 +08:00
|
|
|
|
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
2025-06-04 17:20:25 +08:00
|
|
|
|
UploadingCount = UploadingItems.Count;
|
|
|
|
|
|
CompleteCount = CompleteItems.Count;
|
|
|
|
|
|
MessageBox.Show("正在上传列表中可查看进度");
|
2025-07-05 16:46:35 +08:00
|
|
|
|
WaitUpLoadItems.RemoveAll(r => r.IsSelect == true);
|
2025-07-05 13:59:04 +08:00
|
|
|
|
IsAllSelected = false;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
WaitCount = WaitUpLoadItems.Count;
|
|
|
|
|
|
// 如果没有上传任务在运行,则启动上传
|
|
|
|
|
|
if (!_isUploading)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await ProcessUploadTasks();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("上传失败");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("文件丢失");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
#region 获取等待上传列表
|
|
|
|
|
|
|
|
|
|
|
|
public void GetWaitUploadItems(int pageNumber = 1)
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
var waitlist = _uploadService.GetIncompleteFiles(pageNumber, PAGE_SIZE);
|
2025-06-04 17:20:25 +08:00
|
|
|
|
ObservableCollection<UpLoadItems> up = new ObservableCollection<UpLoadItems>();
|
|
|
|
|
|
if (_isUploading == false)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var file in waitlist)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpLoadItems upLoadItems = new UpLoadItems();
|
|
|
|
|
|
upLoadItems.Value = file.FileName;
|
|
|
|
|
|
upLoadItems.Value4 = file.Id;
|
|
|
|
|
|
upLoadItems.Value5 = file.FilePath;
|
|
|
|
|
|
upLoadItems.Value1 = file.FileSizeText;
|
|
|
|
|
|
upLoadItems.Value6 = file.FileName;
|
|
|
|
|
|
upLoadItems.Value7 = file.CreateTime.ToString("yyyy-MM-dd HH:mm:ss");
|
2025-07-05 16:46:35 +08:00
|
|
|
|
upLoadItems.Value9 = file.BucketName;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
upLoadItems.Bool1 = false;
|
|
|
|
|
|
up.Add(upLoadItems);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
WaitUpLoadItems.Clear();
|
|
|
|
|
|
WaitUpLoadItems.AddRange(up);
|
2026-01-15 09:46:48 +08:00
|
|
|
|
WaitCount = _uploadService.GetIncompleteFileCount(); // 从数据库获取总数
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 加载上传完成列表
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
//加载初始完成文件
|
2026-01-15 09:46:48 +08:00
|
|
|
|
public void GetCompletedFiles(int pageNumber = 1)
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
var files = _uploadService.GetCompleteFiles(pageNumber, PAGE_SIZE);
|
2025-06-04 17:20:25 +08:00
|
|
|
|
ObservableCollection<UpLoadItems> up = new ObservableCollection<UpLoadItems>();
|
|
|
|
|
|
foreach (var file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpLoadItems upLoadItems = new UpLoadItems();
|
|
|
|
|
|
upLoadItems.Value = file.FileName;
|
|
|
|
|
|
upLoadItems.Value4 = file.Id;
|
|
|
|
|
|
upLoadItems.Value5 = file.FilePath;
|
|
|
|
|
|
upLoadItems.Value1 = file.FileSizeText;
|
|
|
|
|
|
upLoadItems.Value6 = file.FileName;
|
|
|
|
|
|
upLoadItems.Value7 = file.CompleteTime.ToString("yyyy-MM-dd HH:mm:ss");
|
2025-07-05 16:46:35 +08:00
|
|
|
|
upLoadItems.Value9 = file.BucketName;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
up.Add(upLoadItems);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CompleteItems.Clear();
|
|
|
|
|
|
CompleteItems.AddRange(up);
|
2026-01-15 09:46:48 +08:00
|
|
|
|
regionCount = _uploadService.GetCompleteFileCount(); // 从数据库获取总数
|
2025-06-04 17:20:25 +08:00
|
|
|
|
CompleteCount = regionCount;
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载更多待上传文件
|
|
|
|
|
|
public void LoadMoreWaitUploadItems()
|
|
|
|
|
|
{
|
|
|
|
|
|
_waitUploadCurrentPage++;
|
|
|
|
|
|
var waitlist = _uploadService.GetIncompleteFiles(_waitUploadCurrentPage, PAGE_SIZE);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
if (waitlist.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var file in waitlist)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpLoadItems upLoadItems = new UpLoadItems();
|
|
|
|
|
|
upLoadItems.Value = file.FileName;
|
|
|
|
|
|
upLoadItems.Value4 = file.Id;
|
|
|
|
|
|
upLoadItems.Value5 = file.FilePath;
|
|
|
|
|
|
upLoadItems.Value1 = file.FileSizeText;
|
|
|
|
|
|
upLoadItems.Value6 = file.FileName;
|
|
|
|
|
|
upLoadItems.Value7 = file.CreateTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
upLoadItems.Value9 = file.BucketName;
|
|
|
|
|
|
upLoadItems.Bool1 = false;
|
|
|
|
|
|
WaitUpLoadItems.Add(upLoadItems);
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
WaitCount = _uploadService.GetIncompleteFileCount();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 加载更多已完成文件
|
|
|
|
|
|
public void LoadMoreCompletedItems()
|
|
|
|
|
|
{
|
|
|
|
|
|
_completedCurrentPage++;
|
|
|
|
|
|
var files = _uploadService.GetCompleteFiles(_completedCurrentPage, PAGE_SIZE);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
if (files.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
UpLoadItems upLoadItems = new UpLoadItems();
|
|
|
|
|
|
upLoadItems.Value = file.FileName;
|
|
|
|
|
|
upLoadItems.Value4 = file.Id;
|
|
|
|
|
|
upLoadItems.Value5 = file.FilePath;
|
|
|
|
|
|
upLoadItems.Value1 = file.FileSizeText;
|
|
|
|
|
|
upLoadItems.Value6 = file.FileName;
|
|
|
|
|
|
upLoadItems.Value7 = file.CompleteTime.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
upLoadItems.Value9 = file.BucketName;
|
|
|
|
|
|
CompleteItems.Add(upLoadItems);
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
regionCount = _uploadService.GetCompleteFileCount();
|
|
|
|
|
|
CompleteCount = regionCount;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 上传
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
//private SendViewModel _sendViewModel;
|
|
|
|
|
|
private SemaphoreSlim _semaphore = new SemaphoreSlim(5);
|
|
|
|
|
|
private System.Timers.Timer _progressTimer;
|
|
|
|
|
|
private System.Timers.Timer _heartbeatTimer;
|
|
|
|
|
|
private bool _isTimerRunning = false;
|
|
|
|
|
|
private object _timerLock = new object();
|
|
|
|
|
|
private Task _currentUploadTask = null; // 新增:当前上传任务
|
2026-01-17 09:29:03 +08:00
|
|
|
|
private CancellationTokenSource _uploadCancellation = new();
|
2025-06-04 17:20:25 +08:00
|
|
|
|
public int _uploadCount = 0;
|
2025-07-14 17:32:18 +08:00
|
|
|
|
public int _completeCount = 0;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
private int regionCount = 0;
|
|
|
|
|
|
private ExplorerMinIOBehavior _explorerBehavior;
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
private Hopetry.Provider.SystemInfo systemInfo;
|
|
|
|
|
|
// 配置Redis连接
|
|
|
|
|
|
//private RedisService redis = new RedisService("175.27.168.120:6050,password=HopetryRedis1406,connectRetry=3");
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#region 更新总进度条 每隔1s更新一次
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
private DateTime _lastProgressUpdate = DateTime.MinValue;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
|
|
|
|
|
private void UpdateProgress(object sender, ElapsedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (UpLoadItems.Count == 0) return;
|
2026-01-15 09:46:48 +08:00
|
|
|
|
var now = DateTime.Now;
|
2026-01-20 10:45:58 +08:00
|
|
|
|
/*// 限制进度更新频率
|
|
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
if ((now - _lastProgressUpdate).TotalMilliseconds < 500) // 至少500ms更新一次
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
double currentBytes = UpLoadItems.Sum(r => r.Double2);
|
2026-01-20 10:45:58 +08:00
|
|
|
|
double totalBytes = UpLoadItems.Sum(r => r.Double1);*/
|
|
|
|
|
|
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 避免除零错误
|
2026-01-20 10:45:58 +08:00
|
|
|
|
var progress = UpLoadItems.Count > 0
|
|
|
|
|
|
? Math.Round((decimal)(CompleteItems.Count / (UpLoadItems.Count + CompleteItems.Count)) * 100, 2)
|
|
|
|
|
|
: 0;
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2026-01-17 09:29:03 +08:00
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Progress = progress;
|
2026-01-15 09:46:48 +08:00
|
|
|
|
_lastProgressUpdate = now;
|
|
|
|
|
|
});
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//上传redis心跳检测
|
|
|
|
|
|
//private async Task SendHeartbeatAsync()
|
|
|
|
|
|
//{
|
|
|
|
|
|
// try
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // 上报心跳并更新客户端信息
|
|
|
|
|
|
// //await redis.StoreClientInfoAsync(systemInfo);
|
|
|
|
|
|
// await redis.UpdateClientHeartbeatAsync(systemInfo.MachineId);
|
|
|
|
|
|
// }
|
|
|
|
|
|
// catch (Exception ex)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // 处理网络异常等
|
|
|
|
|
|
// Debug.WriteLine($"心跳上报失败: {ex.Message}");
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
private void StartProgressTimer()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_timerLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_isTimerRunning)
|
|
|
|
|
|
{
|
|
|
|
|
|
_progressTimer.Start();
|
|
|
|
|
|
_heartbeatTimer.Start();
|
|
|
|
|
|
_isTimerRunning = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void StopProgressTimer()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_timerLock)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_isTimerRunning)
|
|
|
|
|
|
{
|
|
|
|
|
|
_progressTimer.Stop();
|
|
|
|
|
|
_heartbeatTimer.Stop();
|
|
|
|
|
|
_isTimerRunning = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
//创建上传任务
|
|
|
|
|
|
public async Task ProcessUploadTasks()
|
|
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
if (_isUploading) return; // 避免重复启动
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
_isUploading = true;
|
|
|
|
|
|
StartProgressTimer();
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
while (!_uploadCancellation.Token.IsCancellationRequested)
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 在后台线程获取待处理项
|
2026-01-17 09:29:03 +08:00
|
|
|
|
var pendingItems = UpLoadItems.Where(r => !r.Bool1).ToList();
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
|
|
|
|
|
if (!pendingItems.Any())
|
2026-01-17 09:29:03 +08:00
|
|
|
|
Thread.Sleep(500);
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 分批处理,避免一次性启动过多任务
|
|
|
|
|
|
const int batchSize = 10;
|
|
|
|
|
|
for (int i = 0; i < pendingItems.Count; i += batchSize)
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
var batch = pendingItems.Skip(i).Take(batchSize).ToList();
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
//创建并运行上传任务
|
|
|
|
|
|
var batchTasks = batch.Select(async item =>
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 使用带超时的信号量等待
|
|
|
|
|
|
if (await _semaphore.WaitAsync(30000, _uploadCancellation.Token)) // 30秒超时
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await UploadFileToMinIOWithProgress(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
_semaphore.Release();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 信号量获取超时,标记为失败
|
|
|
|
|
|
await Application.Current.Dispatcher.BeginInvoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Value3 = "上传超时";
|
|
|
|
|
|
_uploadService.UpdateFileComplete(item.Value4.ToString(), false);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
await Task.WhenAll(batchTasks);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 批次间短暂延迟,避免过度占用资源
|
|
|
|
|
|
await Task.Delay(100);
|
|
|
|
|
|
}
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
catch (OperationCanceledException)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 正常取消操作
|
|
|
|
|
|
Console.WriteLine("上传任务被取消");
|
|
|
|
|
|
}
|
2025-06-04 17:20:25 +08:00
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
Console.WriteLine($"上传任务异常: {ex.Message}");
|
|
|
|
|
|
// 上传被取消
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
await Task.Delay(1000);
|
2025-06-04 17:20:25 +08:00
|
|
|
|
StopProgressTimer();
|
|
|
|
|
|
_isUploading = false;
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 在UI线程上更新界面
|
|
|
|
|
|
await Application.Current.Dispatcher.BeginInvoke(() =>
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
UpLoadItems.Clear();
|
|
|
|
|
|
//加载上传完成列表
|
2026-01-17 09:29:03 +08:00
|
|
|
|
GetCompletedFiles(1); // 重新加载第一页
|
2026-01-15 09:46:48 +08:00
|
|
|
|
if (MySetting.Instance.IsOn && !UpLoadItems.Any(item => !item.Bool1))
|
|
|
|
|
|
{
|
|
|
|
|
|
Shutdown();
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 刷新网盘空间页面以显示新上传的文件
|
|
|
|
|
|
_explorerBehavior?.RefreshMinIOPath(CurrentMinIOPath);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 执行垃圾回收以释放内存
|
|
|
|
|
|
GC.Collect();
|
|
|
|
|
|
GC.WaitForPendingFinalizers();
|
|
|
|
|
|
});
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//上传具体执行
|
|
|
|
|
|
private async Task UploadFileToMinIOWithProgress(UpLoadItems ut)
|
|
|
|
|
|
{
|
|
|
|
|
|
ut.Bool1 = true;
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
var builder = new ConfigurationBuilder()
|
|
|
|
|
|
.SetBasePath(Directory.GetCurrentDirectory())
|
|
|
|
|
|
.AddJsonFile("global.json", optional: false, reloadOnChange: true);
|
|
|
|
|
|
// 构建配置
|
|
|
|
|
|
var config = builder.Build();
|
|
|
|
|
|
// 获取滑块设置的速度限制(转换为字节 / 秒)
|
|
|
|
|
|
// 查询所有客户端
|
|
|
|
|
|
//var allClients = await redis.GetAllClientsAsync();
|
|
|
|
|
|
//var num = allClients == null ? 1 : allClients.Distinct().Count();
|
|
|
|
|
|
//var speedLimit = 10 * 1024 * 1024 / num/5;
|
|
|
|
|
|
|
|
|
|
|
|
var speedLimit = 100 * 1024 * 1024;
|
|
|
|
|
|
//var speedLimit = Convert.ToInt64(config["Minio:limitspeed"]);
|
|
|
|
|
|
var handler = new MinIOThrottledHandler(speedLimit,
|
|
|
|
|
|
new HttpClientHandler
|
|
|
|
|
|
{
|
|
|
|
|
|
// 保持 MinIO 必需的 SSL 配置
|
|
|
|
|
|
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//var handler =
|
|
|
|
|
|
// new HttpClientHandler
|
|
|
|
|
|
// {
|
|
|
|
|
|
// // 保持 MinIO 必需的 SSL 配置
|
|
|
|
|
|
// ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true
|
|
|
|
|
|
// };
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
// 从配置获取MinIO设置更安全
|
|
|
|
|
|
IMinioClient client = new MinioClient()
|
|
|
|
|
|
.WithEndpoint(config["Minio:Endpoint"])
|
|
|
|
|
|
.WithCredentials(config["Minio:AccessKey"], config["Minio:SecretKey"])
|
2025-07-05 10:02:29 +08:00
|
|
|
|
.WithHttpClient(new HttpClient() { Timeout = TimeSpan.FromMinutes(30) })
|
2025-06-04 17:20:25 +08:00
|
|
|
|
.Build();
|
2025-07-14 17:32:18 +08:00
|
|
|
|
|
2025-07-05 16:46:35 +08:00
|
|
|
|
//string bucketName = GetCurrentBucket();
|
|
|
|
|
|
string bucketName = ut.Value9;
|
|
|
|
|
|
if (string.IsNullOrEmpty(bucketName))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("桶不能为空");
|
|
|
|
|
|
}
|
2026-01-15 09:46:48 +08:00
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
// 确保桶存在
|
|
|
|
|
|
var beArgs = new BucketExistsArgs().WithBucket(bucketName);
|
|
|
|
|
|
bool found = await client.BucketExistsAsync(beArgs).ConfigureAwait(false);
|
|
|
|
|
|
if (!found)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mbArgs = new MakeBucketArgs().WithBucket(bucketName);
|
|
|
|
|
|
await client.MakeBucketAsync(mbArgs).ConfigureAwait(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 限制UI更新频率
|
|
|
|
|
|
DateTime lastUiUpdate = DateTime.MinValue;
|
2025-06-04 17:20:25 +08:00
|
|
|
|
var progress = new Progress<ProgressReport>(progressReport =>
|
|
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
var now = DateTime.Now;
|
|
|
|
|
|
// 限制UI更新频率,每200ms最多更新一次
|
|
|
|
|
|
if ((now - lastUiUpdate).TotalMilliseconds > 200)
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
Application.Current.Dispatcher.InvokeAsync(() =>
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
ut.Int1 = progressReport.Percentage;
|
|
|
|
|
|
long trans = progressReport.TotalBytesTransferred;
|
|
|
|
|
|
ut.Double2 = trans;
|
|
|
|
|
|
|
|
|
|
|
|
int slashIndex = ut.Value1.IndexOf('/');
|
|
|
|
|
|
string sizePart = ut.Value1.Substring(slashIndex);
|
|
|
|
|
|
string transferredPart = trans < 1024 * 1024
|
|
|
|
|
|
? $"{Math.Ceiling((decimal)trans / 1024)}KB"
|
|
|
|
|
|
: $"{Math.Ceiling((decimal)trans / (1024 * 1024))}MB";
|
|
|
|
|
|
|
|
|
|
|
|
ut.Value1 = $"{transferredPart}{sizePart}";
|
|
|
|
|
|
ut.Value3 = progressReport.Percentage == 100 ? "验证中..." : "上传中...";
|
|
|
|
|
|
lastUiUpdate = now;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-06-04 17:20:25 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 使用安全上传助手进行文件上传
|
|
|
|
|
|
bool uploadSuccess = await UploadHelper.SafeUploadFileAsync(
|
2026-01-17 09:29:03 +08:00
|
|
|
|
client,
|
|
|
|
|
|
bucketName,
|
|
|
|
|
|
ut.Value5,
|
|
|
|
|
|
ut.Value6,
|
2026-01-15 09:46:48 +08:00
|
|
|
|
progress);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
if (!uploadSuccess)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("文件上传失败");
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 上传完成后进行验证
|
|
|
|
|
|
await UploadVerifier.VerifyAsync(client, bucketName, ut.Value6);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 验证成功后更新状态
|
|
|
|
|
|
ut.Value7 = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
string id = ut.Value4.ToString();
|
|
|
|
|
|
await _uploadService.UpdateFileCompleteAsync(id, true);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
|
|
|
|
|
// Application.Current.Dispatcher.Invoke
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 在UI线程上更新界面
|
|
|
|
|
|
await Application.Current.Dispatcher.BeginInvoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 从上传列表中移除已完成的项目
|
|
|
|
|
|
UpLoadItems.Remove(ut);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 添加到完成列表
|
|
|
|
|
|
CompleteItems.Add(ut);
|
|
|
|
|
|
ut.Value3 = "已完成";
|
|
|
|
|
|
UpdateUploadingItems();
|
|
|
|
|
|
_completeCount++;
|
2026-01-19 15:07:36 +08:00
|
|
|
|
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
2026-01-15 09:46:48 +08:00
|
|
|
|
UpdateFileCounts();
|
|
|
|
|
|
// 刷新当前目录
|
|
|
|
|
|
_explorerBehavior?.RefreshMinIOPath(CurrentMinIOPath);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 触发上传完成事件
|
|
|
|
|
|
FileUploadCompleted?.Invoke(CurrentMinIOPath);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 更新网盘空间页面状态
|
|
|
|
|
|
/*if (_explorerBehavior != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 延迟刷新以确保MinIO有时间同步数据
|
|
|
|
|
|
Task.Delay(500).ContinueWith(_ =>
|
2025-06-04 17:20:25 +08:00
|
|
|
|
{
|
2026-01-15 09:46:48 +08:00
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
_explorerBehavior.RefreshMinIOPath(CurrentMinIOPath);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}*/
|
2025-06-04 17:20:25 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-01-17 09:29:03 +08:00
|
|
|
|
await Application.Current.Dispatcher.BeginInvoke(() => { ut.Value3 = $"上传失败: {ex.Message}"; });
|
|
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await _uploadService.UpdateFileCompleteAsync(ut.Value4.ToString(), false);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception dbEx)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine($"数据库更新失败: {dbEx.Message}");
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
Console.WriteLine($"文件 {ut.Value} 上传失败: {ex.Message}");
|
2025-06-04 17:20:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取当前路径下的桶
|
|
|
|
|
|
private string GetCurrentBucket()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(CurrentMinIOPath))
|
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
return CurrentMinIOPath.Split('/')[0];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//更新上传进行中及上传完成列表
|
|
|
|
|
|
private void UpdateFileCounts()
|
|
|
|
|
|
{
|
|
|
|
|
|
UploadingCount = UploadingItems.Count;
|
|
|
|
|
|
CompleteCount = CompleteItems.Count;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-17 09:29:03 +08:00
|
|
|
|
public void AddUploadTask(UpLoadItems ut)
|
|
|
|
|
|
{
|
|
|
|
|
|
Application.Current.Dispatcher.BeginInvoke(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
UpLoadItems.Add(ut);
|
|
|
|
|
|
_uploadCount = UpLoadItems.Count;
|
|
|
|
|
|
_completeCount = UpLoadItems.Where(r => r.Value3 == "已完成").Count();
|
2026-01-19 15:07:36 +08:00
|
|
|
|
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
2026-01-17 09:29:03 +08:00
|
|
|
|
UpdateFileCounts();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
//关机
|
|
|
|
|
|
private void Shutdown()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Process.Start("shutdown", "/s /t 0");
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Win32Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"关机失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 清理资源
|
|
|
|
|
|
public void Cleanup()
|
|
|
|
|
|
{
|
|
|
|
|
|
_progressTimer?.Stop();
|
|
|
|
|
|
_progressTimer?.Dispose();
|
|
|
|
|
|
_heartbeatTimer?.Stop();
|
|
|
|
|
|
_heartbeatTimer?.Dispose();
|
|
|
|
|
|
_semaphore?.Release();
|
|
|
|
|
|
_uploadCancellation?.Cancel();
|
|
|
|
|
|
_uploadCancellation?.Dispose();
|
2026-01-17 09:29:03 +08:00
|
|
|
|
|
2026-01-15 09:46:48 +08:00
|
|
|
|
// 清理集合以释放内存
|
|
|
|
|
|
UpLoadItems?.Clear();
|
|
|
|
|
|
CompleteItems?.Clear();
|
|
|
|
|
|
WaitUpLoadItems?.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-04 17:20:25 +08:00
|
|
|
|
#endregion
|
2025-03-17 10:58:59 +08:00
|
|
|
|
}
|
2025-04-18 16:38:37 +08:00
|
|
|
|
}
|