2025-04-21 16:35:40 +08:00
|
|
|
|
using System.IO;
|
2025-04-12 13:23:12 +08:00
|
|
|
|
using System.Windows;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
using HeBianGu.Base.WpfBase;
|
2025-04-12 13:23:12 +08:00
|
|
|
|
using Hopetry.Provider;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
using SqlSugar;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Hopetry.Services;
|
|
|
|
|
|
|
|
|
|
|
|
[SugarTable(TableName = "download_task")]
|
2025-04-21 16:35:40 +08:00
|
|
|
|
public class MinioDownloadTask : NotifyPropertyChangedBase
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-23 10:33:57 +08:00
|
|
|
|
// 同步锁
|
|
|
|
|
|
private static readonly object SyncLock = new();
|
2025-04-21 13:41:57 +08:00
|
|
|
|
public MinioService Minio;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
2025-04-21 16:35:40 +08:00
|
|
|
|
public CancellationTokenSource StopDownTs;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private ManualResetEventSlim _pauseEvent = new(true);
|
|
|
|
|
|
|
|
|
|
|
|
// 任务属性(绑定到UI)
|
2025-04-12 13:23:12 +08:00
|
|
|
|
[SugarColumn(ColumnName = "task_id", IsPrimaryKey = true, IsIdentity = true)]
|
|
|
|
|
|
public int TaskId { get; set; }
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "file_name")]
|
|
|
|
|
|
public string FileName { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "bucket_name")]
|
2025-04-24 16:44:43 +08:00
|
|
|
|
public string BucketName { get; set; }
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "object_key")]
|
|
|
|
|
|
public string ObjectKey { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "total_size")]
|
2025-04-23 10:29:49 +08:00
|
|
|
|
public long TotalSize { get; set; }
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "downloaded")]
|
2025-04-21 16:42:41 +08:00
|
|
|
|
public long Downloaded { get; set; }
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "file_path")]
|
|
|
|
|
|
public string FilePath { get; set; }
|
|
|
|
|
|
|
2025-04-12 16:43:28 +08:00
|
|
|
|
[SugarColumn(ColumnName = "status")] public string Status { get; set; } = "等待中";
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
[SugarColumn(ColumnName = "create_time")]
|
|
|
|
|
|
public string CreateTime { get; set; }
|
2025-04-14 17:05:48 +08:00
|
|
|
|
|
2025-04-14 15:56:38 +08:00
|
|
|
|
[SugarColumn(ColumnName = "finished_time")]
|
|
|
|
|
|
public string FinishedTime { get; set; }
|
2025-04-15 09:40:29 +08:00
|
|
|
|
|
2025-04-14 17:05:48 +08:00
|
|
|
|
[SugarColumn(ColumnName = "file_size")]
|
|
|
|
|
|
public string FileSize { get; set; }
|
|
|
|
|
|
|
2025-04-15 09:40:29 +08:00
|
|
|
|
[SugarColumn(ColumnName = "file_etag")]
|
|
|
|
|
|
public string FileETag { get; set; }
|
2025-04-16 13:48:45 +08:00
|
|
|
|
|
2025-04-24 16:44:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 0 普通对象 1 文件夹 2 存储桶
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
[SugarColumn(ColumnName = "type")]
|
|
|
|
|
|
public int Type { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "file_number")]
|
|
|
|
|
|
public int FileNumber { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[SugarColumn(ColumnName = "download_number")]
|
|
|
|
|
|
public int DownloadNumber { get; set; }
|
|
|
|
|
|
|
2025-04-26 14:03:11 +08:00
|
|
|
|
[SugarColumn(ColumnName = "file_icon")]
|
|
|
|
|
|
public string FileIcon { get; set; }
|
|
|
|
|
|
|
2025-04-24 16:44:43 +08:00
|
|
|
|
private string _downloadInfo;
|
2025-04-16 13:48:45 +08:00
|
|
|
|
|
|
|
|
|
|
[SugarColumn(IsIgnore = true)]
|
2025-04-24 16:44:43 +08:00
|
|
|
|
public string DownloadInfo
|
2025-04-16 13:48:45 +08:00
|
|
|
|
{
|
|
|
|
|
|
get => _downloadInfo;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_downloadInfo = value;
|
2025-04-21 16:35:40 +08:00
|
|
|
|
RaisePropertyChanged();
|
2025-04-16 13:48:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private String _speed;
|
|
|
|
|
|
|
|
|
|
|
|
[SugarColumn(IsIgnore = true)]
|
|
|
|
|
|
public String Speed
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _speed;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_speed = value;
|
2025-04-21 16:35:40 +08:00
|
|
|
|
RaisePropertyChanged();
|
2025-04-16 13:48:45 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-15 14:05:06 +08:00
|
|
|
|
private Double _progress;
|
2025-04-16 13:48:45 +08:00
|
|
|
|
|
2025-04-12 13:23:12 +08:00
|
|
|
|
[SugarColumn(IsIgnore = true)]
|
2025-04-15 14:05:06 +08:00
|
|
|
|
public Double Progress
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-15 10:29:41 +08:00
|
|
|
|
get
|
|
|
|
|
|
{
|
2025-04-15 14:05:06 +08:00
|
|
|
|
if (_progress == 0)
|
2025-04-15 10:29:41 +08:00
|
|
|
|
{
|
2025-04-23 16:34:24 +08:00
|
|
|
|
if (TotalSize == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return 0d;
|
|
|
|
|
|
}
|
2025-04-24 16:44:43 +08:00
|
|
|
|
|
2025-04-15 14:05:06 +08:00
|
|
|
|
_progress = Downloaded == 0 ? 0 : (Downloaded * 100 / TotalSize);
|
2025-04-15 10:29:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return _progress;
|
|
|
|
|
|
}
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_progress = value;
|
2025-04-21 16:35:40 +08:00
|
|
|
|
RaisePropertyChanged();
|
2025-04-15 10:29:41 +08:00
|
|
|
|
}
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-22 10:58:32 +08:00
|
|
|
|
private string _startOrPauseIcon;
|
|
|
|
|
|
|
|
|
|
|
|
[SugarColumn(IsIgnore = true)]
|
|
|
|
|
|
public string StartOrPauseIcon
|
|
|
|
|
|
{
|
|
|
|
|
|
get => _startOrPauseIcon;
|
|
|
|
|
|
set
|
|
|
|
|
|
{
|
|
|
|
|
|
_startOrPauseIcon = value;
|
|
|
|
|
|
RaisePropertyChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-23 10:29:49 +08:00
|
|
|
|
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
|
|
|
|
|
public MinioDownloadTask()
|
|
|
|
|
|
{
|
2025-04-23 09:45:08 +08:00
|
|
|
|
StartOrPauseIcon = "\xe76e";
|
|
|
|
|
|
Status = "等待中";
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
2025-04-12 13:23:12 +08:00
|
|
|
|
|
2025-04-24 16:44:43 +08:00
|
|
|
|
public MinioDownloadTask(MinioService minio, string bucketName, string objectKey, string downDir, string fileSize)
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-26 14:03:11 +08:00
|
|
|
|
var suffix = objectKey[objectKey.LastIndexOf('.')..].ToLower();
|
|
|
|
|
|
FileIcon = suffix switch
|
2025-04-26 10:53:46 +08:00
|
|
|
|
{
|
2025-04-26 14:03:11 +08:00
|
|
|
|
".png" or ".jpg" or ".jpeg" or ".gif" => "\xe747",
|
|
|
|
|
|
".pdf" => "\xe804",
|
|
|
|
|
|
".doc" or ".docx" => "\xe744",
|
|
|
|
|
|
".xls" or ".xlsx" => "\xe80a",
|
|
|
|
|
|
".zip" or ".rar" or ".7z" => "\xe810",
|
|
|
|
|
|
".mp3" or ".wav" => "\xe7ff",
|
|
|
|
|
|
".mp4" or ".avi" or ".mov" => "\xe803",
|
|
|
|
|
|
".txt" => "\xe666",
|
|
|
|
|
|
_ => "\xe741" // 默认图标
|
|
|
|
|
|
};
|
2025-04-26 10:53:46 +08:00
|
|
|
|
|
2025-04-22 10:58:32 +08:00
|
|
|
|
StartOrPauseIcon = "\xe76e";
|
2025-04-12 15:50:38 +08:00
|
|
|
|
Status = "等待中";
|
2025-04-21 13:41:57 +08:00
|
|
|
|
Minio = minio;
|
2025-04-24 16:44:43 +08:00
|
|
|
|
BucketName = bucketName;
|
2025-04-10 13:17:39 +08:00
|
|
|
|
ObjectKey = objectKey;
|
|
|
|
|
|
FileName = Path.GetFileName(objectKey);
|
2025-04-12 16:24:15 +08:00
|
|
|
|
FilePath = downDir;
|
2025-04-14 15:56:38 +08:00
|
|
|
|
CreateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
2025-04-24 16:44:43 +08:00
|
|
|
|
var x = minio.GetObjectMetadata(bucketName, objectKey);
|
2025-04-23 09:45:08 +08:00
|
|
|
|
TotalSize = x.Result.Size;
|
2025-04-14 17:05:48 +08:00
|
|
|
|
FileSize = fileSize;
|
2025-04-21 16:42:41 +08:00
|
|
|
|
Speed = Status;
|
|
|
|
|
|
DownloadInfo = $"0MB/{FileSize}";
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
2025-04-21 16:42:41 +08:00
|
|
|
|
|
2025-04-15 14:05:06 +08:00
|
|
|
|
|
2025-04-10 13:17:39 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 下载
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="savePath"></param>
|
2025-04-12 13:23:12 +08:00
|
|
|
|
public async Task StartDownload()
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-21 16:35:40 +08:00
|
|
|
|
StopDownTs = new CancellationTokenSource();
|
2025-04-10 13:17:39 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-04-24 16:44:43 +08:00
|
|
|
|
var stat = await Minio.GetObjectMetadata(BucketName, ObjectKey);
|
2025-04-15 10:29:41 +08:00
|
|
|
|
// 获取对象信息
|
|
|
|
|
|
TotalSize = stat.Size;
|
|
|
|
|
|
FileETag = stat.ETag;
|
2025-04-12 13:23:12 +08:00
|
|
|
|
Status = "下载中";
|
|
|
|
|
|
var updateTask = new MinioDownloadTask
|
|
|
|
|
|
{
|
|
|
|
|
|
TaskId = TaskId,
|
2025-04-15 10:29:41 +08:00
|
|
|
|
Status = Status,
|
|
|
|
|
|
TotalSize = TotalSize,
|
|
|
|
|
|
FileETag = FileETag
|
2025-04-12 13:23:12 +08:00
|
|
|
|
};
|
2025-04-10 13:17:39 +08:00
|
|
|
|
|
2025-04-12 13:23:12 +08:00
|
|
|
|
using (var client = SqlSugarConfig.GetSqlSugarScope())
|
2025-04-10 13:17:39 +08:00
|
|
|
|
{
|
2025-04-12 13:23:12 +08:00
|
|
|
|
await client.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-12 16:24:15 +08:00
|
|
|
|
Console.WriteLine($"id {TaskId} path: {FilePath} key: {ObjectKey}文件下载中...");
|
2025-04-12 13:23:12 +08:00
|
|
|
|
updateTask.Status = "下载中";
|
2025-04-17 09:12:17 +08:00
|
|
|
|
var humanFileSize = (TotalSize > 1048576
|
|
|
|
|
|
? $"{TotalSize / 1048576}MB"
|
|
|
|
|
|
: $"{TotalSize / 1024}KB");
|
2025-04-22 10:58:32 +08:00
|
|
|
|
var offset = Downloaded;
|
2025-04-22 13:30:54 +08:00
|
|
|
|
Console.WriteLine("偏移量:" + (offset > 1048576 ? $"{offset / 1048576:f2}MB" : $"{(offset) / 1024:f2}KB"));
|
2025-04-24 16:44:43 +08:00
|
|
|
|
await Minio.DownLoadObjectWithCallBack(this, BucketName, ObjectKey, FilePath, FileETag,
|
2025-04-16 13:48:45 +08:00
|
|
|
|
(downloaded, total, speed) =>
|
2025-04-15 10:29:41 +08:00
|
|
|
|
{
|
2025-04-22 10:58:32 +08:00
|
|
|
|
var progress = (double)(downloaded + offset) / total * 100;
|
2025-04-22 13:30:54 +08:00
|
|
|
|
Downloaded = downloaded + offset;
|
2025-04-15 14:05:06 +08:00
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
|
{
|
2025-04-16 13:48:45 +08:00
|
|
|
|
var remaining = total - downloaded;
|
|
|
|
|
|
var seconds = speed > 0 ? remaining / speed : 0;
|
2025-04-17 09:12:17 +08:00
|
|
|
|
Speed = (speed > 1048576
|
2025-04-18 14:04:28 +08:00
|
|
|
|
? $"{speed / 1048576:f2}MB/s"
|
|
|
|
|
|
: $"{speed / 1024:f2}KB/s") + $" 剩余时间 {TimeSpan.FromSeconds(seconds):mm\\:ss}";
|
2025-04-15 14:05:06 +08:00
|
|
|
|
Progress = progress;
|
2025-04-22 10:58:32 +08:00
|
|
|
|
DownloadInfo = (downloaded + offset > 1048576
|
|
|
|
|
|
? $"{(downloaded + offset) / 1048576:f2}MB"
|
|
|
|
|
|
: $"{(downloaded + offset) / 1024:f2}KB") + "/" + humanFileSize;
|
2025-04-17 09:12:17 +08:00
|
|
|
|
//Console.WriteLine($"{DownloadInfo}");
|
2025-04-16 13:48:45 +08:00
|
|
|
|
/*var x =
|
|
|
|
|
|
$"{(double)downloaded / total:P1} | {speed:0.0} KB/s | 剩余 {TimeSpan.FromSeconds(seconds):mm\\:ss}";
|
|
|
|
|
|
Console.WriteLine(x);*/
|
2025-04-15 14:05:06 +08:00
|
|
|
|
});
|
2025-04-22 10:58:32 +08:00
|
|
|
|
}, offset: offset);
|
2025-04-10 13:17:39 +08:00
|
|
|
|
Status = "已完成";
|
2025-04-12 13:23:12 +08:00
|
|
|
|
updateTask.Status = Status;
|
2025-04-22 14:01:48 +08:00
|
|
|
|
updateTask.Downloaded = TotalSize;
|
2025-04-14 17:05:48 +08:00
|
|
|
|
updateTask.FinishedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
2025-04-12 13:23:12 +08:00
|
|
|
|
using (var client = SqlSugarConfig.GetSqlSugarScope())
|
|
|
|
|
|
{
|
|
|
|
|
|
await client.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"文件{ObjectKey}下载完成");
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
_pauseEvent.Dispose();
|
2025-04-21 16:35:40 +08:00
|
|
|
|
RaisePropertyChanged(nameof(Status));
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-24 16:44:43 +08:00
|
|
|
|
|
|
|
|
|
|
public async Task StartDownloadDir()
|
|
|
|
|
|
{
|
|
|
|
|
|
StopDownTs = new CancellationTokenSource();
|
|
|
|
|
|
// 改变任务状态
|
|
|
|
|
|
Status = "下载中";
|
|
|
|
|
|
var updateTask = new MinioDownloadTask
|
|
|
|
|
|
{
|
|
|
|
|
|
TaskId = TaskId
|
|
|
|
|
|
};
|
|
|
|
|
|
var prefix = BucketName.Equals(ObjectKey) ? "" : ObjectKey;
|
|
|
|
|
|
var allObject = await Minio.ListAllObject(BucketName, prefix, true, StopDownTs.Token);
|
|
|
|
|
|
await foreach (var item in allObject)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 验证文件是否存在
|
|
|
|
|
|
if (File.Exists(Path.Combine(FilePath, item.Key))) continue;
|
|
|
|
|
|
var localDir = Type == 1 ? FilePath : Path.Combine(FilePath, BucketName);
|
2025-04-26 10:53:46 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await Minio.DownLoadObject(BucketName, item.Key, localDir, item.ETag, StopDownTs.Token);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("停止运行了");
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-24 16:44:43 +08:00
|
|
|
|
DownloadNumber++;
|
|
|
|
|
|
DownloadInfo = $"{DownloadNumber}/{FileNumber}";
|
2025-04-26 10:53:46 +08:00
|
|
|
|
Speed = $"已下载 {DownloadNumber}";
|
2025-04-24 16:44:43 +08:00
|
|
|
|
Progress = (double)DownloadNumber / FileNumber * 100;
|
|
|
|
|
|
using var xxx = SqlSugarConfig.GetSqlSugarScope();
|
|
|
|
|
|
updateTask.DownloadNumber = DownloadNumber;
|
|
|
|
|
|
await xxx.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Status = "已完成";
|
|
|
|
|
|
updateTask.Status = Status;
|
|
|
|
|
|
updateTask.FinishedTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
|
updateTask.DownloadNumber = DownloadNumber;
|
|
|
|
|
|
using var client = SqlSugarConfig.GetSqlSugarScope();
|
|
|
|
|
|
await client.Updateable(updateTask).IgnoreNullColumns().ExecuteCommandAsync();
|
|
|
|
|
|
}
|
2025-04-10 13:17:39 +08:00
|
|
|
|
}
|