1111
This commit is contained in:
@@ -33,6 +33,23 @@ namespace FileService.Application.StorageContracts
|
||||
|
||||
public Dictionary<int, UploadPart> Parts { get; init; } = new();
|
||||
|
||||
public UploadRuntimeCache(string taskId, string providerCode,
|
||||
string uploadSessionId, string bucket, string region,
|
||||
string objectKey, long fileSize, int totalPartCount,
|
||||
DateTimeOffset? expireAt = null)
|
||||
{
|
||||
TaskId = taskId;
|
||||
ProviderCode = providerCode;
|
||||
UploadSessionId = uploadSessionId;
|
||||
Bucket = bucket;
|
||||
Region = region;
|
||||
ObjectKey = objectKey;
|
||||
FileSize = fileSize;
|
||||
TotalPartCount = totalPartCount;
|
||||
ExpireAt = expireAt ?? DateTime.MaxValue;
|
||||
CreatedAt = DateTime.Now;
|
||||
}
|
||||
|
||||
public void AddOrUpdatePart(UploadPart part)
|
||||
{
|
||||
Parts[part.PartNumber] = part;
|
||||
|
||||
@@ -14,26 +14,23 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace FileService.Application.UploadFileTask
|
||||
{
|
||||
public class UploadFileTaskService
|
||||
public class UploadFileTaskService(IUploadTaskReposity reposity,
|
||||
IMapper mapper, IObjectStorageRouter router,
|
||||
IOptions<StorageOptions> options, IStorageRedisCache redis)
|
||||
{
|
||||
private readonly IUploadTaskReposity reposity;
|
||||
private readonly IMapper mapper;
|
||||
private readonly IObjectStorageRouter router;
|
||||
private readonly IOptions<StorageOptions> options;
|
||||
|
||||
public UploadFileTaskService(IUploadTaskReposity reposity, IMapper mapper, IObjectStorageRouter router, IOptions<StorageOptions> options)
|
||||
{
|
||||
this.reposity = reposity;
|
||||
this.mapper = mapper;
|
||||
this.router = router;
|
||||
this.options = options;
|
||||
}
|
||||
private readonly IUploadTaskReposity reposity = reposity;
|
||||
private readonly IMapper mapper = mapper;
|
||||
private readonly IObjectStorageRouter router = router;
|
||||
private readonly IOptions<StorageOptions> options = options;
|
||||
private readonly IStorageRedisCache redis = redis;
|
||||
|
||||
public async Task<Result<TaskInitResponse>> InitTaskAsync(UploadTaskInitCommand command)
|
||||
{
|
||||
CancellationToken cancellationToken = CancellationToken.None;
|
||||
var task = command.ToUploadTask();
|
||||
var storage = router.Route(options.Value.ProviderCode);
|
||||
|
||||
var storageOption = options.Value.Providers[options.Value.DefaultProviderCode];
|
||||
var storage = router.Route(storageOption.ProviderCode);
|
||||
var initRes = await storage.InitUploadAsync(new StorageContracts.InitiateUploadCommand(
|
||||
ProviderCode: options.Value.ProviderCode,
|
||||
Bucket: options.Value.Bucket,
|
||||
@@ -45,6 +42,20 @@ namespace FileService.Application.UploadFileTask
|
||||
|
||||
var res = mapper.Map<TaskInitResponse>(initRes);
|
||||
res.TaskId = task.Id;
|
||||
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);
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using FileService.Application.UploadFileTask;
|
||||
using FileService.Infrastructure;
|
||||
using IM.ASPNETCore;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Security.Claims;
|
||||
|
||||
namespace FileService.WebApi.Controllers.FileTask
|
||||
{
|
||||
@@ -9,11 +13,27 @@ namespace FileService.WebApi.Controllers.FileTask
|
||||
[ApiController]
|
||||
public class FileTaskController : ControllerBase
|
||||
{
|
||||
private readonly UploadFileTaskService service;
|
||||
|
||||
public FileTaskController(UploadFileTaskService service)
|
||||
{
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
[HttpPost("init")]
|
||||
public async Task<IActionResult> Init()
|
||||
[UnitOfWork(typeof(FileDbContext))]
|
||||
public async Task<IActionResult> Init(FileTaskInitRequest request)
|
||||
{
|
||||
|
||||
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||
var res = await service.InitTaskAsync(new UploadTaskInitCommand(
|
||||
UploaderId: Guid.Parse(userId),
|
||||
ConversationId: request.ConversationId,
|
||||
FileName: request.FileName,
|
||||
FileSize: request.FileSize,
|
||||
contentType: request.ContentType,
|
||||
checkSum: request.CheckSum
|
||||
));
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace FileService.WebApi.Controllers.FileTask
|
||||
{
|
||||
public class FileTaskInitRequest
|
||||
{
|
||||
public Guid ConversationId { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public long FileSize { get; set; }
|
||||
public string ContentType { get; set; }
|
||||
public string CheckSum { get; set; }
|
||||
|
||||
}
|
||||
public class FileTaskInitRequestValidator: AbstractValidator<FileTaskInitRequest>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,12 @@ using System.Threading.Tasks;
|
||||
namespace IM.InitCommon
|
||||
{
|
||||
public class StorageOptions
|
||||
{
|
||||
public string DefaultProviderCode { get; set; }
|
||||
public Dictionary<string, StorageProviderOptions> Providers { get; set; }
|
||||
}
|
||||
|
||||
public class StorageProviderOptions
|
||||
{
|
||||
public string ProviderCode { get; init; } = default!;
|
||||
|
||||
@@ -37,6 +43,7 @@ namespace IM.InitCommon
|
||||
public long MaxObjectSizeBytes { get; init; } = 1024L * 1024 * 1024;
|
||||
|
||||
public int MinPartSizeBytes { get; init; } = 5 * 1024 * 1024;
|
||||
public int DefaultPartSizeBytes { get; init; } = 5 * 1024 * 1024;
|
||||
|
||||
public int MaxPartCount { get; init; } = 10_000;
|
||||
}
|
||||
|
||||
@@ -65,8 +65,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileService.WebApi", "FileS
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileService.Application", "FileService.Application\FileService.Application.csproj", "{A05B43F3-3391-4ACC-A8BD-B9B7AEABC90B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MessageService (2)", "MessageService (2)", "{9FA3D6BD-1EC1-3BA5-80CB-CE02773A58D5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
||||
+26
-40
@@ -1,15 +1,19 @@
|
||||
pipeline {
|
||||
agent { label '构建机1' }
|
||||
agent any
|
||||
|
||||
parameters {
|
||||
booleanParam(
|
||||
name: 'FORCE_BUILD_ALL',
|
||||
defaultValue: false,
|
||||
description: '强制构建所有镜像'
|
||||
)
|
||||
}
|
||||
|
||||
environment {
|
||||
IMAGE_PREFIX = "im"
|
||||
IMAGE_TAG = "${BUILD_NUMBER}"
|
||||
|
||||
DOCKER_BUILDKIT = "1"
|
||||
|
||||
// 如果你有 Harbor,可以改成:
|
||||
// REGISTRY = "harbor.xxx.com/im"
|
||||
REGISTRY = "reg.nxsir.cn/im"
|
||||
REGISTRY = ""
|
||||
}
|
||||
|
||||
stages {
|
||||
@@ -22,21 +26,23 @@ pipeline {
|
||||
stage('检测变更') {
|
||||
steps {
|
||||
script {
|
||||
def diffCmd = '''
|
||||
if git rev-parse HEAD~1 >/dev/null 2>&1; then
|
||||
git diff --name-only HEAD~1 HEAD
|
||||
else
|
||||
git ls-files
|
||||
fi
|
||||
'''
|
||||
if (params.FORCE_BUILD_ALL || env.BUILD_NUMBER == '1') {
|
||||
env.BUILD_ALL = "true"
|
||||
env.CHANGED_FILES = "FIRST_BUILD"
|
||||
echo "首次构建或手动强制构建,构建全部镜像"
|
||||
} else {
|
||||
env.BUILD_ALL = "false"
|
||||
|
||||
env.CHANGED_FILES = sh(
|
||||
script: diffCmd,
|
||||
returnStdout: true
|
||||
).trim()
|
||||
env.CHANGED_FILES = sh(
|
||||
script: '''
|
||||
git diff --name-only HEAD~1 HEAD
|
||||
''',
|
||||
returnStdout: true
|
||||
).trim()
|
||||
|
||||
echo "变更文件:"
|
||||
echo env.CHANGED_FILES
|
||||
echo "变更文件:"
|
||||
echo env.CHANGED_FILES
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +135,7 @@ pipeline {
|
||||
def changedFiles = env.CHANGED_FILES.split("\\n") as List
|
||||
|
||||
services.each { svc ->
|
||||
def needBuild = changedFiles.any { file ->
|
||||
def needBuild = env.BUILD_ALL == "true" || changedFiles.any { file ->
|
||||
svc.paths.any { path ->
|
||||
file.startsWith(path)
|
||||
}
|
||||
@@ -147,16 +153,6 @@ pipeline {
|
||||
-t ${latestName} \
|
||||
-f ${svc.dockerfile} .
|
||||
"""
|
||||
|
||||
if (env.REGISTRY?.trim()) {
|
||||
sh """
|
||||
docker tag ${imageName} ${REGISTRY}/${svc.image}:${IMAGE_TAG}
|
||||
docker tag ${latestName} ${REGISTRY}/${svc.image}:latest
|
||||
|
||||
docker push ${REGISTRY}/${svc.image}:${IMAGE_TAG}
|
||||
docker push ${REGISTRY}/${svc.image}:latest
|
||||
"""
|
||||
}
|
||||
} else {
|
||||
echo "跳过构建:${svc.name},没有相关代码变更"
|
||||
}
|
||||
@@ -165,14 +161,4 @@ pipeline {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
success {
|
||||
echo "流水线执行成功"
|
||||
}
|
||||
|
||||
failure {
|
||||
echo "流水线执行失败"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user