Merge remote-tracking branch 'origin/dev2.0' into dev2.0

# Conflicts:
#	ViewModel/Loyout/LoyoutViewModel.cs
#	minio.db
dev2.0
陈伟 2025-04-24 16:48:06 +08:00
commit b42ea1f55c
7 changed files with 175 additions and 38 deletions

View File

@ -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;

View File

@ -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" />

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -11,6 +11,7 @@
"Endpoint": "192.168.10.163:9016",
"AccessKey": "I2c35jD6ayApaneyQZyC",
"SecretKey": "XHlrNeCHK0xf8y2Fo0K5OKyDeaI2ItfEsFbzQPFk",
"BucketName": "demo"
"BucketName": "demo",
"limitspeed": 1048576
}
}

BIN
logo.ico

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 154 KiB