1use std::env;
4use std::time::Duration;
5
6use crate::error::{Error, Result};
7
8pub const DEFAULT_BASE_URL: &str = "http://www.dce.com.cn";
10
11pub const DEFAULT_TIMEOUT_SECS: u64 = 30;
13
14pub const DEFAULT_LANG: &str = "zh";
16
17pub const DEFAULT_TRADE_TYPE: i32 = 1;
19
20pub const ENV_API_KEY: &str = "DCE_API_KEY";
22
23pub const ENV_SECRET: &str = "DCE_SECRET";
25
26#[derive(Debug, Clone)]
28pub struct Config {
29 pub base_url: String,
31
32 pub api_key: String,
34
35 pub secret: String,
37
38 pub timeout: Duration,
40
41 pub lang: String,
43
44 pub trade_type: i32,
46}
47
48impl Default for Config {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54impl Config {
55 pub fn new() -> Self {
59 Config {
60 base_url: DEFAULT_BASE_URL.to_string(),
61 api_key: String::new(),
62 secret: String::new(),
63 timeout: Duration::from_secs(DEFAULT_TIMEOUT_SECS),
64 lang: DEFAULT_LANG.to_string(),
65 trade_type: DEFAULT_TRADE_TYPE,
66 }
67 }
68
69 pub fn from_env() -> Self {
73 let mut config = Self::new();
74 config.api_key = env::var(ENV_API_KEY).unwrap_or_default();
75 config.secret = env::var(ENV_SECRET).unwrap_or_default();
76 config
77 }
78
79 pub fn with_base_url(mut self, base_url: impl Into<String>) -> Self {
81 self.base_url = base_url.into();
82 self
83 }
84
85 pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
87 self.api_key = api_key.into();
88 self
89 }
90
91 pub fn with_secret(mut self, secret: impl Into<String>) -> Self {
93 self.secret = secret.into();
94 self
95 }
96
97 pub fn with_timeout(mut self, timeout: Duration) -> Self {
99 self.timeout = timeout;
100 self
101 }
102
103 pub fn with_lang(mut self, lang: impl Into<String>) -> Self {
105 self.lang = lang.into();
106 self
107 }
108
109 pub fn with_trade_type(mut self, trade_type: i32) -> Self {
111 self.trade_type = trade_type;
112 self
113 }
114
115 pub fn validate(&self) -> Result<()> {
119 if self.api_key.is_empty() {
120 return Err(Error::validation("api_key", "API key is required"));
121 }
122 if self.secret.is_empty() {
123 return Err(Error::validation("secret", "secret is required"));
124 }
125 Ok(())
126 }
127
128 pub fn apply_defaults(&mut self) {
130 if self.base_url.is_empty() {
131 self.base_url = DEFAULT_BASE_URL.to_string();
132 }
133 if self.timeout.is_zero() {
134 self.timeout = Duration::from_secs(DEFAULT_TIMEOUT_SECS);
135 }
136 if self.lang.is_empty() {
137 self.lang = DEFAULT_LANG.to_string();
138 }
139 if self.trade_type == 0 {
140 self.trade_type = DEFAULT_TRADE_TYPE;
141 }
142 }
143}