use crate::error::{CosError, Result};
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Config {
pub secret_id: String,
pub secret_key: String,
pub region: String,
pub bucket: String,
pub timeout: Duration,
pub use_https: bool,
pub domain: Option<String>,
pub app_id: Option<String>,
}
impl Config {
pub fn new<S: Into<String>>(
secret_id: S,
secret_key: S,
region: S,
bucket: S,
) -> Self {
let bucket_name = bucket.into();
let app_id = extract_app_id(&bucket_name);
Self {
secret_id: secret_id.into(),
secret_key: secret_key.into(),
region: region.into(),
bucket: bucket_name,
timeout: Duration::from_secs(30),
use_https: true,
domain: None,
app_id,
}
}
pub fn with_timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
pub fn with_https(mut self, use_https: bool) -> Self {
self.use_https = use_https;
self
}
pub fn with_domain<S: Into<String>>(mut self, domain: S) -> Self {
self.domain = Some(domain.into());
self
}
pub fn bucket_url(&self) -> Result<String> {
if let Some(ref domain) = self.domain {
Ok(format!(
"{}://{}",
if self.use_https { "https" } else { "http" },
domain
))
} else {
Ok(format!(
"{}://{}.cos.{}.myqcloud.com",
if self.use_https { "https" } else { "http" },
self.bucket,
self.region
))
}
}
pub fn service_url(&self) -> String {
format!(
"{}://cos.{}.myqcloud.com",
if self.use_https { "https" } else { "http" },
self.region
)
}
pub fn validate(&self) -> Result<()> {
if self.secret_id.is_empty() {
return Err(CosError::config("SecretId cannot be empty"));
}
if self.secret_key.is_empty() {
return Err(CosError::config("SecretKey cannot be empty"));
}
if self.region.is_empty() {
return Err(CosError::config("Region cannot be empty"));
}
if self.bucket.is_empty() {
return Err(CosError::config("Bucket cannot be empty"));
}
Ok(())
}
}
fn extract_app_id(bucket_name: &str) -> Option<String> {
bucket_name
.rfind('-')
.and_then(|pos| {
let app_id = &bucket_name[pos + 1..];
if app_id.chars().all(|c| c.is_ascii_digit()) && !app_id.is_empty() {
Some(app_id.to_string())
} else {
None
}
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_app_id() {
assert_eq!(extract_app_id("mybucket-1234567890"), Some("1234567890".to_string()));
assert_eq!(extract_app_id("test-bucket-1234567890"), Some("1234567890".to_string()));
assert_eq!(extract_app_id("mybucket"), None);
assert_eq!(extract_app_id("mybucket-abc"), None);
}
#[test]
fn test_config_validation() {
let config = Config::new("id", "key", "region", "bucket-123");
assert!(config.validate().is_ok());
let config = Config::new("", "key", "region", "bucket-123");
assert!(config.validate().is_err());
}
}