goldenpay 0.3.0

Production-oriented Rust SDK for FunPay automation
Documentation
use std::path::PathBuf;
use std::time::Duration;

#[derive(Debug, Clone)]
pub struct GoldenPayConfig {
    pub golden_key: String,
    pub base_url: String,
    pub user_agent: String,
    pub poll_interval: Duration,
    pub retry: RetryPolicy,
    pub proxy: Option<String>,
    pub state_path: Option<PathBuf>,
}

#[derive(Debug, Clone)]
pub struct RetryPolicy {
    pub max_attempts: u32,
    pub base_delay: Duration,
}

#[derive(Debug, Clone, Default)]
pub struct GoldenPayConfigBuilder {
    golden_key: Option<String>,
    base_url: Option<String>,
    user_agent: Option<String>,
    poll_interval: Option<Duration>,
    retry: Option<RetryPolicy>,
    proxy: Option<String>,
    state_path: Option<PathBuf>,
}

impl GoldenPayConfig {
    pub fn new(golden_key: impl Into<String>) -> Self {
        Self {
            golden_key: golden_key.into(),
            ..Self::default()
        }
    }

    pub fn builder() -> GoldenPayConfigBuilder {
        GoldenPayConfigBuilder::default()
    }

    pub fn with_proxy(mut self, proxy: impl Into<String>) -> Self {
        self.proxy = Some(proxy.into());
        self
    }

    pub fn with_state_path(mut self, path: impl Into<PathBuf>) -> Self {
        self.state_path = Some(path.into());
        self
    }
}

impl Default for GoldenPayConfig {
    fn default() -> Self {
        Self {
            golden_key: String::new(),
            base_url: "https://funpay.com".to_string(),
            user_agent: format!("goldenpay/{}", env!("CARGO_PKG_VERSION")),
            poll_interval: Duration::from_secs(2),
            retry: RetryPolicy::default(),
            proxy: None,
            state_path: None,
        }
    }
}

impl Default for RetryPolicy {
    fn default() -> Self {
        Self {
            max_attempts: 3,
            base_delay: Duration::from_millis(300),
        }
    }
}

impl RetryPolicy {
    pub fn new(max_attempts: u32, base_delay: Duration) -> Self {
        Self {
            max_attempts,
            base_delay,
        }
    }
}

impl GoldenPayConfigBuilder {
    pub fn golden_key(mut self, golden_key: impl Into<String>) -> Self {
        self.golden_key = Some(golden_key.into());
        self
    }

    pub fn base_url(mut self, base_url: impl Into<String>) -> Self {
        self.base_url = Some(base_url.into());
        self
    }

    pub fn user_agent(mut self, user_agent: impl Into<String>) -> Self {
        self.user_agent = Some(user_agent.into());
        self
    }

    pub fn poll_interval(mut self, poll_interval: Duration) -> Self {
        self.poll_interval = Some(poll_interval);
        self
    }

    pub fn retry_policy(mut self, retry: RetryPolicy) -> Self {
        self.retry = Some(retry);
        self
    }

    pub fn proxy(mut self, proxy: impl Into<String>) -> Self {
        self.proxy = Some(proxy.into());
        self
    }

    pub fn state_path(mut self, path: impl Into<PathBuf>) -> Self {
        self.state_path = Some(path.into());
        self
    }

    pub fn build(self) -> GoldenPayConfig {
        let defaults = GoldenPayConfig::default();
        GoldenPayConfig {
            golden_key: self.golden_key.unwrap_or(defaults.golden_key),
            base_url: self.base_url.unwrap_or(defaults.base_url),
            user_agent: self.user_agent.unwrap_or(defaults.user_agent),
            poll_interval: self.poll_interval.unwrap_or(defaults.poll_interval),
            retry: self.retry.unwrap_or(defaults.retry),
            proxy: self.proxy,
            state_path: self.state_path,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn builder_overrides_defaults() {
        let config = GoldenPayConfig::builder()
            .golden_key("abc")
            .base_url("https://example.com")
            .poll_interval(Duration::from_secs(5))
            .retry_policy(RetryPolicy::new(7, Duration::from_secs(1)))
            .build();

        assert_eq!(config.golden_key, "abc");
        assert_eq!(config.base_url, "https://example.com");
        assert_eq!(config.poll_interval, Duration::from_secs(5));
        assert_eq!(config.retry.max_attempts, 7);
    }
}