927 lines
33 KiB
C#
927 lines
33 KiB
C#
using System;
|
||
using System.Collections.ObjectModel;
|
||
using System.ComponentModel;
|
||
using System.IO;
|
||
using System.Net.Http;
|
||
using System.Security.AccessControl;
|
||
using System.Windows;
|
||
using System.Windows.Documents;
|
||
using System.Windows.Input;
|
||
using System.Windows.Threading;
|
||
using HeBianGu.Base.WpfBase;
|
||
using HeBianGu.General.WpfControlLib;
|
||
using HeBianGu.Service.Mvc;
|
||
using Hopetry.Provider;
|
||
using Hopetry.Provider.Behaviors;
|
||
using Hopetry.Services;
|
||
using Hopetry.ViewModel.Send;
|
||
using Microsoft.Extensions.Configuration;
|
||
using Minio.DataModel.Args;
|
||
using Minio.DataModel;
|
||
using Minio;
|
||
using Newtonsoft.Json.Linq;
|
||
using System.Diagnostics;
|
||
using System.Timers;
|
||
using Hopetry.Services;
|
||
|
||
namespace HeBianGu.App.Disk
|
||
{
|
||
[ViewModel("Send")]
|
||
internal class SendViewModel : MvcViewModelBase
|
||
{
|
||
private LinkAction _uploadingAction; //正在上传
|
||
private LinkAction _completeAction; //上传完成
|
||
public LinkAction DownLinkAction;
|
||
public LinkAction _waituploadAction;
|
||
private readonly FileUploadService _uploadService;
|
||
public ICommand WaitUpLoadCommand { get; }
|
||
public ICommand DeleteWaitUpLoadCommand { get; }
|
||
public bool _isUploading = false;
|
||
|
||
public string CurrentMinIOPath;
|
||
|
||
// 分页相关字段
|
||
private int _waitUploadCurrentPage = 1;
|
||
private int _completedCurrentPage = 1;
|
||
private const int PAGE_SIZE = 50;
|
||
|
||
// 上传完成事件
|
||
public event Action<string> FileUploadCompleted;
|
||
|
||
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();
|
||
//加载待上传列表
|
||
GetWaitUploadItems(1); // 从第一页开始加载
|
||
//加载上传完成列表
|
||
GetCompletedFiles(1); // 从第一页开始加载
|
||
//new Thread(ProcessUploadTasks) { IsBackground = true }.Start();
|
||
Task.Run(() => ProcessUploadTasks()); // 启动文件上传线程
|
||
}
|
||
|
||
protected override void Init()
|
||
{
|
||
ITransitionWipe wipe = new CircleWipe();
|
||
|
||
DownLinkAction = new LinkAction()
|
||
{ Action = "Down", Controller = "Send", DisplayName = "下载 0", Logo = "\xe891", TransitionWipe = wipe };
|
||
LinkActions.Add(DownLinkAction);
|
||
// 正在上传
|
||
_uploadingAction = new LinkAction()
|
||
{
|
||
Action = "UpLoad",
|
||
Controller = "Send",
|
||
DisplayName = "正在上传",
|
||
Logo = "\xe6f3",
|
||
TransitionWipe = wipe
|
||
};
|
||
LinkActions.Add(_uploadingAction);
|
||
|
||
_completeAction = new LinkAction()
|
||
{
|
||
Action = "CompleteUpload",
|
||
Controller = "Send",
|
||
DisplayName = "上传完成",
|
||
Logo = "\xe613",
|
||
TransitionWipe = wipe
|
||
};
|
||
LinkActions.Add(_completeAction);
|
||
|
||
_waituploadAction = new LinkAction()
|
||
{
|
||
Action = "WaitUpload",
|
||
Controller = "Send",
|
||
DisplayName = "待上传",
|
||
Logo = "\xe613",
|
||
TransitionWipe = wipe
|
||
};
|
||
LinkActions.Add(_waituploadAction);
|
||
|
||
|
||
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Loaded,
|
||
new Action(() => { SelectLink = LinkActions[0]; }));
|
||
UpLoadItems.CollectionChanged += (s, e) => { UpdateUploadingItems(); };
|
||
}
|
||
|
||
protected override void Loaded(string args)
|
||
{
|
||
}
|
||
|
||
#region 文件上传
|
||
|
||
#region 参数
|
||
|
||
//上传文件总数
|
||
private ObservableCollection<UpLoadItems> _upLoadItems = new ObservableCollection<UpLoadItems>();
|
||
|
||
/// <summary> 说明 </summary>
|
||
public ObservableCollection<UpLoadItems> UpLoadItems
|
||
{
|
||
get { return _upLoadItems; }
|
||
set
|
||
{
|
||
_upLoadItems = value;
|
||
//UpdateUploadingItems();
|
||
RaisePropertyChanged("UpLoadItems");
|
||
}
|
||
}
|
||
|
||
//已上传完成文件
|
||
private ObservableCollection<UpLoadItems> _completeItems = new ObservableCollection<UpLoadItems>();
|
||
|
||
public ObservableCollection<UpLoadItems> CompleteItems
|
||
{
|
||
get { return _completeItems; }
|
||
private set
|
||
{
|
||
_completeItems = value;
|
||
RaisePropertyChanged("CompleteItems");
|
||
}
|
||
}
|
||
|
||
//待上传文件
|
||
private ObservableCollection<UpLoadItems> _waitUpLoadItems = new ObservableCollection<UpLoadItems>();
|
||
|
||
/// <summary> 说明 </summary>
|
||
public ObservableCollection<UpLoadItems> WaitUpLoadItems
|
||
{
|
||
get { return _waitUpLoadItems; }
|
||
set
|
||
{
|
||
_waitUpLoadItems = value;
|
||
RaisePropertyChanged("WaitUpLoadItems");
|
||
}
|
||
}
|
||
|
||
private bool? _isAllSelected;
|
||
|
||
public bool? IsAllSelected
|
||
{
|
||
get => _isAllSelected;
|
||
set
|
||
{
|
||
_isAllSelected = value;
|
||
// 全选/取消全选逻辑
|
||
if (value.HasValue)
|
||
{
|
||
foreach (var item in WaitUpLoadItems)
|
||
{
|
||
item.IsSelect = value.Value;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 只读属性,返回过滤后的集合(动态计算)
|
||
private ObservableCollection<UpLoadItems> _uploadingItems = new ObservableCollection<UpLoadItems>();
|
||
|
||
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>()
|
||
);
|
||
}
|
||
|
||
|
||
//文件上传进度
|
||
private decimal _progress;
|
||
|
||
public decimal Progress
|
||
{
|
||
get { return _progress; }
|
||
set
|
||
{
|
||
if (_progress != value)
|
||
{
|
||
_progress = value;
|
||
RaisePropertyChanged("Progress");
|
||
}
|
||
}
|
||
}
|
||
|
||
//上传文件个数
|
||
private string _filecount;
|
||
|
||
public string FileCount
|
||
{
|
||
get { return _filecount; }
|
||
set
|
||
{
|
||
if (_filecount != value)
|
||
{
|
||
_filecount = value;
|
||
RaisePropertyChanged("FileCount");
|
||
}
|
||
}
|
||
}
|
||
|
||
//上传完成文件个数
|
||
private int _uploadingcount;
|
||
|
||
public int UploadingCount
|
||
{
|
||
get { return _uploadingcount; }
|
||
set
|
||
{
|
||
if (_uploadingcount != value)
|
||
{
|
||
_uploadingcount = value;
|
||
_uploadingAction.FullName = "(" + _uploadingcount + ")";
|
||
RaisePropertyChanged("UploadingCount");
|
||
}
|
||
}
|
||
}
|
||
|
||
//上传文件个数
|
||
private int _completecount;
|
||
|
||
public int CompleteCount
|
||
{
|
||
get { return _completecount; }
|
||
set
|
||
{
|
||
if (_completecount != value)
|
||
{
|
||
_completecount = value;
|
||
_completeAction.FullName = "(" + _completecount + ")";
|
||
RaisePropertyChanged("CompleteCount");
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// 内存使用监控
|
||
private long _lastMemoryUsage = GC.GetTotalMemory(false);
|
||
|
||
public long MemoryUsage
|
||
{
|
||
get { return GC.GetTotalMemory(false); }
|
||
}
|
||
|
||
public double MemoryUsageMB
|
||
{
|
||
get { return Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0, 2); }
|
||
}
|
||
|
||
//等待上传文件个数
|
||
private int _waitcount;
|
||
|
||
public int WaitCount
|
||
{
|
||
get { return _waitcount; }
|
||
set
|
||
{
|
||
if (_waitcount != value)
|
||
{
|
||
_waitcount = value;
|
||
_waituploadAction.FullName = "(" + _waitcount + ")";
|
||
RaisePropertyChanged("WaitCount");
|
||
}
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region PropertyChanged
|
||
|
||
public event PropertyChangedEventHandler PropertyChanged;
|
||
|
||
protected void OnPropertyChanged(string propertyName)
|
||
{
|
||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||
}
|
||
|
||
#endregion
|
||
|
||
#endregion
|
||
|
||
#region 删除等待上传文件
|
||
|
||
private async Task DeleteFile()
|
||
{
|
||
try
|
||
{
|
||
var items = WaitUpLoadItems.Where(r => r.IsSelect == true).ToList();
|
||
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>();
|
||
list = items.Select(r => r.Value4).ToList();
|
||
var flag = _uploadService.DeleteFiles(list);
|
||
WaitUpLoadItems.RemoveAll(r => r.IsSelect == true);
|
||
WaitCount = WaitUpLoadItems.Count;
|
||
if (flag == true)
|
||
{
|
||
MessageBox.Show($"已成功删除 {items.Count} 个项目");
|
||
IsAllSelected = false;
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show($"删除失败");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show($"删除失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 上传待上传文件
|
||
|
||
public async Task UploadWaitItems()
|
||
{
|
||
var items = WaitUpLoadItems.Where(r => r.IsSelect == true).ToList();
|
||
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; //文件地址
|
||
ut.Value9 = item.Value9;
|
||
ut.Double1 = fileInfo.Length;
|
||
ut.Double2 = 0.0;
|
||
ut.Bool1 = false;
|
||
ut.Value1 = $"0{(fileInfo.Length < 1024 * 1024 ? "KB" : "MB")}/{sizeText}";
|
||
UpLoadItems.Add(ut);
|
||
}
|
||
|
||
_uploadCount = UpLoadItems.Count;
|
||
_completeCount = UpLoadItems.Where(r => r.Value3 == "已完成").Count();
|
||
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
||
UploadingCount = UploadingItems.Count;
|
||
CompleteCount = CompleteItems.Count;
|
||
MessageBox.Show("正在上传列表中可查看进度");
|
||
WaitUpLoadItems.RemoveAll(r => r.IsSelect == true);
|
||
IsAllSelected = false;
|
||
WaitCount = WaitUpLoadItems.Count;
|
||
// 如果没有上传任务在运行,则启动上传
|
||
if (!_isUploading)
|
||
{
|
||
try
|
||
{
|
||
await ProcessUploadTasks();
|
||
}
|
||
catch
|
||
{
|
||
MessageBox.Show("上传失败");
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
MessageBox.Show("文件丢失");
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 获取等待上传列表
|
||
|
||
public void GetWaitUploadItems(int pageNumber = 1)
|
||
{
|
||
var waitlist = _uploadService.GetIncompleteFiles(pageNumber, PAGE_SIZE);
|
||
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");
|
||
upLoadItems.Value9 = file.BucketName;
|
||
upLoadItems.Bool1 = false;
|
||
up.Add(upLoadItems);
|
||
}
|
||
|
||
WaitUpLoadItems.Clear();
|
||
WaitUpLoadItems.AddRange(up);
|
||
WaitCount = _uploadService.GetIncompleteFileCount(); // 从数据库获取总数
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 加载上传完成列表
|
||
|
||
//加载初始完成文件
|
||
public void GetCompletedFiles(int pageNumber = 1)
|
||
{
|
||
var files = _uploadService.GetCompleteFiles(pageNumber, PAGE_SIZE);
|
||
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");
|
||
upLoadItems.Value9 = file.BucketName;
|
||
up.Add(upLoadItems);
|
||
}
|
||
|
||
CompleteItems.Clear();
|
||
CompleteItems.AddRange(up);
|
||
regionCount = _uploadService.GetCompleteFileCount(); // 从数据库获取总数
|
||
CompleteCount = regionCount;
|
||
}
|
||
|
||
// 加载更多待上传文件
|
||
public void LoadMoreWaitUploadItems()
|
||
{
|
||
_waitUploadCurrentPage++;
|
||
var waitlist = _uploadService.GetIncompleteFiles(_waitUploadCurrentPage, PAGE_SIZE);
|
||
|
||
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);
|
||
}
|
||
|
||
WaitCount = _uploadService.GetIncompleteFileCount();
|
||
}
|
||
}
|
||
|
||
// 加载更多已完成文件
|
||
public void LoadMoreCompletedItems()
|
||
{
|
||
_completedCurrentPage++;
|
||
var files = _uploadService.GetCompleteFiles(_completedCurrentPage, PAGE_SIZE);
|
||
|
||
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);
|
||
}
|
||
|
||
regionCount = _uploadService.GetCompleteFileCount();
|
||
CompleteCount = regionCount;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 上传
|
||
|
||
//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; // 新增:当前上传任务
|
||
private CancellationTokenSource _uploadCancellation = new();
|
||
public int _uploadCount = 0;
|
||
public int _completeCount = 0;
|
||
private int regionCount = 0;
|
||
private ExplorerMinIOBehavior _explorerBehavior;
|
||
|
||
private Hopetry.Provider.SystemInfo systemInfo;
|
||
// 配置Redis连接
|
||
//private RedisService redis = new RedisService("175.27.168.120:6050,password=HopetryRedis1406,connectRetry=3");
|
||
|
||
#region 更新总进度条 每隔1s更新一次
|
||
|
||
private DateTime _lastProgressUpdate = DateTime.MinValue;
|
||
|
||
private void UpdateProgress(object sender, ElapsedEventArgs e)
|
||
{
|
||
if (UpLoadItems.Count == 0) return;
|
||
var now = DateTime.Now;
|
||
/*// 限制进度更新频率
|
||
|
||
if ((now - _lastProgressUpdate).TotalMilliseconds < 500) // 至少500ms更新一次
|
||
{
|
||
return;
|
||
}
|
||
|
||
double currentBytes = UpLoadItems.Sum(r => r.Double2);
|
||
double totalBytes = UpLoadItems.Sum(r => r.Double1);*/
|
||
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
||
// 避免除零错误
|
||
var progress = UpLoadItems.Count > 0
|
||
? Math.Round((decimal)(CompleteItems.Count / (UpLoadItems.Count + CompleteItems.Count)) * 100, 2)
|
||
: 0;
|
||
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
Progress = progress;
|
||
_lastProgressUpdate = now;
|
||
});
|
||
}
|
||
|
||
//上传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()
|
||
{
|
||
if (_isUploading) return; // 避免重复启动
|
||
|
||
_isUploading = true;
|
||
StartProgressTimer();
|
||
try
|
||
{
|
||
while (!_uploadCancellation.Token.IsCancellationRequested)
|
||
{
|
||
// 在后台线程获取待处理项
|
||
var pendingItems = UpLoadItems.Where(r => !r.Bool1).ToList();
|
||
|
||
if (!pendingItems.Any())
|
||
Thread.Sleep(500);
|
||
|
||
// 分批处理,避免一次性启动过多任务
|
||
const int batchSize = 10;
|
||
for (int i = 0; i < pendingItems.Count; i += batchSize)
|
||
{
|
||
var batch = pendingItems.Skip(i).Take(batchSize).ToList();
|
||
|
||
//创建并运行上传任务
|
||
var batchTasks = batch.Select(async item =>
|
||
{
|
||
// 使用带超时的信号量等待
|
||
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);
|
||
});
|
||
}
|
||
});
|
||
|
||
await Task.WhenAll(batchTasks);
|
||
// 批次间短暂延迟,避免过度占用资源
|
||
await Task.Delay(100);
|
||
}
|
||
}
|
||
}
|
||
catch (OperationCanceledException)
|
||
{
|
||
// 正常取消操作
|
||
Console.WriteLine("上传任务被取消");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Console.WriteLine($"上传任务异常: {ex.Message}");
|
||
// 上传被取消
|
||
}
|
||
finally
|
||
{
|
||
await Task.Delay(1000);
|
||
StopProgressTimer();
|
||
_isUploading = false;
|
||
|
||
// 在UI线程上更新界面
|
||
await Application.Current.Dispatcher.BeginInvoke(() =>
|
||
{
|
||
UpLoadItems.Clear();
|
||
//加载上传完成列表
|
||
GetCompletedFiles(1); // 重新加载第一页
|
||
if (MySetting.Instance.IsOn && !UpLoadItems.Any(item => !item.Bool1))
|
||
{
|
||
Shutdown();
|
||
}
|
||
|
||
// 刷新网盘空间页面以显示新上传的文件
|
||
//_explorerBehavior?.RefreshMinIOPath(CurrentMinIOPath);
|
||
|
||
// 执行垃圾回收以释放内存
|
||
GC.Collect();
|
||
GC.WaitForPendingFinalizers();
|
||
});
|
||
}
|
||
}
|
||
|
||
//上传具体执行
|
||
private async Task UploadFileToMinIOWithProgress(UpLoadItems ut)
|
||
{
|
||
ut.Bool1 = true;
|
||
|
||
try
|
||
{
|
||
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
|
||
// };
|
||
|
||
// 从配置获取MinIO设置更安全
|
||
IMinioClient client = new MinioClient()
|
||
.WithEndpoint(config["Minio:Endpoint"])
|
||
.WithCredentials(config["Minio:AccessKey"], config["Minio:SecretKey"])
|
||
.WithHttpClient(new HttpClient() { Timeout = TimeSpan.FromMinutes(30) })
|
||
.Build();
|
||
|
||
//string bucketName = GetCurrentBucket();
|
||
string bucketName = ut.Value9;
|
||
if (string.IsNullOrEmpty(bucketName))
|
||
{
|
||
throw new Exception("桶不能为空");
|
||
}
|
||
|
||
// 确保桶存在
|
||
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);
|
||
}
|
||
|
||
// 限制UI更新频率
|
||
DateTime lastUiUpdate = DateTime.MinValue;
|
||
var progress = new Progress<ProgressReport>(progressReport =>
|
||
{
|
||
var now = DateTime.Now;
|
||
// 限制UI更新频率,每200ms最多更新一次
|
||
if ((now - lastUiUpdate).TotalMilliseconds > 200)
|
||
{
|
||
Application.Current.Dispatcher.InvokeAsync(() =>
|
||
{
|
||
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;
|
||
});
|
||
}
|
||
});
|
||
|
||
// 使用安全上传助手进行文件上传
|
||
bool uploadSuccess = await UploadHelper.SafeUploadFileAsync(
|
||
client,
|
||
bucketName,
|
||
ut.Value5,
|
||
ut.Value6,
|
||
progress);
|
||
|
||
if (!uploadSuccess)
|
||
{
|
||
throw new Exception("文件上传失败");
|
||
}
|
||
|
||
// 上传完成后进行验证
|
||
await UploadVerifier.VerifyAsync(client, bucketName, ut.Value6);
|
||
|
||
// 验证成功后更新状态
|
||
ut.Value7 = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||
string id = ut.Value4.ToString();
|
||
await _uploadService.UpdateFileCompleteAsync(id, true);
|
||
|
||
// Application.Current.Dispatcher.Invoke
|
||
// 在UI线程上更新界面
|
||
await Application.Current.Dispatcher.BeginInvoke(() =>
|
||
{
|
||
// 从上传列表中移除已完成的项目
|
||
UpLoadItems.Remove(ut);
|
||
|
||
// 添加到完成列表
|
||
CompleteItems.Add(ut);
|
||
ut.Value3 = "已完成";
|
||
UpdateUploadingItems();
|
||
_completeCount++;
|
||
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
||
UpdateFileCounts();
|
||
// 刷新当前目录
|
||
//_explorerBehavior?.RefreshMinIOPath(CurrentMinIOPath);
|
||
|
||
// 触发上传完成事件
|
||
//FileUploadCompleted?.Invoke(CurrentMinIOPath);
|
||
Progress = (CompleteItems.Count) / (UpLoadItems.Count + CompleteItems.Count);
|
||
// 更新网盘空间页面状态
|
||
/*if (_explorerBehavior != null)
|
||
{
|
||
// 延迟刷新以确保MinIO有时间同步数据
|
||
Task.Delay(500).ContinueWith(_ =>
|
||
{
|
||
Application.Current.Dispatcher.Invoke(() =>
|
||
{
|
||
_explorerBehavior.RefreshMinIOPath(CurrentMinIOPath);
|
||
});
|
||
});
|
||
}*/
|
||
});
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
await Application.Current.Dispatcher.BeginInvoke(() => { ut.Value3 = $"上传失败: {ex.Message}"; });
|
||
|
||
try
|
||
{
|
||
await _uploadService.UpdateFileCompleteAsync(ut.Value4.ToString(), false);
|
||
}
|
||
catch (Exception dbEx)
|
||
{
|
||
Console.WriteLine($"数据库更新失败: {dbEx.Message}");
|
||
}
|
||
|
||
Console.WriteLine($"文件 {ut.Value} 上传失败: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
//获取当前路径下的桶
|
||
private string GetCurrentBucket()
|
||
{
|
||
if (string.IsNullOrEmpty(CurrentMinIOPath))
|
||
return string.Empty;
|
||
|
||
return CurrentMinIOPath.Split('/')[0];
|
||
}
|
||
|
||
//更新上传进行中及上传完成列表
|
||
private void UpdateFileCounts()
|
||
{
|
||
UploadingCount = UploadingItems.Count;
|
||
CompleteCount = CompleteItems.Count;
|
||
}
|
||
|
||
public void AddUploadTask(UpLoadItems ut)
|
||
{
|
||
Application.Current.Dispatcher.BeginInvoke(() =>
|
||
{
|
||
UpLoadItems.Add(ut);
|
||
_uploadCount = UpLoadItems.Count;
|
||
_completeCount = UpLoadItems.Where(r => r.Value3 == "已完成").Count();
|
||
FileCount = (CompleteItems.Count) + "/" + (UpLoadItems.Count + CompleteItems.Count);
|
||
UpdateFileCounts();
|
||
});
|
||
}
|
||
|
||
//关机
|
||
private void Shutdown()
|
||
{
|
||
try
|
||
{
|
||
Process.Start("shutdown", "/s /t 0");
|
||
}
|
||
catch (Win32Exception ex)
|
||
{
|
||
MessageBox.Show($"关机失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
}
|
||
|
||
// 清理资源
|
||
public void Cleanup()
|
||
{
|
||
_progressTimer?.Stop();
|
||
_progressTimer?.Dispose();
|
||
_heartbeatTimer?.Stop();
|
||
_heartbeatTimer?.Dispose();
|
||
_semaphore?.Release();
|
||
_uploadCancellation?.Cancel();
|
||
_uploadCancellation?.Dispose();
|
||
|
||
// 清理集合以释放内存
|
||
UpLoadItems?.Clear();
|
||
CompleteItems?.Clear();
|
||
WaitUpLoadItems?.Clear();
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |