This commit is contained in:
2026-06-02 16:25:57 +08:00
24 changed files with 285 additions and 53 deletions
+4
View File
@@ -2,7 +2,9 @@
using FileService.Domain.IReposities;
using FileService.Infrastructure.Reposites;
using FileService.Infrastructure.Storage;
using IM.Application.Abstractions;
using IM.Commons;
using IM.Infrastructure.Efcore;
using Microsoft.Extensions.DependencyInjection;
namespace FileService.Infrastructure
@@ -17,6 +19,8 @@ namespace FileService.Infrastructure
services.AddScoped<IRedisService, RedisCacheService>();
services.AddScoped<IObjectStorageRouter, ObjectStorageRouter>();
services.AddScoped<IStorageRedisCache,StorageCacheService>();
services.AddScoped<ILocalChunkStorage, LocalStorageAdapter>();
services.AddScoped<IUnitOfWork, EfUnitOfWork<FileDbContext>>();
}
}
}
@@ -8,10 +8,11 @@ using StackExchange.Redis;
namespace FileService.Infrastructure.Storage
{
public class LocalStorageAdapter(IStorageRedisCache redis, IOptions<StorageOptions> options) : IObjectStoragePort
public class LocalStorageAdapter(IStorageRedisCache redis, IOptions<StorageOptions> options) : IObjectStoragePort, ILocalChunkStorage
{
private readonly IStorageRedisCache redis = redis;
private readonly IOptions<StorageOptions> options = options;
private readonly StorageProviderOptions providerOptions = options.Value.Providers[options.Value.DefaultProviderCode];
public string ProviderCode => "Local";
@@ -28,7 +29,7 @@ namespace FileService.Infrastructure.Storage
public async Task<Result<object>> MergeAsync(string sessionId, string objectKey, IReadOnlyList<UploadPart> parts)
{
var rootPath = options.Value.Providers[options.Value.DefaultProviderCode].LocalRootPath;
var tempPath = Path.Combine(rootPath, "temp"); // 项目根目录下 uploads // 最终文件存储路径(这里可以用你之前 ObjectNameGenerator 生成的名字)
var tempPath = Path.Combine(rootPath, sessionId, "parts"); // 项目根目录下 uploads // 最终文件存储路径(这里可以用你之前 ObjectNameGenerator 生成的名字)
var finalPath = Path.Combine(rootPath, objectKey);
var finalDir = Path.GetDirectoryName(finalPath);
Directory.CreateDirectory(finalDir);
@@ -50,7 +51,7 @@ namespace FileService.Infrastructure.Storage
// new("progress", progress.ToString("F2"))
//});
}
var chunkPath = Path.Combine(tempPath, $"{i}.part.tmp");
var chunkPath = Path.Combine(tempPath, $"{i}.part");
if (!File.Exists(chunkPath))
return Result.Fail(ResultCode.CHUNK_NOT_FOUND);
using (var chunkStream = new FileStream(chunkPath, FileMode.Open))
@@ -76,7 +77,7 @@ namespace FileService.Infrastructure.Storage
{
var baseUrl = options.Value.Providers[options.Value.DefaultProviderCode].LocalUploadApiBaseUrl;
return new PresignedUrl(
baseUrl + $"?partNumber={command.PartNumber}",
baseUrl + $"local/parts/upload?sessionId={command.UploadSessionId}&partNumber={command.PartNumber}",
new Dictionary<string, string>(),
ExpiresAt: DateTimeOffset.Now.Add(options.Value.Providers[options.Value.DefaultProviderCode].UploadUrlExpiresIn)
);
@@ -88,5 +89,31 @@ namespace FileService.Infrastructure.Storage
var location = new StorageLocation();
return new InitiateUploadResult(sessionId.ToString(),location);
}
public async Task SavePartAsync(SaveLocalPartCommand command)
{
var path = BuildPartPath(
command.UploadSessionId,
command.PartNumber);
Directory.CreateDirectory(
Path.GetDirectoryName(path)!);
await using var fs = File.Create(path);
await command.Stream.CopyToAsync(fs);
await fs.FlushAsync();
}
private string BuildPartPath(
string uploadSessionId,
int partNumber)
{
return Path.Combine(
providerOptions.LocalRootPath,
uploadSessionId,
"parts",
$"{partNumber}.part");
}
}
}