cos_rust_sdk/
config.rs

1//! 配置模块
2
3use crate::error::{CosError, Result};
4use std::time::Duration;
5
6/// COS 客户端配置
7#[derive(Debug, Clone)]
8pub struct Config {
9    /// 腾讯云 SecretId
10    pub secret_id: String,
11    /// 腾讯云 SecretKey
12    pub secret_key: String,
13    /// 地域
14    pub region: String,
15    /// 存储桶名称
16    pub bucket: String,
17    /// 请求超时时间
18    pub timeout: Duration,
19    /// 是否使用 HTTPS
20    pub use_https: bool,
21    /// 自定义域名
22    pub domain: Option<String>,
23    /// 应用 ID(从存储桶名称中提取)
24    pub app_id: Option<String>,
25}
26
27impl Config {
28    /// 创建新的配置
29    pub fn new<S: Into<String>>(
30        secret_id: S,
31        secret_key: S,
32        region: S,
33        bucket: S,
34    ) -> Self {
35        let bucket_name = bucket.into();
36        let app_id = extract_app_id(&bucket_name);
37        
38        Self {
39            secret_id: secret_id.into(),
40            secret_key: secret_key.into(),
41            region: region.into(),
42            bucket: bucket_name,
43            timeout: Duration::from_secs(30),
44            use_https: true,
45            domain: None,
46            app_id,
47        }
48    }
49
50    /// 设置请求超时时间
51    pub fn with_timeout(mut self, timeout: Duration) -> Self {
52        self.timeout = timeout;
53        self
54    }
55
56    /// 设置是否使用 HTTPS
57    pub fn with_https(mut self, use_https: bool) -> Self {
58        self.use_https = use_https;
59        self
60    }
61
62    /// 设置自定义域名
63    pub fn with_domain<S: Into<String>>(mut self, domain: S) -> Self {
64        self.domain = Some(domain.into());
65        self
66    }
67
68    /// 获取存储桶的完整 URL
69    pub fn bucket_url(&self) -> Result<String> {
70        if let Some(ref domain) = self.domain {
71            Ok(format!(
72                "{}://{}",
73                if self.use_https { "https" } else { "http" },
74                domain
75            ))
76        } else {
77            Ok(format!(
78                "{}://{}.cos.{}.myqcloud.com",
79                if self.use_https { "https" } else { "http" },
80                self.bucket,
81                self.region
82            ))
83        }
84    }
85
86    /// 获取服务 URL(用于获取存储桶列表等操作)
87    pub fn service_url(&self) -> String {
88        format!(
89            "{}://cos.{}.myqcloud.com",
90            if self.use_https { "https" } else { "http" },
91            self.region
92        )
93    }
94
95    /// 验证配置
96    pub fn validate(&self) -> Result<()> {
97        if self.secret_id.is_empty() {
98            return Err(CosError::config("SecretId cannot be empty"));
99        }
100        if self.secret_key.is_empty() {
101            return Err(CosError::config("SecretKey cannot be empty"));
102        }
103        if self.region.is_empty() {
104            return Err(CosError::config("Region cannot be empty"));
105        }
106        if self.bucket.is_empty() {
107            return Err(CosError::config("Bucket cannot be empty"));
108        }
109        Ok(())
110    }
111}
112
113/// 从存储桶名称中提取应用 ID
114/// 存储桶名称格式:{bucket-name}-{app-id}
115fn extract_app_id(bucket_name: &str) -> Option<String> {
116    bucket_name
117        .rfind('-')
118        .and_then(|pos| {
119            let app_id = &bucket_name[pos + 1..];
120            if app_id.chars().all(|c| c.is_ascii_digit()) && !app_id.is_empty() {
121                Some(app_id.to_string())
122            } else {
123                None
124            }
125        })
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131
132    #[test]
133    fn test_extract_app_id() {
134        assert_eq!(extract_app_id("mybucket-1234567890"), Some("1234567890".to_string()));
135        assert_eq!(extract_app_id("test-bucket-1234567890"), Some("1234567890".to_string()));
136        assert_eq!(extract_app_id("mybucket"), None);
137        assert_eq!(extract_app_id("mybucket-abc"), None);
138    }
139
140    #[test]
141    fn test_config_validation() {
142        let config = Config::new("id", "key", "region", "bucket-123");
143        assert!(config.validate().is_ok());
144
145        let config = Config::new("", "key", "region", "bucket-123");
146        assert!(config.validate().is_err());
147    }
148}