This commit is contained in:
2026-06-02 16:25:57 +08:00
24 changed files with 285 additions and 53 deletions
@@ -1,26 +1,19 @@
using AutoMapper;
using FileService.Application.Ports;
using FileService.Application.StorageContracts;
using FileService.Domain.Entities;
using FileService.Domain.IReposities;
using IM.Commons;
using IM.Commons.IntegrationEvents;
using IM.InitCommon;
using MassTransit;
using MassTransit.Internals;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FileService.Application.UploadFileTask
{
public class UploadFileTaskService(IUploadTaskReposity reposity,
IMapper mapper, IObjectStorageRouter router,
IOptions<StorageOptions> options, IStorageRedisCache redis,
IPublishEndpoint endpoint
IPublishEndpoint endpoint, ILocalChunkStorage localChunkStorage
)
{
private readonly IUploadTaskReposity reposity = reposity;
@@ -29,23 +22,24 @@ namespace FileService.Application.UploadFileTask
private readonly IOptions<StorageOptions> options = options;
private readonly IStorageRedisCache redis = redis;
private readonly IPublishEndpoint endpoint = endpoint;
private readonly ILocalChunkStorage localChunkStorage = localChunkStorage;
private readonly IObjectStoragePort storage = router.Route(options.Value.DefaultProviderCode);
public async Task<Result<TaskInitResponse>> InitTaskAsync(UploadTaskInitCommand command)
{
CancellationToken cancellationToken = CancellationToken.None;
var task = command.ToUploadTask();
var date = DateTime.Now;
var storageOption = options.Value.Providers[options.Value.DefaultProviderCode];
var storage = router.Route(storageOption.ProviderCode);
var initRes = await storage.InitUploadAsync(new StorageContracts.InitiateUploadCommand(
var initUpdateCommand = new StorageContracts.InitiateUploadCommand(
ProviderCode: storageOption.ProviderCode,
Bucket: storageOption.Bucket,
ObjectKey: storageOption.Endpoint,
ContentType:task.ContentType.Value,
ObjectKey: $"{storageOption.LocalRootPath}\\{date.Year}\\{date.Month}\\{date.Day}\\{command.FileName}",
ContentType: task.ContentType.Value,
ContentLength: command.FileSize,
null
), cancellationToken);
null);
var initRes = await storage.InitUploadAsync(initUpdateCommand, cancellationToken);
var res = mapper.Map<TaskInitResponse>(initRes);
res.TaskId = task.Id;
@@ -59,7 +53,7 @@ namespace FileService.Application.UploadFileTask
uploadSessionId: res.UploadSessionId,
bucket: storageOption.Bucket,
region: storageOption.Region,
objectKey: storageOption.Endpoint,
objectKey: initUpdateCommand.ObjectKey,
fileSize: task.FileSize,
totalPartCount: (int)(task.FileSize % storageOption.DefaultPartSizeBytes > 0 ?
(task.FileSize / storageOption.DefaultPartSizeBytes) + 1 :
@@ -78,6 +72,11 @@ namespace FileService.Application.UploadFileTask
return Result.Fail<PresignedUrl>(ResultCode.CHUNK_NOT_FOUND);
}
if(taskCache.TotalPartCount < partNum)
{
return Result.Fail<PresignedUrl>(ResultCode.CHUNK_NOT_FOUND);
}
var presignUrl = await storage.GenerateUploadUrlAsync(new GenerateUploadUrlCommand(
ProviderCode: taskCache.ProviderCode,
Bucket: taskCache.Bucket,
@@ -99,6 +98,12 @@ namespace FileService.Application.UploadFileTask
return Result.Fail<UploadTaskResponse>(ResultCode.CHUNK_NOT_FOUND);
}
if(taskCache.Parts.Count < taskCache.TotalPartCount)
{
return Result.Fail<UploadTaskResponse>(ResultCode.CHUNK_COMBINE_FAIL);
}
var task = await reposity.FindByIdAsync(Guid.Parse(taskCache.TaskId));
//var res = await storage.CompleteUploadAsync(new CompleteUploadCommand(
// ProviderCode: taskCache.ProviderCode,
@@ -116,6 +121,7 @@ namespace FileService.Application.UploadFileTask
await endpoint.Publish(new UploadTaskCompleteEvent()
{
OperatorId = command.userId,
Bucket = taskCache.Bucket,
FileName = task.FileName.ToString(),
ObjectKey = taskCache.ObjectKey,
@@ -126,10 +132,39 @@ namespace FileService.Application.UploadFileTask
ProviderCode = taskCache.ProviderCode,
Region = taskCache.Region,
SessionId = command.UploadSessionId,
TaskId = task.Id
});
TaskId = task.Id,
FileSize = task.FileSize,
ContentType = task.ContentType.ToString(),
CheckSun = task.CheckSum.Value
}, cancellationToken);
return Result.Success(mapper.Map<UploadTaskResponse>(task));
}
public async Task<Result<CompleteUploadResult>> UploadPartAsync(UploadPartCommand command)
{
var taskCache = await redis.GetAsync(command.SessionId);
if(taskCache is null)
{
return Result.Fail<CompleteUploadResult>(ResultCode.CHUNK_NOT_FOUND);
}
await localChunkStorage.SavePartAsync(new SaveLocalPartCommand(
UploadSessionId: command.SessionId,
PartNumber: command.PartNum,
Stream: command.Stream,
ContentLength: command.ContentLength
));
taskCache.AddOrUpdatePart(new StorageContracts.UploadPart(command.PartNum, command.PartNum.ToString(), command.ContentLength));
await redis.SetAsync(taskCache);
var location = new Domain.ValueObjects.StorageLocation(
storageProvider: taskCache.ProviderCode,
bucket: taskCache.Bucket,
objectKey: taskCache.ObjectKey,
region: taskCache.Region
);
return Result.Success(new CompleteUploadResult(location, command.PartNum.ToString(), command.ContentLength));
}
}
}
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FileService.Application.UploadFileTask
{
public record UploadPartCommand(Stream Stream, string SessionId, int PartNum, long ContentLength);
}