using Dpz.Core.Infrastructure;

namespace Dpz.Core.Service.ObjectStorage;

/// <summary>
/// COS/S3 对象存储配置
/// </summary>
public class S3ObjectStorageOptions
{
    /// <summary>
    /// 腾讯云 COS 的 S3 兼容访问端点,例如:https://cos.ap-guangzhou.myqcloud.com
    /// </summary>
    public string? Endpoint { get; set; }

    /// <summary>
    /// 腾讯云访问密钥 SecretId
    /// </summary>
    public string? SecretId { get; set; }

    /// <summary>
    /// 腾讯云访问密钥 SecretKey
    /// </summary>
    public string? SecretKey { get; set; }

    /// <summary>
    /// COS 存储桶完整名称,格式通常为 bucket-name-appid
    /// </summary>
    public string? Bucket { get; set; }

    /// <summary>
    /// 文件对外访问域名,可配置为 CDN 域名或 COS 公开访问域名
    /// </summary>
    public string? CdnHost { get; set; }

    /// <summary>
    /// COS 地域,例如 ap-guangzhou;未配置时会从 <see cref="Endpoint"/> 中推断
    /// </summary>
    public string? Region { get; set; }

    /// <summary>
    /// 获取已经校验并补齐默认值的配置
    /// </summary>
    /// <exception cref="InvalidConfigurationException">配置缺失或格式无效</exception>
    public S3ObjectStorageOptions Validate()
    {
        Endpoint = Require(Endpoint, nameof(Endpoint)).TrimEnd('/');
        SecretId = Require(SecretId, nameof(SecretId));
        SecretKey = Require(SecretKey, nameof(SecretKey));
        Bucket = Require(Bucket, nameof(Bucket));
        CdnHost = Require(CdnHost, nameof(CdnHost)).TrimEnd('/');
        Region = string.IsNullOrWhiteSpace(Region) ? InferRegion(Endpoint) : Region.Trim();

        return this;
    }

    private static string Require(string? value, string name)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new InvalidConfigurationException($"S3:{name} configuration is missing");
        }

        return value.Trim();
    }

    private static string InferRegion(string endpoint)
    {
        if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var uri))
        {
            throw new InvalidConfigurationException("S3:Endpoint configuration is invalid");
        }

        var parts = uri.Host.Split('.', StringSplitOptions.RemoveEmptyEntries);
        var cosIndex = Array.FindIndex(
            parts,
            x => x.Equals("cos", StringComparison.OrdinalIgnoreCase)
        );
        if (cosIndex < 0 || cosIndex + 1 >= parts.Length)
        {
            throw new InvalidConfigurationException("S3:Region configuration is missing");
        }

        return parts[cosIndex + 1];
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

代码解释

这是一个用于配置 S3 兼容对象存储服务(特别是腾讯云 COS)的配置类。

主要组成部分

1. 配置属性

该类包含6个配置属性,用于存储对象存储服务的连接信息:

  • Endpoint: S3 服务端点 URL(如 https://cos.ap-guangzhou.myqcloud.com
  • SecretId: 访问密钥 ID
  • SecretKey: 访问密钥
  • Bucket: 存储桶名称(格式如 bucket-name-appid
  • CdnHost: 文件公开访问域名(可以是 CDN 或 COS 直链)
  • Region: 服务地域(如 ap-guangzhou

2. 核心方法

Validate() 方法

  • 功能: 验证配置完整性并返回规范化后的配置对象
  • 处理逻辑:
    • 验证必填字段(Endpoint、SecretId、SecretKey、Bucket、CdnHost)
    • 去除 URL 末尾的斜杠
    • 自动推断 Region(如果未配置)
  • 异常: 配置缺失或无效时抛出 InvalidConfigurationException

Require() 私有方法

  • 验证单个配置项不为空
  • 返回去除首尾空格的值

InferRegion() 私有方法

  • 功能: 从 Endpoint URL 中自动推断地域信息
  • 逻辑:
    1. 解析 Endpoint URL
    2. 分割主机名(如 cos.ap-guangzhou.myqcloud.com
    3. 查找 "cos" 关键字
    4. 提取紧随其后的部分作为 Region(即 ap-guangzhou

使用场景

这个配置类通常在应用启动时从配置文件(如 appsettings.json)中加载,用于初始化 S3/COS 客户端:

{
  "S3": {
    "Endpoint": "https://cos.ap-guangzhou.myqcloud.com",
    "SecretId": "your-secret-id",
    "SecretKey": "your-secret-key",
    "Bucket": "mybucket-1234567890",
    "CdnHost": "https://cdn.example.com"
  }
}

设计亮点

  1. 链式调用: Validate() 返回 this,支持流式编程
  2. 智能推断: 自动从 URL 中提取地域信息,减少配置冗余
  3. 友好错误: 明确指出缺失的配置项名称
评论加载中...