Merge remote-tracking branch 'origin/dev2.0' into dev2.0
# Conflicts: # ViewModel/Loyout/LoyoutViewModel.cs # minio.dbdev2.0
commit
b42ea1f55c
|
|
@ -11,6 +11,7 @@ using HeBianGu.Service.Mvp;
|
|||
using HeBianGu.Systems.Identity;
|
||||
using HeBianGu.Systems.Setting;
|
||||
using HeBianGu.Window.Link;
|
||||
using Hopetry.Provider;
|
||||
using Hopetry.Services;
|
||||
using SqlSugar;
|
||||
using SystemSetting = FileUploader.Models.SystemSetting;
|
||||
|
|
@ -125,7 +126,9 @@ namespace HeBianGu.App.Disk
|
|||
//var find = dll.GetTypes().Where(x => typeof(IExplorerService).IsAssignableFrom(x))?.FirstOrDefault();
|
||||
//ServiceRegistry.Instance.Register(typeof(IExplorerService), find);
|
||||
//services.AddSingleton<IExplorerService, WindowExplorerServiceDemo>();
|
||||
|
||||
|
||||
//minio分片上传修改
|
||||
PartSizeOverride.OverrideMinioCalculator();
|
||||
|
||||
var minioService = services.GetService<MinioService>();
|
||||
var bucketName = minioService._bucketName;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="C:\Users\79980\.nuget\packages\hebiangu.service.markupextension\5.0.0\contentFiles\any\net7.0-windows7.0\logo.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HeBianGu.Base.WpfBase" Version="5.0.0" />
|
||||
<PackageReference Include="HeBianGu.Control.Adorner" Version="5.0.0" />
|
||||
|
|
@ -44,6 +48,7 @@
|
|||
<PackageReference Include="HeBianGu.Window.Link" Version="5.0.0" />
|
||||
<PackageReference Include="HeBianGu.Window.Message" Version="5.0.0" />
|
||||
<PackageReference Include="HeBianGu.Window.MessageDialog" Version="5.0.0" />
|
||||
<PackageReference Include="Lib.Harmony" Version="2.3.6" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.3" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using Minio.DataModel;
|
||||
using Minio.Exceptions;
|
||||
|
||||
namespace Hopetry.Provider
|
||||
{
|
||||
public class PartSizeOverride
|
||||
{
|
||||
private static Harmony _harmony;
|
||||
|
||||
/// <summary>
|
||||
/// 使用Harmony动态替换MinIO的分片计算逻辑
|
||||
/// </summary>
|
||||
public static void OverrideMinioCalculator()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 初始化Harmony实例
|
||||
_harmony = new Harmony("com.hopetry.minio.patch");
|
||||
|
||||
// 获取原始方法和自定义方法
|
||||
var originalMethod = typeof(Minio.Helper.Utils).GetMethod(
|
||||
"CalculateMultiPartSize",
|
||||
BindingFlags.Static | BindingFlags.Public,
|
||||
null,
|
||||
new[] { typeof(long), typeof(bool) },
|
||||
null);
|
||||
|
||||
var customMethod = typeof(PartSizeOverride).GetMethod(
|
||||
"CustomCalculateMultiPartSize",
|
||||
BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
if (originalMethod == null || customMethod == null)
|
||||
throw new InvalidOperationException("Method not found");
|
||||
|
||||
// 应用Harmony补丁(替换原始方法)
|
||||
_harmony.Patch(originalMethod,
|
||||
new HarmonyMethod(customMethod));
|
||||
|
||||
Console.WriteLine("Method override successful");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Override failed: {ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自定义分片计算逻辑(需严格匹配原始方法签名)
|
||||
/// </summary>
|
||||
private static bool CustomCalculateMultiPartSize(ref MultiPartInfo __result, long size, bool copy)
|
||||
{
|
||||
// 原计算逻辑保持不变
|
||||
long MaxParts = 10000;
|
||||
long MinimumPartSize = 5 * 1024L * 1024L;
|
||||
long MinimumPUTPartSize = 16 * 1024L * 1024L;
|
||||
long MaximumStreamObjectSize = MaxParts * MinimumPartSize;
|
||||
long MaxMultipartPutObjectSize = 1024L * 1024L * 1024L * 1024L * 5;
|
||||
if (size == -1) size = MaximumStreamObjectSize;
|
||||
long MinimumCOPYPartSize = 512 * 1024L * 1024L;
|
||||
|
||||
if (size > MaxMultipartPutObjectSize)
|
||||
throw new EntityTooLargeException(
|
||||
$"Your proposed upload size {size} exceeds the maximum allowed object size {MaxMultipartPutObjectSize}");
|
||||
|
||||
var partSize = (double)Math.Ceiling((decimal)size / MaxParts);
|
||||
var minPartSize = copy ? MinimumCOPYPartSize : MinimumPartSize;
|
||||
partSize = (double)Math.Ceiling((decimal)partSize / minPartSize) * minPartSize;
|
||||
var partCount = Math.Ceiling(size / partSize);
|
||||
var lastPartSize = size - ((partCount - 1) * partSize);
|
||||
|
||||
__result = new MultiPartInfo
|
||||
{
|
||||
PartSize = partSize,
|
||||
PartCount = partCount,
|
||||
LastPartSize = lastPartSize
|
||||
};
|
||||
|
||||
// 跳过原始方法执行
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -902,29 +902,78 @@ namespace Hopetry.Provider
|
|||
_totalLength = totalLength;
|
||||
}
|
||||
|
||||
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
//public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
//{
|
||||
// // 计算剩余可读取字节数
|
||||
// var remaining = _totalLength - _bytesRead;
|
||||
// if (remaining <= 0) return 0;
|
||||
|
||||
// // 动态调整缓冲区大小(优化大文件传输)
|
||||
// int chunkSize = (int)Math.Min(
|
||||
// Math.Min(count, _maxBytesPerSecond), // 每 chunk 不超过限速的 1/10
|
||||
// remaining
|
||||
// );
|
||||
|
||||
// int bytesRead = await _innerStream.ReadAsync(buffer, offset, chunkSize, cancellationToken);
|
||||
// if (bytesRead == 0) return 0;
|
||||
|
||||
// // 精确限速控制
|
||||
// var expectedTime = (double)(_bytesRead + bytesRead) / _maxBytesPerSecond;
|
||||
// var actualTime = _stopwatch.Elapsed.TotalSeconds;
|
||||
|
||||
// if (actualTime < expectedTime)
|
||||
// {
|
||||
// var delay = TimeSpan.FromSeconds(expectedTime - actualTime);
|
||||
// await Task.Delay(delay, cancellationToken);
|
||||
// }
|
||||
|
||||
// Interlocked.Add(ref _bytesRead, bytesRead);
|
||||
// return bytesRead;
|
||||
//}
|
||||
|
||||
public override async Task<int> ReadAsync(
|
||||
byte[] buffer,
|
||||
int offset,
|
||||
int count,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// 计算剩余可读取字节数
|
||||
// 计算剩余可读取字节
|
||||
var remaining = _totalLength - _bytesRead;
|
||||
if (remaining <= 0) return 0;
|
||||
|
||||
// 动态调整缓冲区大小(优化大文件传输)
|
||||
// 优化1:动态调整块大小为限速值的1/2,减少调用次数
|
||||
int chunkSize = (int)Math.Min(
|
||||
Math.Min(count, _maxBytesPerSecond / 10), // 每 chunk 不超过限速的 1/10
|
||||
Math.Min(count, _maxBytesPerSecond / 2),
|
||||
remaining
|
||||
);
|
||||
|
||||
int bytesRead = await _innerStream.ReadAsync(buffer, offset, chunkSize, cancellationToken);
|
||||
// 记录读取开始时间
|
||||
long startTicks = _stopwatch.ElapsedTicks;
|
||||
|
||||
int bytesRead = await _innerStream.ReadAsync(
|
||||
buffer,
|
||||
offset,
|
||||
chunkSize,
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
if (bytesRead == 0) return 0;
|
||||
|
||||
// 精确限速控制
|
||||
var expectedTime = (double)(_bytesRead + bytesRead) / _maxBytesPerSecond;
|
||||
var actualTime = _stopwatch.Elapsed.TotalSeconds;
|
||||
// 优化2:精确计算需要等待的时间
|
||||
double requiredSeconds = (double)bytesRead / _maxBytesPerSecond;
|
||||
double elapsedSeconds = (double)(_stopwatch.ElapsedTicks - startTicks)
|
||||
/ Stopwatch.Frequency;
|
||||
|
||||
if (actualTime < expectedTime)
|
||||
if (elapsedSeconds < requiredSeconds)
|
||||
{
|
||||
var delay = TimeSpan.FromSeconds(expectedTime - actualTime);
|
||||
await Task.Delay(delay, cancellationToken);
|
||||
double delaySeconds = requiredSeconds - elapsedSeconds;
|
||||
int delayMs = (int)Math.Ceiling(delaySeconds * 1000);
|
||||
|
||||
// 优化3:使用高精度延迟(最小化系统调度误差)
|
||||
await Task.Delay(
|
||||
delayMs > 15 ? delayMs : 15, // 绕过Windows最小15ms调度限制
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
|
||||
Interlocked.Add(ref _bytesRead, bytesRead);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ using System.Net;
|
|||
using Minio.Exceptions;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Security.AccessControl;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
using Microsoft.VisualBasic;
|
||||
|
||||
namespace HeBianGu.App.Disk
|
||||
{
|
||||
|
|
@ -86,7 +86,7 @@ namespace HeBianGu.App.Disk
|
|||
|
||||
// LinkActions.Add(new LinkAction() { Action = "Near", Controller = "Loyout", DisplayName = "最近使用", Logo = "\xe6f3" });
|
||||
LinkActions.Add(new LinkAction()
|
||||
{ Action = "Explorer", Controller = "Loyout", DisplayName = "全部文件", Logo = "" });
|
||||
{ Action = "Explorer", Controller = "Loyout", DisplayName = "全部文件", Logo = "" });
|
||||
// LinkActions.Add(new LinkAction() { Action = "Image", Controller = "Loyout", DisplayName = " 图片", Logo = "" });
|
||||
// LinkActions.Add(new LinkAction() { Action = "Video", Controller = "Loyout", DisplayName = " 视频", Logo = "" });
|
||||
// LinkActions.Add(new LinkAction() { Action = "Document", Controller = "Loyout", DisplayName = " 文档", Logo = "" });
|
||||
|
|
@ -446,35 +446,26 @@ namespace HeBianGu.App.Disk
|
|||
}
|
||||
|
||||
#region
|
||||
|
||||
#endregion
|
||||
|
||||
//上传具体执行
|
||||
private async Task UploadFileToMinIOWithProgress(UpLoadItems ut)
|
||||
{
|
||||
ut.Bool1 = true;
|
||||
// 获取滑块设置的速度限制(转换为字节 / 秒)
|
||||
var speedLimit = (long)1 * 1024 * 1024;
|
||||
//using var limiter = new BandwidthLimiter(bytesPerSecond: speedLimit);
|
||||
//using var handler = new ThrottledHttpClientHandler(limiter);
|
||||
//using var httpClient = new HttpClient(handler)
|
||||
//{
|
||||
// Timeout = Timeout.InfiniteTimeSpan
|
||||
//};
|
||||
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddJsonFile("global.json", optional: false, reloadOnChange: true);
|
||||
// 构建配置
|
||||
var config = builder.Build();
|
||||
|
||||
var handler = new MinIOThrottledHandler(
|
||||
speedLimit,
|
||||
new HttpClientHandler
|
||||
{
|
||||
// 保持 MinIO 必需的 SSL 配置
|
||||
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true
|
||||
});
|
||||
// 获取滑块设置的速度限制(转换为字节 / 秒)
|
||||
var speedLimit = Convert.ToInt64(config["Minio:limitspeed"]);
|
||||
var handler = new MinIOThrottledHandler(speedLimit,
|
||||
new HttpClientHandler
|
||||
{
|
||||
// 保持 MinIO 必需的 SSL 配置
|
||||
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -493,7 +484,6 @@ namespace HeBianGu.App.Disk
|
|||
var mbArgs = new MakeBucketArgs().WithBucket(bucketName);
|
||||
await client.MakeBucketAsync(mbArgs).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
// 关键修改:添加完成信号等待
|
||||
var completionSource = new TaskCompletionSource<bool>();
|
||||
var progress = new Progress<ProgressReport>(progressReport =>
|
||||
|
|
@ -529,11 +519,13 @@ namespace HeBianGu.App.Disk
|
|||
{
|
||||
ut.Value3 = "上传中...";
|
||||
}
|
||||
|
||||
if (progressReport.Percentage == 100)
|
||||
{
|
||||
// 延迟500ms确保MinIO完成处理
|
||||
Task.Delay(500).ContinueWith(_ => { completionSource.TrySetResult(true); });
|
||||
Task.Delay(500).ContinueWith(_ =>
|
||||
{
|
||||
completionSource.TrySetResult(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -541,10 +533,11 @@ namespace HeBianGu.App.Disk
|
|||
// 对对象名称进行URL编码
|
||||
//string objectName = WebUtility.UrlEncode(ut.Value6);
|
||||
var putObjectArgs = new PutObjectArgs()
|
||||
.WithBucket(bucketName)
|
||||
.WithBucket(bucketName)
|
||||
.WithObject(ut.Value6)
|
||||
.WithFileName(ut.Value5)
|
||||
.WithProgress(progress);
|
||||
.WithProgress(progress)
|
||||
.WithObjectSize(5*1024*1024);
|
||||
|
||||
var uploadTask = client.PutObjectAsync(putObjectArgs);
|
||||
await Task.WhenAny(uploadTask, completionSource.Task);
|
||||
|
|
@ -863,7 +856,7 @@ namespace HeBianGu.App.Disk
|
|||
|
||||
if (selectedItems == null || !selectedItems.Any())
|
||||
{
|
||||
MessageBox.Show("请先选择要删除的项目");
|
||||
await MessageProxy.Messager.ShowResult("请先选择要删除的项目");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
"Endpoint": "192.168.10.163:9016",
|
||||
"AccessKey": "I2c35jD6ayApaneyQZyC",
|
||||
"SecretKey": "XHlrNeCHK0xf8y2Fo0K5OKyDeaI2ItfEsFbzQPFk",
|
||||
"BucketName": "demo"
|
||||
"BucketName": "demo",
|
||||
"limitspeed": 1048576
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue