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 options, IStorageRedisCache redis, IPublishEndpoint endpoint ) { private readonly IUploadTaskReposity reposity = reposity; private readonly IMapper mapper = mapper; private readonly IObjectStorageRouter router = router; private readonly IOptions options = options; private readonly IStorageRedisCache redis = redis; private readonly IPublishEndpoint endpoint = endpoint; private readonly IObjectStoragePort storage = router.Route(options.Value.DefaultProviderCode); public async Task> InitTaskAsync(UploadTaskInitCommand command) { CancellationToken cancellationToken = CancellationToken.None; var task = command.ToUploadTask(); var storageOption = options.Value.Providers[options.Value.DefaultProviderCode]; var storage = router.Route(storageOption.ProviderCode); var initRes = await storage.InitUploadAsync(new StorageContracts.InitiateUploadCommand( ProviderCode: storageOption.ProviderCode, Bucket: storageOption.Bucket, ObjectKey: storageOption.Endpoint, ContentType:task.ContentType.Value, ContentLength: command.FileSize, null ), cancellationToken); var res = mapper.Map(initRes); res.TaskId = task.Id; task.StartUpload(); reposity.Create(task); await redis.SetAsync(new StorageContracts.UploadRuntimeCache( taskId: task.Id.ToString(), providerCode: storage.ProviderCode, uploadSessionId: res.UploadSessionId, bucket: storageOption.Bucket, region: storageOption.Region, objectKey: storageOption.Endpoint, fileSize: task.FileSize, totalPartCount: (int)(task.FileSize % storageOption.DefaultPartSizeBytes > 0 ? (task.FileSize / storageOption.DefaultPartSizeBytes) + 1 : task.FileSize / storageOption.DefaultPartSizeBytes) )); return Result.Success(res); } public async Task> GenerateUrlAsync(string sessionId, int partNum, Guid userId, CancellationToken token = default) { var taskCache = await redis.GetAsync(sessionId); if(taskCache is null) { return Result.Fail(ResultCode.CHUNK_NOT_FOUND); } var presignUrl = await storage.GenerateUploadUrlAsync(new GenerateUploadUrlCommand( ProviderCode: taskCache.ProviderCode, Bucket: taskCache.Bucket, ObjectKey: taskCache.ObjectKey, UploadSessionId: taskCache.UploadSessionId, PartNumber: partNum, ExpiresIn: options.Value.Providers[options.Value.DefaultProviderCode].UploadUrlExpiresIn ), token); return Result.Success(presignUrl); } public async Task> CompleteTaskAsync(UploadTaskCompleteCommand command, CancellationToken cancellationToken = default) { var taskCache = await redis.GetAsync(command.UploadSessionId); if(taskCache is null) { return Result.Fail(ResultCode.CHUNK_NOT_FOUND); } var task = await reposity.FindByIdAsync(Guid.Parse(taskCache.TaskId)); //var res = await storage.CompleteUploadAsync(new CompleteUploadCommand( // ProviderCode: taskCache.ProviderCode, // Bucket: taskCache.Bucket, // Region: taskCache.Region, // ObjectKey: taskCache.ObjectKey, // UploadSessionId: taskCache.UploadSessionId, // Parts: command.Parts // ), cancellationToken); task.CompleteUpload(new Domain.ValueObjects.StorageLocation( taskCache.ProviderCode, taskCache.Bucket, taskCache.ObjectKey, taskCache.Region )); await endpoint.Publish(new UploadTaskCompleteEvent() { Bucket = taskCache.Bucket, FileName = task.FileName.ToString(), ObjectKey = taskCache.ObjectKey, Parts = command.Parts.Select(s => new IM.Commons.IntegrationEvents.UploadPart( s.PartNumber, s.ETag, s.Size, s.Checksum) ).ToList(), ProviderCode = taskCache.ProviderCode, Region = taskCache.Region, SessionId = command.UploadSessionId, TaskId = task.Id }); return Result.Success(mapper.Map(task)); } } }