1use crate::constants::{
2 AWS_KMS_ENDPOINT_PATTERN, DEFAULT_APP_ADDR, DEFAULT_APP_PORT, DEFAULT_AWS_REGION,
3 DEFAULT_COSMOS_CHAIN_ID, DEFAULT_COSMOS_HRP, DEFAULT_COSMOS_REST_URL, DEFAULT_ETH_CHAIN_ID,
4};
5use std::env;
6use tracing::{error, info};
7
8#[derive(Debug, Clone, Default)]
9pub struct AwsCreds {
10 pub access_key_id: String,
11 pub secret_access_key: String,
12}
13
14#[derive(Debug, Clone, Default)]
15pub struct AwsConfig {
16 pub region: String,
17 pub endpoint: String,
18 pub sign: AwsCreds,
19 pub create: AwsCreds,
20 pub delete: Option<AwsCreds>,
21 pub list: Option<AwsCreds>,
22 pub hash_type: HashType,
23}
24
25#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
26pub enum HashType {
27 #[default]
28 Sha256,
29 Keccak256,
30 }
32
33#[derive(Debug, Clone, PartialEq, Eq, Default)]
34#[non_exhaustive]
35pub enum BlockchainMode {
36 #[default]
37 Casper,
38 Ethereum,
39 Cosmos,
40}
41
42#[allow(clippy::struct_excessive_bools)]
43#[derive(Debug, Clone)]
44pub struct Config {
45 blockchain_mode: BlockchainMode,
46 addr: String,
47 port: u16,
48 aws: AwsConfig,
49 testing_mode: bool,
50 aws_mode: bool,
51 delete_mode: bool,
52 list_mode: bool,
53 eth_chain_id: u8,
54 cosmos_hrp: String,
55 cosmos_rest_url: String,
56 cosmos_chain_id: String,
57}
58
59impl Default for Config {
60 fn default() -> Self {
61 Self {
62 blockchain_mode: BlockchainMode::default(), port: DEFAULT_APP_PORT,
64 addr: DEFAULT_APP_ADDR.to_string(),
65 aws: AwsConfig::default(),
66 testing_mode: true, aws_mode: false,
68 delete_mode: false,
69 list_mode: false,
70 eth_chain_id: DEFAULT_ETH_CHAIN_ID,
71 cosmos_hrp: DEFAULT_COSMOS_HRP.to_string(),
72 cosmos_rest_url: DEFAULT_COSMOS_REST_URL.to_string(),
73 cosmos_chain_id: DEFAULT_COSMOS_CHAIN_ID.to_string(),
74 }
75 }
76}
77
78impl Config {
79 #[must_use]
80 pub fn from_env() -> Self {
81 dotenvy::dotenv().ok();
82
83 let testing_mode = env::var("TESTING_MODE")
84 .map(|v| v == "true")
85 .unwrap_or(true);
86
87 let delete_mode = env::var("DELETE_MODE")
88 .map(|v| v == "true")
89 .unwrap_or(false);
90 let list_mode = env::var("LIST_MODE").map(|v| v == "true").unwrap_or(false);
91
92 let sign = get_creds("KMS_SIGN_ID", "KMS_SIGN_KEY");
93 let create = get_creds("KMS_CREATE_ID", "KMS_CREATE_KEY");
94 let delete = delete_mode.then(|| get_creds("KMS_DELETE_ID", "KMS_DELETE_KEY"));
95 let list = list_mode.then(|| get_creds("KMS_LIST_ID", "KMS_LIST_KEY"));
96 let aws_mode = env::var("AWS_MODE").map(|v| v == "true").unwrap_or(true);
97
98 let blockchain_mode = match env::var("BLOCKCHAIN_MODE")
99 .unwrap_or_else(|_| format!("{:?}", BlockchainMode::default()))
100 .to_lowercase()
101 .as_str()
102 {
103 "casper" => BlockchainMode::Casper,
104 "ethereum" => BlockchainMode::Ethereum,
105 "cosmos" => BlockchainMode::Cosmos,
106 _ => BlockchainMode::default(),
107 };
108
109 let hash_type = match blockchain_mode {
110 BlockchainMode::Casper | BlockchainMode::Cosmos => HashType::Sha256,
111 BlockchainMode::Ethereum => HashType::Keccak256,
112 };
113
114 log_modes(&Modes {
115 delete_mode,
116 list_mode,
117 aws_mode,
118 testing_mode,
119 blockchain_mode: blockchain_mode.clone(),
120 hash_type,
121 });
122
123 let region = env::var("AWS_REGION").unwrap_or_else(|_| DEFAULT_AWS_REGION.into());
124 let endpoint = env::var("AWS_ENDPOINT").unwrap_or_else(|_| {
125 AWS_KMS_ENDPOINT_PATTERN.replace("{}", ®ion)
127 });
128
129 Self {
130 blockchain_mode,
131 port: env::var("APP_PORT")
132 .ok()
133 .and_then(|v| v.parse().ok())
134 .unwrap_or(DEFAULT_APP_PORT),
135 addr: env::var("APP_ADDR")
136 .ok()
137 .unwrap_or_else(|| DEFAULT_APP_ADDR.to_string()),
138 aws: AwsConfig {
139 region,
140 endpoint,
141 sign,
142 create,
143 delete,
144 list,
145 hash_type,
146 },
147 aws_mode,
148 testing_mode,
149 delete_mode,
150 list_mode,
151 eth_chain_id: env::var("ETH_CHAIN_ID")
152 .ok()
153 .and_then(|v| v.parse().ok())
154 .unwrap_or(DEFAULT_ETH_CHAIN_ID),
155 cosmos_hrp: env::var("COSMOS_HRP")
156 .ok()
157 .and_then(|v| v.parse().ok())
158 .unwrap_or_else(|| DEFAULT_COSMOS_HRP.to_string()),
159 cosmos_rest_url: env::var("COSMOS_REST_URL")
160 .ok()
161 .and_then(|v| v.parse().ok())
162 .unwrap_or_else(|| DEFAULT_COSMOS_REST_URL.to_string()),
163 cosmos_chain_id: env::var("COSMOS_CHAIN_ID")
164 .ok()
165 .and_then(|v| v.parse().ok())
166 .unwrap_or_else(|| DEFAULT_COSMOS_CHAIN_ID.to_string()),
167 }
168 }
169
170 #[must_use]
171 pub const fn is_testing_mode(&self) -> bool {
172 self.testing_mode
173 }
174
175 #[must_use]
176 pub fn is_ethereum_mode(&self) -> bool {
177 self.blockchain_mode == BlockchainMode::Ethereum
178 }
179
180 #[must_use]
181 pub fn is_casper_mode(&self) -> bool {
182 self.blockchain_mode == BlockchainMode::Casper
183 }
184
185 #[must_use]
186 pub fn is_cosmos_mode(&self) -> bool {
187 self.blockchain_mode == BlockchainMode::Cosmos
188 }
189
190 #[must_use]
191 pub const fn is_delete_mode(&self) -> bool {
192 self.delete_mode
193 }
194
195 #[must_use]
196 pub const fn is_list_mode(&self) -> bool {
197 self.list_mode
198 }
199
200 #[must_use]
201 pub const fn is_aws_mode(&self) -> bool {
202 self.aws_mode
203 }
204
205 #[must_use]
206 pub fn get_aws_config(&self) -> AwsConfig {
207 self.aws.clone()
208 }
209
210 #[must_use]
211 pub const fn get_port(&self) -> u16 {
212 self.port
213 }
214
215 #[must_use]
216 pub fn get_addr(&self) -> String {
217 self.addr.clone()
218 }
219
220 #[must_use]
221 pub const fn get_eth_chain_id(&self) -> u8 {
222 self.eth_chain_id
223 }
224
225 #[must_use]
226 pub fn get_cosmos_hrp(&self) -> String {
227 self.cosmos_hrp.clone()
228 }
229
230 #[must_use]
231 pub fn get_cosmos_rest_url(&self) -> String {
232 self.cosmos_rest_url.clone()
233 }
234
235 #[must_use]
236 pub fn get_cosmos_chain_id(&self) -> String {
237 self.cosmos_chain_id.clone()
238 }
239}
240
241fn get_creds(id_key: &str, secret_key: &str) -> AwsCreds {
242 let id = env::var(id_key).unwrap_or_default();
243 let secret = env::var(secret_key).unwrap_or_default();
244
245 if id.is_empty() {
246 error!("{id_key} env var is empty");
247 }
248 if secret.is_empty() {
249 error!("{secret_key} env var is empty");
250 }
251
252 AwsCreds {
253 access_key_id: id,
254 secret_access_key: secret,
255 }
256}
257
258#[allow(clippy::struct_excessive_bools)]
259struct Modes {
260 delete_mode: bool,
261 list_mode: bool,
262 aws_mode: bool,
263 testing_mode: bool,
264 blockchain_mode: BlockchainMode,
265 hash_type: HashType,
266}
267
268#[allow(clippy::cognitive_complexity)]
269fn log_modes(modes: &Modes) {
270 info!("testing_mode: {}", modes.testing_mode);
271 info!("aws_mode: {}", modes.aws_mode);
272 info!("delete_mode: {}", modes.delete_mode);
273 info!("list_mode: {}", modes.list_mode);
274 info!("blockchain_mode: {:?}", modes.blockchain_mode);
275 info!("hash_type: {:?}", modes.hash_type);
276}
277
278#[derive(Debug, Default)]
279pub struct ConfigBuilder {
280 config: Config,
281}
282
283impl ConfigBuilder {
284 #[must_use]
285 pub fn new() -> Self {
286 Self::default()
287 }
288
289 #[must_use]
290 pub const fn with_blockchain_mode(mut self, mode: BlockchainMode) -> Self {
291 self.config.blockchain_mode = mode;
292 self
293 }
294
295 #[must_use]
296 pub const fn with_casper_mode(mut self) -> Self {
297 self.config.blockchain_mode = BlockchainMode::Casper;
298 self
299 }
300
301 #[must_use]
302 pub const fn with_ethereum_mode(mut self) -> Self {
303 self.config.blockchain_mode = BlockchainMode::Ethereum;
304 self
305 }
306
307 #[must_use]
308 pub const fn with_cosmos_mode(mut self) -> Self {
309 self.config.blockchain_mode = BlockchainMode::Cosmos;
310 self
311 }
312
313 #[must_use]
314 pub const fn with_testing_mode(mut self, enabled: bool) -> Self {
315 self.config.testing_mode = enabled;
316 self
317 }
318
319 #[must_use]
320 pub const fn with_delete_mode(mut self, enabled: bool) -> Self {
321 self.config.delete_mode = enabled;
322 self
323 }
324
325 #[must_use]
326 pub const fn with_list_mode(mut self, enabled: bool) -> Self {
327 self.config.list_mode = enabled;
328 self
329 }
330
331 #[must_use]
332 pub const fn with_aws_mode(mut self, enabled: bool) -> Self {
333 self.config.aws_mode = enabled;
334 self
335 }
336
337 #[must_use]
338 pub const fn with_port(mut self, port: u16) -> Self {
339 self.config.port = port;
340 self
341 }
342
343 #[must_use]
344 pub const fn with_eth_chain_id(mut self, id: u8) -> Self {
345 self.config.eth_chain_id = id;
346 self
347 }
348
349 #[must_use]
350 pub fn with_aws_config(mut self, aws: AwsConfig) -> Self {
351 self.config.aws = aws;
352 self
353 }
354
355 #[must_use]
356 pub fn build(self) -> Config {
357 self.config
358 }
359}