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.Identity;
using HeBianGu.Systems.Setting; using HeBianGu.Systems.Setting;
using HeBianGu.Window.Link; using HeBianGu.Window.Link;
using Hopetry.Provider;
using Hopetry.Services; using Hopetry.Services;
using SqlSugar; using SqlSugar;
using SystemSetting = FileUploader.Models.SystemSetting; using SystemSetting = FileUploader.Models.SystemSetting;
@ -125,7 +126,9 @@ namespace HeBianGu.App.Disk
//var find = dll.GetTypes().Where(x => typeof(IExplorerService).IsAssignableFrom(x))?.FirstOrDefault(); //var find = dll.GetTypes().Where(x => typeof(IExplorerService).IsAssignableFrom(x))?.FirstOrDefault();
//ServiceRegistry.Instance.Register(typeof(IExplorerService), find); //ServiceRegistry.Instance.Register(typeof(IExplorerService), find);
//services.AddSingleton<IExplorerService, WindowExplorerServiceDemo>(); //services.AddSingleton<IExplorerService, WindowExplorerServiceDemo>();
//minio分片上传修改
PartSizeOverride.OverrideMinioCalculator();
var minioService = services.GetService<MinioService>(); var minioService = services.GetService<MinioService>();
var bucketName = minioService._bucketName; var bucketName = minioService._bucketName;

View File

@ -17,6 +17,10 @@
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
</PropertyGroup> </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> <ItemGroup>
<PackageReference Include="HeBianGu.Base.WpfBase" Version="5.0.0" /> <PackageReference Include="HeBianGu.Base.WpfBase" Version="5.0.0" />
<PackageReference Include="HeBianGu.Control.Adorner" 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.Link" Version="5.0.0" />
<PackageReference Include="HeBianGu.Window.Message" Version="5.0.0" /> <PackageReference Include="HeBianGu.Window.Message" Version="5.0.0" />
<PackageReference Include="HeBianGu.Window.MessageDialog" 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.Data.Sqlite" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" 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; _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; var remaining = _totalLength - _bytesRead;
if (remaining <= 0) return 0; if (remaining <= 0) return 0;
// 动态调整缓冲区大小(优化大文件传输) // 优化1动态调整块大小为限速值的1/2减少调用次数
int chunkSize = (int)Math.Min( int chunkSize = (int)Math.Min(
Math.Min(count, _maxBytesPerSecond / 10), // 每 chunk 不超过限速的 1/10 Math.Min(count, _maxBytesPerSecond / 2),
remaining 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; if (bytesRead == 0) return 0;
// 精确限速控制 // 优化2精确计算需要等待的时间
var expectedTime = (double)(_bytesRead + bytesRead) / _maxBytesPerSecond; double requiredSeconds = (double)bytesRead / _maxBytesPerSecond;
var actualTime = _stopwatch.Elapsed.TotalSeconds; double elapsedSeconds = (double)(_stopwatch.ElapsedTicks - startTicks)
/ Stopwatch.Frequency;
if (actualTime < expectedTime) if (elapsedSeconds < requiredSeconds)
{ {
var delay = TimeSpan.FromSeconds(expectedTime - actualTime); double delaySeconds = requiredSeconds - elapsedSeconds;
await Task.Delay(delay, cancellationToken); int delayMs = (int)Math.Ceiling(delaySeconds * 1000);
// 优化3使用高精度延迟最小化系统调度误差
await Task.Delay(
delayMs > 15 ? delayMs : 15, // 绕过Windows最小15ms调度限制
cancellationToken
);
} }
Interlocked.Add(ref _bytesRead, bytesRead); Interlocked.Add(ref _bytesRead, bytesRead);

View File

@ -27,7 +27,7 @@ using System.Net;
using Minio.Exceptions; using Minio.Exceptions;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Security.AccessControl; using System.Security.AccessControl;
using System.Windows.Forms.VisualStyles; using Microsoft.VisualBasic;
namespace HeBianGu.App.Disk 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 = "Near", Controller = "Loyout", DisplayName = "最近使用", Logo = "\xe6f3" });
LinkActions.Add(new LinkAction() 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 = "Image", Controller = "Loyout", DisplayName = " 图片", Logo = "" });
// LinkActions.Add(new LinkAction() { Action = "Video", Controller = "Loyout", DisplayName = " 视频", Logo = "" }); // LinkActions.Add(new LinkAction() { Action = "Video", Controller = "Loyout", DisplayName = " 视频", Logo = "" });
// LinkActions.Add(new LinkAction() { Action = "Document", Controller = "Loyout", DisplayName = " 文档", Logo = "" }); // LinkActions.Add(new LinkAction() { Action = "Document", Controller = "Loyout", DisplayName = " 文档", Logo = "" });
@ -446,35 +446,26 @@ namespace HeBianGu.App.Disk
} }
#region #region
#endregion #endregion
//上传具体执行 //上传具体执行
private async Task UploadFileToMinIOWithProgress(UpLoadItems ut) private async Task UploadFileToMinIOWithProgress(UpLoadItems ut)
{ {
ut.Bool1 = true; 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() var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory()) .SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("global.json", optional: false, reloadOnChange: true); .AddJsonFile("global.json", optional: false, reloadOnChange: true);
// 构建配置 // 构建配置
var config = builder.Build(); var config = builder.Build();
// 获取滑块设置的速度限制(转换为字节 / 秒)
var handler = new MinIOThrottledHandler( var speedLimit = Convert.ToInt64(config["Minio:limitspeed"]);
speedLimit, var handler = new MinIOThrottledHandler(speedLimit,
new HttpClientHandler new HttpClientHandler
{ {
// 保持 MinIO 必需的 SSL 配置 // 保持 MinIO 必需的 SSL 配置
ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true ServerCertificateCustomValidationCallback = (msg, cert, chain, errors) => true
}); });
try try
{ {
@ -493,7 +484,6 @@ namespace HeBianGu.App.Disk
var mbArgs = new MakeBucketArgs().WithBucket(bucketName); var mbArgs = new MakeBucketArgs().WithBucket(bucketName);
await client.MakeBucketAsync(mbArgs).ConfigureAwait(false); await client.MakeBucketAsync(mbArgs).ConfigureAwait(false);
} }
// 关键修改:添加完成信号等待 // 关键修改:添加完成信号等待
var completionSource = new TaskCompletionSource<bool>(); var completionSource = new TaskCompletionSource<bool>();
var progress = new Progress<ProgressReport>(progressReport => var progress = new Progress<ProgressReport>(progressReport =>
@ -529,11 +519,13 @@ namespace HeBianGu.App.Disk
{ {
ut.Value3 = "上传中..."; ut.Value3 = "上传中...";
} }
if (progressReport.Percentage == 100) if (progressReport.Percentage == 100)
{ {
// 延迟500ms确保MinIO完成处理 // 延迟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编码 // 对对象名称进行URL编码
//string objectName = WebUtility.UrlEncode(ut.Value6); //string objectName = WebUtility.UrlEncode(ut.Value6);
var putObjectArgs = new PutObjectArgs() var putObjectArgs = new PutObjectArgs()
.WithBucket(bucketName) .WithBucket(bucketName)
.WithObject(ut.Value6) .WithObject(ut.Value6)
.WithFileName(ut.Value5) .WithFileName(ut.Value5)
.WithProgress(progress); .WithProgress(progress)
.WithObjectSize(5*1024*1024);
var uploadTask = client.PutObjectAsync(putObjectArgs); var uploadTask = client.PutObjectAsync(putObjectArgs);
await Task.WhenAny(uploadTask, completionSource.Task); await Task.WhenAny(uploadTask, completionSource.Task);
@ -863,7 +856,7 @@ namespace HeBianGu.App.Disk
if (selectedItems == null || !selectedItems.Any()) if (selectedItems == null || !selectedItems.Any())
{ {
MessageBox.Show("请先选择要删除的项目"); await MessageProxy.Messager.ShowResult("请先选择要删除的项目");
return; return;
} }

View File

@ -11,6 +11,7 @@
"Endpoint": "192.168.10.163:9016", "Endpoint": "192.168.10.163:9016",
"AccessKey": "I2c35jD6ayApaneyQZyC", "AccessKey": "I2c35jD6ayApaneyQZyC",
"SecretKey": "XHlrNeCHK0xf8y2Fo0K5OKyDeaI2ItfEsFbzQPFk", "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