1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(rename_all = "camelCase")]
11pub struct SearchConfig {
12 #[serde(default = "default_search_timeout")]
14 pub timeout: u64,
15
16 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub health: Option<SearchHealthConfig>,
19
20 #[serde(default, rename = "engine")]
22 pub engines: std::collections::HashMap<String, SearchEngineConfig>,
23
24 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub headless: Option<HeadlessConfig>,
29}
30
31#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
33#[serde(rename_all = "lowercase")]
34pub enum BrowserBackend {
35 #[default]
37 Moli,
38 #[serde(alias = "chromium")]
40 Chrome,
41 Lightpanda,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
51#[serde(rename_all = "camelCase")]
52pub struct HeadlessConfig {
53 #[serde(default)]
55 pub backend: BrowserBackend,
56
57 #[serde(default = "default_headless_max_tabs")]
59 pub max_tabs: usize,
60
61 #[serde(
64 default,
65 alias = "chromePath",
66 alias = "lightpandaPath",
67 alias = "obscuraPath",
68 alias = "playwrightPath",
69 skip_serializing_if = "Option::is_none"
70 )]
71 pub browser_path: Option<String>,
72
73 #[serde(default = "default_auto_download_moli")]
76 pub auto_download_moli: bool,
77
78 #[serde(default, skip_serializing_if = "Option::is_none")]
81 pub moli_version: Option<String>,
82
83 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub moli_sha256: Option<String>,
87
88 #[serde(default, skip_serializing_if = "Option::is_none")]
90 pub moli_cache_dir: Option<PathBuf>,
91
92 #[serde(default = "default_moli_download_timeout_secs")]
96 pub moli_download_timeout_secs: u64,
97
98 #[serde(default, skip_serializing_if = "Vec::is_empty")]
100 pub launch_args: Vec<String>,
101
102 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub proxy_url: Option<String>,
105}
106
107impl BrowserBackend {
108 pub fn is_moli(self) -> bool {
109 matches!(self, Self::Moli)
110 }
111
112 pub fn is_lightpanda(self) -> bool {
113 matches!(self, Self::Lightpanda)
114 }
115}
116
117impl Default for HeadlessConfig {
118 fn default() -> Self {
119 Self {
120 backend: BrowserBackend::Moli,
121 max_tabs: 4,
122 browser_path: None,
123 auto_download_moli: true,
124 moli_version: None,
125 moli_sha256: None,
126 moli_cache_dir: None,
127 moli_download_timeout_secs: default_moli_download_timeout_secs(),
128 launch_args: Vec::new(),
129 proxy_url: None,
130 }
131 }
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct DocumentParserConfig {
138 #[serde(default = "default_enabled")]
140 pub enabled: bool,
141
142 #[serde(default = "default_document_parser_max_file_size_mb")]
144 pub max_file_size_mb: u64,
145
146 #[serde(default, skip_serializing_if = "Option::is_none")]
148 pub cache: Option<DocumentCacheConfig>,
149}
150
151impl Default for DocumentParserConfig {
152 fn default() -> Self {
153 Self {
154 enabled: true,
155 max_file_size_mb: default_document_parser_max_file_size_mb(),
156 cache: Some(DocumentCacheConfig::default()),
157 }
158 }
159}
160
161impl DocumentParserConfig {
162 pub fn normalized(&self) -> Self {
163 Self {
164 enabled: self.enabled,
165 max_file_size_mb: self.max_file_size_mb.clamp(1, 1024),
166 cache: self.cache.as_ref().map(DocumentCacheConfig::normalized),
167 }
168 }
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct DocumentCacheConfig {
174 #[serde(default = "default_enabled")]
175 pub enabled: bool,
176
177 #[serde(default, skip_serializing_if = "Option::is_none")]
178 pub directory: Option<PathBuf>,
179}
180
181impl Default for DocumentCacheConfig {
182 fn default() -> Self {
183 Self {
184 enabled: true,
185 directory: None,
186 }
187 }
188}
189
190impl DocumentCacheConfig {
191 pub fn normalized(&self) -> Self {
192 Self {
193 enabled: self.enabled,
194 directory: self.directory.clone(),
195 }
196 }
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
201#[serde(rename_all = "camelCase")]
202pub struct SearchHealthConfig {
203 #[serde(default = "default_max_failures")]
205 pub max_failures: u32,
206
207 #[serde(default = "default_suspend_seconds")]
209 pub suspend_seconds: u64,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
214#[serde(rename_all = "camelCase")]
215pub struct SearchEngineConfig {
216 #[serde(default = "default_enabled")]
218 pub enabled: bool,
219
220 #[serde(default = "default_weight")]
222 pub weight: f64,
223
224 #[serde(skip_serializing_if = "Option::is_none")]
226 pub timeout: Option<u64>,
227}
228
229pub(crate) fn default_search_timeout() -> u64 {
230 20
231}
232
233pub(crate) fn default_headless_max_tabs() -> usize {
234 4
235}
236
237fn default_auto_download_moli() -> bool {
238 true
239}
240
241pub(crate) fn default_moli_download_timeout_secs() -> u64 {
242 120
243}
244
245fn default_max_failures() -> u32 {
246 3
247}
248
249fn default_suspend_seconds() -> u64 {
250 60
251}
252
253pub(crate) fn default_enabled() -> bool {
254 true
255}
256
257fn default_weight() -> f64 {
258 1.0
259}
260
261pub(crate) fn default_document_parser_max_file_size_mb() -> u64 {
262 50
263}