translation-lib 0.1.1

A simple and efficient translation library for Rust
Documentation
//! 配置管理模块
//!
//! 提供简化的翻译配置管理功能。

use crate::error::{TranslationError, TranslationResult};
use serde::{Deserialize, Serialize};
use std::time::Duration;

/// 翻译配置
///
/// 简化的配置结构,包含翻译所需的基本参数。
///
/// # 示例
///
/// ```rust
/// use translation_lib::TranslationConfig;
/// use std::time::Duration;
///
/// let config = TranslationConfig {
///     api_url: "YOUR_API_URL".to_string(),
///     api_key: Some("YOUR_API_KEY".to_string()),
///     timeout: Duration::from_secs(30),
///     max_concurrent_requests: 5,
///     enable_cache: true,
/// };
/// ```
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TranslationConfig {
    /// 翻译API地址
    pub api_url: String,

    /// API密钥(可选)
    pub api_key: Option<String>,

    /// 请求超时时间
    #[serde(with = "serde_duration")]
    pub timeout: Duration,

    /// 最大并发请求数
    pub max_concurrent_requests: usize,

    /// 是否启用缓存
    pub enable_cache: bool,
}

impl Default for TranslationConfig {
    fn default() -> Self {
        Self {
            api_url: "https://api.example.com/translate".to_string(),
            api_key: None,
            timeout: Duration::from_secs(30),
            max_concurrent_requests: 10,
            enable_cache: true,
        }
    }
}

impl TranslationConfig {
    /// 创建新的配置
    pub fn new(api_url: String) -> Self {
        Self {
            api_url,
            ..Default::default()
        }
    }

    /// 设置API密钥
    pub fn with_api_key(mut self, api_key: String) -> Self {
        self.api_key = Some(api_key);
        self
    }

    /// 设置超时时间
    pub fn with_timeout(mut self, timeout: Duration) -> Self {
        self.timeout = timeout;
        self
    }

    /// 设置最大并发数
    pub fn with_max_concurrent(mut self, max_concurrent: usize) -> Self {
        self.max_concurrent_requests = max_concurrent;
        self
    }

    /// 设置是否启用缓存
    pub fn with_cache(mut self, enable_cache: bool) -> Self {
        self.enable_cache = enable_cache;
        self
    }

    /// 从环境变量加载配置
    pub fn from_env() -> TranslationResult<Self> {
        let api_url = std::env::var("TRANSLATION_API_URL")
            .unwrap_or_else(|_| "https://api.example.com/translate".to_string());

        let api_key = std::env::var("TRANSLATION_API_KEY").ok();

        let timeout_secs = std::env::var("TRANSLATION_TIMEOUT")
            .unwrap_or_else(|_| "30".to_string())
            .parse::<u64>()
            .map_err(|_| TranslationError::Config("Invalid timeout value".to_string()))?;

        let max_concurrent = std::env::var("TRANSLATION_MAX_CONCURRENT")
            .unwrap_or_else(|_| "10".to_string())
            .parse::<usize>()
            .map_err(|_| TranslationError::Config("Invalid max_concurrent value".to_string()))?;

        let enable_cache = std::env::var("TRANSLATION_ENABLE_CACHE")
            .unwrap_or_else(|_| "true".to_string())
            .parse::<bool>()
            .map_err(|_| TranslationError::Config("Invalid enable_cache value".to_string()))?;

        Ok(Self {
            api_url,
            api_key,
            timeout: Duration::from_secs(timeout_secs),
            max_concurrent_requests: max_concurrent,
            enable_cache,
        })
    }

    /// 验证配置
    pub fn validate(&self) -> TranslationResult<()> {
        if self.api_url.is_empty() {
            return Err(TranslationError::Config(
                "API URL cannot be empty".to_string(),
            ));
        }

        if !self.api_url.starts_with("http://") && !self.api_url.starts_with("https://") {
            return Err(TranslationError::Config(
                "API URL must start with http:// or https://".to_string(),
            ));
        }

        if self.max_concurrent_requests == 0 {
            return Err(TranslationError::Config(
                "max_concurrent_requests must be greater than 0".to_string(),
            ));
        }

        if self.timeout.as_secs() == 0 {
            return Err(TranslationError::Config(
                "timeout must be greater than 0".to_string(),
            ));
        }

        Ok(())
    }
}

// Duration序列化辅助模块
mod serde_duration {
    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    use std::time::Duration;

    pub fn serialize<S>(duration: &Duration, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        duration.as_secs().serialize(serializer)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Duration, D::Error>
    where
        D: Deserializer<'de>,
    {
        let secs = u64::deserialize(deserializer)?;
        Ok(Duration::from_secs(secs))
    }
}