feat: implement Aliyun multipart storage operations

Co-authored-by: Velik <hongochai10@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-02-23 11:50:40 +00:00
parent f4f5d9d576
commit 22dcc97ba9
2 changed files with 116 additions and 13 deletions

View File

@@ -93,7 +93,9 @@ public class CompleteMultipartUploadCommandHandler
fileSizeBytes: upload.TotalSizeBytes,
userId: upload.UserId,
provider: provider.ProviderType,
accessLevel: FileAccessLevel.Private // TODO: Get from upload metadata
// EN: Multipart aggregate currently does not persist access-level metadata.
// VI: Aggregate multipart hiện chưa lưu metadata access-level.
accessLevel: FileAccessLevel.Private
);
await _context.StorageFiles.AddAsync(storageFile, cancellationToken);

View File

@@ -3,6 +3,8 @@ using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using StorageService.Domain.AggregatesModel.FileAggregate;
using StorageService.Infrastructure.Configuration;
using OssPartETag = Aliyun.OSS.PartETag;
using System.Linq;
namespace StorageService.Infrastructure.Storage;
@@ -171,9 +173,33 @@ public class AliyunOssStorageProvider : IStorageProvider
string contentType,
CancellationToken cancellationToken = default)
{
// TODO: Implement using Aliyun OSS InitiateMultipartUpload
_logger.LogWarning("Multipart upload for Aliyun OSS not yet implemented");
throw new NotImplementedException("Multipart upload will be implemented in next phase");
try
{
EnsureBucketExistsAsync(bucketName, cancellationToken).Wait(cancellationToken);
var request = new InitiateMultipartUploadRequest(bucketName, objectKey)
{
ContentType = contentType
};
var response = _ossClient.InitiateMultipartUpload(request);
_logger.LogInformation(
"Initiated Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
bucketName,
objectKey,
response.UploadId);
return Task.FromResult(response.UploadId);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to initiate Aliyun OSS multipart upload: {Bucket}/{ObjectKey}",
bucketName,
objectKey);
throw;
}
}
/// <inheritdoc />
@@ -185,9 +211,38 @@ public class AliyunOssStorageProvider : IStorageProvider
Stream dataStream,
CancellationToken cancellationToken = default)
{
// TODO: Implement using Aliyun OSS UploadPart
_logger.LogWarning("Upload part for Aliyun OSS not yet implemented");
throw new NotImplementedException("Upload part will be implemented in next phase");
try
{
var request = new UploadPartRequest(bucketName, objectKey, uploadId)
{
InputStream = dataStream,
PartSize = dataStream.Length,
PartNumber = partNumber
};
var response = _ossClient.UploadPart(request);
var etag = response.PartETag.ETag;
_logger.LogInformation(
"Uploaded Aliyun OSS multipart part: {Bucket}/{ObjectKey}, UploadId: {UploadId}, Part: {PartNumber}",
bucketName,
objectKey,
uploadId,
partNumber);
return Task.FromResult(etag);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to upload Aliyun OSS multipart part: {Bucket}/{ObjectKey}, UploadId: {UploadId}, Part: {PartNumber}",
bucketName,
objectKey,
uploadId,
partNumber);
throw;
}
}
/// <inheritdoc />
@@ -198,9 +253,35 @@ public class AliyunOssStorageProvider : IStorageProvider
List<PartETag> parts,
CancellationToken cancellationToken = default)
{
// TODO: Implement using Aliyun OSS CompleteMultipartUpload
_logger.LogWarning("Complete multipart upload for Aliyun OSS not yet implemented");
throw new NotImplementedException("Complete multipart upload will be implemented in next phase");
try
{
var request = new CompleteMultipartUploadRequest(bucketName, objectKey, uploadId);
var orderedParts = parts
.OrderBy(part => part.PartNumber)
.Select(part => new OssPartETag(part.PartNumber, part.ETag))
.ToList();
request.PartETags.AddRange(orderedParts);
_ossClient.CompleteMultipartUpload(request);
_logger.LogInformation(
"Completed Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
bucketName,
objectKey,
uploadId);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to complete Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
bucketName,
objectKey,
uploadId);
throw;
}
return Task.CompletedTask;
}
/// <inheritdoc />
@@ -210,8 +291,28 @@ public class AliyunOssStorageProvider : IStorageProvider
string uploadId,
CancellationToken cancellationToken = default)
{
// TODO: Implement using Aliyun OSS AbortMultipartUpload
_logger.LogWarning("Abort multipart upload for Aliyun OSS not yet implemented");
throw new NotImplementedException("Abort multipart upload will be implemented in next phase");
try
{
var request = new AbortMultipartUploadRequest(bucketName, objectKey, uploadId);
_ossClient.AbortMultipartUpload(request);
_logger.LogInformation(
"Aborted Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
bucketName,
objectKey,
uploadId);
}
catch (Exception ex)
{
_logger.LogError(
ex,
"Failed to abort Aliyun OSS multipart upload: {Bucket}/{ObjectKey}, UploadId: {UploadId}",
bucketName,
objectKey,
uploadId);
throw;
}
return Task.CompletedTask;
}
}