Skip to main content

wax/
config.rs

1use std::path::{Path, PathBuf};
2
3use directories::ProjectDirs;
4use serde::{Deserialize, Serialize};
5
6use crate::cli::Cli;
7use crate::error::{AppError, Result};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct FileConfig {
11    pub cache_dir: Option<PathBuf>,
12    pub request_delay_ms: Option<u64>,
13    pub concurrency: Option<usize>,
14    pub timeout_ms: Option<u64>,
15    pub user_agent: Option<String>,
16    pub max_collectors: Option<usize>,
17    pub max_depth: Option<usize>,
18}
19
20#[derive(Debug, Clone)]
21pub struct Settings {
22    pub cache_dir: PathBuf,
23    pub request_delay_ms: u64,
24    pub concurrency: usize,
25    pub timeout_ms: u64,
26    pub user_agent: String,
27}
28
29impl Settings {
30    pub fn load(cli: &Cli) -> Result<Self> {
31        let file_cfg = load_file_config(cli.config.as_deref())?;
32        let project_dirs = ProjectDirs::from("dev", "jdhoffa", "wax").ok_or_else(|| {
33            AppError::InvalidInput("unable to determine cache directory".to_string())
34        })?;
35
36        let cache_dir = cli
37            .cache_dir
38            .clone()
39            .or(file_cfg.cache_dir)
40            .unwrap_or_else(|| project_dirs.cache_dir().to_path_buf());
41
42        Ok(Self {
43            cache_dir,
44            request_delay_ms: cli
45                .rate_limit_ms
46                .or(file_cfg.request_delay_ms)
47                .unwrap_or(750),
48            concurrency: cli.concurrency.or(file_cfg.concurrency).unwrap_or(4),
49            timeout_ms: cli.timeout_ms.or(file_cfg.timeout_ms).unwrap_or(10_000),
50            user_agent: cli
51                .user_agent
52                .clone()
53                .or(file_cfg.user_agent)
54                .unwrap_or_else(|| "wax/0.1".to_string()),
55        })
56    }
57}
58
59fn load_file_config(path: Option<&Path>) -> Result<FileConfig> {
60    let Some(path) = path else {
61        return Ok(FileConfig {
62            cache_dir: None,
63            request_delay_ms: None,
64            concurrency: None,
65            timeout_ms: None,
66            user_agent: None,
67            max_collectors: None,
68            max_depth: None,
69        });
70    };
71
72    let text = std::fs::read_to_string(path)?;
73    let cfg = toml::from_str(&text)?;
74    Ok(cfg)
75}