rusty_files/core/
config.rs

1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct SearchConfig {
6    pub index_path: PathBuf,
7    pub thread_count: usize,
8    pub max_file_size_for_content: u64,
9    pub enable_content_search: bool,
10    pub enable_fuzzy_search: bool,
11    pub fuzzy_threshold: f64,
12    pub cache_size: usize,
13    pub bloom_filter_capacity: usize,
14    pub bloom_filter_error_rate: f64,
15    pub max_search_results: usize,
16    pub batch_size: usize,
17    pub follow_symlinks: bool,
18    pub index_hidden_files: bool,
19    pub exclusion_patterns: Vec<String>,
20    pub watch_debounce_ms: u64,
21    pub enable_access_tracking: bool,
22    pub db_pool_size: u32,
23}
24
25impl Default for SearchConfig {
26    fn default() -> Self {
27        Self {
28            index_path: PathBuf::from("./filesearch.db"),
29            thread_count: num_cpus() * 2,
30            max_file_size_for_content: 10 * 1024 * 1024,
31            enable_content_search: false,
32            enable_fuzzy_search: true,
33            fuzzy_threshold: 0.7,
34            cache_size: 1000,
35            bloom_filter_capacity: 10_000_000,
36            bloom_filter_error_rate: 0.0001,
37            max_search_results: 1000,
38            batch_size: 1000,
39            follow_symlinks: false,
40            index_hidden_files: false,
41            exclusion_patterns: vec![
42                ".git".to_string(),
43                "node_modules".to_string(),
44                "target".to_string(),
45                ".DS_Store".to_string(),
46            ],
47            watch_debounce_ms: 500,
48            enable_access_tracking: true,
49            db_pool_size: 10,
50        }
51    }
52}
53
54impl SearchConfig {
55    pub fn from_file(path: &PathBuf) -> crate::core::error::Result<Self> {
56        let content = std::fs::read_to_string(path)?;
57        let config: Self = if path.extension().and_then(|s| s.to_str()) == Some("json") {
58            serde_json::from_str(&content)
59                .map_err(|e| crate::core::error::SearchError::Configuration(e.to_string()))?
60        } else {
61            toml::from_str(&content)
62                .map_err(|e| crate::core::error::SearchError::Configuration(e.to_string()))?
63        };
64        Ok(config)
65    }
66
67    pub fn to_file(&self, path: &PathBuf) -> crate::core::error::Result<()> {
68        let content = if path.extension().and_then(|s| s.to_str()) == Some("json") {
69            serde_json::to_string_pretty(self)
70                .map_err(|e| crate::core::error::SearchError::Configuration(e.to_string()))?
71        } else {
72            toml::to_string_pretty(self)
73                .map_err(|e| crate::core::error::SearchError::Configuration(e.to_string()))?
74        };
75        std::fs::write(path, content)?;
76        Ok(())
77    }
78}
79
80pub struct SearchConfigBuilder {
81    config: SearchConfig,
82}
83
84impl SearchConfigBuilder {
85    pub fn new() -> Self {
86        Self {
87            config: SearchConfig::default(),
88        }
89    }
90
91    pub fn index_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
92        self.config.index_path = path.into();
93        self
94    }
95
96    pub fn thread_count(mut self, count: usize) -> Self {
97        self.config.thread_count = count;
98        self
99    }
100
101    pub fn max_file_size_for_content(mut self, size: u64) -> Self {
102        self.config.max_file_size_for_content = size;
103        self
104    }
105
106    pub fn enable_content_search(mut self, enable: bool) -> Self {
107        self.config.enable_content_search = enable;
108        self
109    }
110
111    pub fn enable_fuzzy_search(mut self, enable: bool) -> Self {
112        self.config.enable_fuzzy_search = enable;
113        self
114    }
115
116    pub fn fuzzy_threshold(mut self, threshold: f64) -> Self {
117        self.config.fuzzy_threshold = threshold;
118        self
119    }
120
121    pub fn cache_size(mut self, size: usize) -> Self {
122        self.config.cache_size = size;
123        self
124    }
125
126    pub fn max_search_results(mut self, max: usize) -> Self {
127        self.config.max_search_results = max;
128        self
129    }
130
131    pub fn batch_size(mut self, size: usize) -> Self {
132        self.config.batch_size = size;
133        self
134    }
135
136    pub fn follow_symlinks(mut self, follow: bool) -> Self {
137        self.config.follow_symlinks = follow;
138        self
139    }
140
141    pub fn index_hidden_files(mut self, index: bool) -> Self {
142        self.config.index_hidden_files = index;
143        self
144    }
145
146    pub fn exclusion_patterns(mut self, patterns: Vec<String>) -> Self {
147        self.config.exclusion_patterns = patterns;
148        self
149    }
150
151    pub fn add_exclusion_pattern<S: Into<String>>(mut self, pattern: S) -> Self {
152        self.config.exclusion_patterns.push(pattern.into());
153        self
154    }
155
156    pub fn watch_debounce_ms(mut self, ms: u64) -> Self {
157        self.config.watch_debounce_ms = ms;
158        self
159    }
160
161    pub fn enable_access_tracking(mut self, enable: bool) -> Self {
162        self.config.enable_access_tracking = enable;
163        self
164    }
165
166    pub fn db_pool_size(mut self, size: u32) -> Self {
167        self.config.db_pool_size = size;
168        self
169    }
170
171    pub fn build(self) -> SearchConfig {
172        self.config
173    }
174}
175
176impl Default for SearchConfigBuilder {
177    fn default() -> Self {
178        Self::new()
179    }
180}
181
182fn num_cpus() -> usize {
183    std::thread::available_parallelism()
184        .map(|n| n.get())
185        .unwrap_or(4)
186}