1use crate::ui::StatusReporter;
2use data_gov_ckan::{ApiKey, Configuration as CkanConfiguration};
3use std::fmt;
4use std::path::PathBuf;
5use std::sync::Arc;
6
7#[derive(Debug, Clone, PartialEq)]
9pub enum OperatingMode {
10 Interactive,
12 CommandLine,
14}
15
16#[derive(Clone)]
18pub struct DataGovConfig {
19 pub ckan_config: Arc<CkanConfiguration>,
21 pub mode: OperatingMode,
23 pub base_download_dir: PathBuf,
25 pub user_agent: String,
27 pub max_concurrent_downloads: usize,
29 pub download_timeout_secs: u64,
31 pub status_reporter: Option<Arc<dyn StatusReporter + Send + Sync>>,
33}
34
35impl fmt::Debug for DataGovConfig {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.debug_struct("DataGovConfig")
38 .field("ckan_config", &self.ckan_config)
39 .field("mode", &self.mode)
40 .field("base_download_dir", &self.base_download_dir)
41 .field("user_agent", &self.user_agent)
42 .field("max_concurrent_downloads", &self.max_concurrent_downloads)
43 .field("download_timeout_secs", &self.download_timeout_secs)
44 .field(
45 "status_reporter",
46 &self
47 .status_reporter
48 .as_ref()
49 .map(|_| "Some(StatusReporter)"),
50 )
51 .finish()
52 }
53}
54
55impl Default for DataGovConfig {
56 fn default() -> Self {
57 Self {
58 ckan_config: Arc::new(CkanConfiguration::default()),
59 mode: OperatingMode::Interactive, base_download_dir: Self::get_default_download_dir(),
61 user_agent: "data-gov-rs/1.0".to_string(),
62 max_concurrent_downloads: 3,
63 download_timeout_secs: 300, status_reporter: None,
65 }
66 }
67}
68
69impl DataGovConfig {
70 fn get_default_download_dir() -> PathBuf {
72 if let Some(download_dir) = dirs::download_dir() {
74 download_dir
75 } else {
76 let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
78 home.join("Downloads")
79 }
80 }
81
82 pub fn new() -> Self {
84 Self::default()
85 }
86
87 pub fn with_download_dir<P: Into<PathBuf>>(mut self, dir: P) -> Self {
89 self.base_download_dir = dir.into();
90 self
91 }
92
93 pub fn with_mode(mut self, mode: OperatingMode) -> Self {
95 self.mode = mode;
96 self
97 }
98
99 pub fn get_base_download_dir(&self) -> PathBuf {
101 match self.mode {
102 OperatingMode::Interactive => {
103 self.base_download_dir.clone()
105 }
106 OperatingMode::CommandLine => {
107 std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
109 }
110 }
111 }
112
113 pub fn get_dataset_download_dir(&self, dataset_name: &str) -> PathBuf {
115 self.get_base_download_dir().join(dataset_name)
116 }
117
118 pub fn with_api_key<S: Into<String>>(mut self, api_key: S) -> Self {
120 let mut ckan_config = (*self.ckan_config).clone();
121 ckan_config.api_key = Some(ApiKey {
122 key: api_key.into(),
123 prefix: None,
124 });
125 self.ckan_config = Arc::new(ckan_config);
126 self
127 }
128
129 pub fn with_user_agent<S: Into<String>>(mut self, user_agent: S) -> Self {
131 self.user_agent = user_agent.into();
132 let mut ckan_config = (*self.ckan_config).clone();
133 ckan_config.user_agent = Some(self.user_agent.clone());
134 self.ckan_config = Arc::new(ckan_config);
135 self
136 }
137
138 pub fn with_max_concurrent_downloads(mut self, max: usize) -> Self {
140 self.max_concurrent_downloads = max.max(1);
141 self
142 }
143
144 pub fn with_download_timeout(mut self, timeout_secs: u64) -> Self {
146 self.download_timeout_secs = timeout_secs;
147 self
148 }
149
150 pub fn with_status_reporter<R>(mut self, reporter: Arc<R>) -> Self
152 where
153 R: StatusReporter + Send + Sync + 'static,
154 {
155 self.status_reporter = Some(reporter);
156 self
157 }
158
159 pub fn without_status_reporter(mut self) -> Self {
161 self.status_reporter = None;
162 self
163 }
164
165 pub fn status_reporter(&self) -> Option<&Arc<dyn StatusReporter + Send + Sync>> {
167 self.status_reporter.as_ref()
168 }
169}