UploadMapFileCommandHandler.cs 4.61 KB
using MassTransit;
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.MessageBus.Commands;
using Rcs.Application.Services;
using Rcs.Domain.Entities;
using Rcs.Domain.Repositories;

namespace Rcs.Infrastructure.MessageBus.Handlers.Commands;

/// <summary>
/// 上传地图文件命令处理器
/// </summary>
public class UploadMapFileCommandHandler : IConsumer<UploadMapFileCommand>
{
    private readonly ILogger<UploadMapFileCommandHandler> _logger;
    private readonly IFileStorageService _fileStorageService;
    private readonly IMapFileRepository _mapFileRepository;
    private readonly IMapRepository _mapRepository;

    // 允许的文件类型(地图图片文件 + PGM地图文件)
    private static readonly string[] AllowedExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".webp", ".pgm" };
    
    // 最大文件大小:50MB
    private const long MaxFileSize = 50 * 1024 * 1024;

    public UploadMapFileCommandHandler(
        ILogger<UploadMapFileCommandHandler> logger,
        IFileStorageService fileStorageService,
        IMapFileRepository mapFileRepository,
        IMapRepository mapRepository)
    {
        _logger = logger;
        _fileStorageService = fileStorageService;
        _mapFileRepository = mapFileRepository;
        _mapRepository = mapRepository;
    }

    public async Task Consume(ConsumeContext<UploadMapFileCommand> context)
    {
        var command = context.Message;

        try
        {
            // 验证地图ID
            if (!Guid.TryParse(command.MapId, out Guid mapId))
            {
                await context.RespondAsync(ApiResponse.Failed("无效的地图ID格式"));
                return;
            }

            // 验证地图是否存在
            var map = await _mapRepository.GetByIdAsync(mapId, context.CancellationToken);
            if (map == null)
            {
                await context.RespondAsync(ApiResponse.Failed($"未找到ID为 {mapId} 的地图"));
                return;
            }

            // 验证文件
            var (isValid, errorMessage) = _fileStorageService.ValidateFile(
                command.FileName,
                command.FileSize,
                AllowedExtensions, 
                MaxFileSize);

            if (!isValid)
            {
                await context.RespondAsync(ApiResponse.Failed(errorMessage));
                return;
            }

            // 检查该地图是否已经有文件,如果有则删除旧文件
            var existingMapFile = await _mapFileRepository.GetByMapIdAsync(mapId, context.CancellationToken);
            if (existingMapFile != null)
            {
                // 删除旧的物理文件
                await _fileStorageService.DeleteFileAsync(existingMapFile.FilePath, context.CancellationToken);
                // 删除旧的数据库记录
                await _mapFileRepository.DeleteAsync(existingMapFile, context.CancellationToken);
                await _mapFileRepository.SaveChangesAsync(context.CancellationToken);
            }

            // 保存文件到磁盘
            var fileResult = await _fileStorageService.SaveFileAsync(
                command.FileStream,
                command.FileName,
                "maps", 
                context.CancellationToken);

            // 创建地图文件实体
            var mapFile = new MapFile
            {
                Id = Guid.NewGuid().ToString(),
                FileName = fileResult.FileName,
                FileSize = fileResult.FileSize,
                FilePath = fileResult.RelativePath,
                Opacity = command.Opacity,
                Scale = command.Scale,
                Rotation = command.Rotation,
                OffsetX = command.OffsetX,
                OffsetY = command.OffsetY,
                UploadTime = DateTime.Now,
                MapId = mapId,
                Active = true
            };

            // 保存到数据库
            await _mapFileRepository.AddAsync(mapFile, context.CancellationToken);
            await _mapFileRepository.SaveChangesAsync(context.CancellationToken);

            _logger.LogInformation(
                "地图文件上传成功: MapId={MapId}, FileName={FileName}, Size={Size}", 
                mapId, 
                command.FileName, 
                fileResult.FileSize);

            await context.RespondAsync(ApiResponse.Successful("文件上传成功"));
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "上传地图文件失败: MapId={MapId}", command.MapId);
            await context.RespondAsync(ApiResponse.Failed($"上传失败: {ex.Message}"));
        }
    }
}