1use serde::Serialize;
11
12use super::base::SearchProvider;
13use super::bing::{BingConfig, BingProvider};
14use super::duckduckgo::DuckDuckGoProvider;
15use super::engines::{access_for, all_descriptor_engines, EngineDescriptor};
16use super::generic::GenericProvider;
17use super::google::{GoogleConfig, GoogleProvider};
18use super::web_capture::{WebCaptureProvider, SUPPORTED_PROVIDERS};
19
20pub const CATEGORIES: [&str; 4] = ["search", "knowledge", "papers", "code"];
22
23#[derive(Debug, Clone, Serialize)]
25#[serde(rename_all = "camelCase")]
26pub struct RegistryEntry {
27 pub id: String,
29 pub label: String,
31 pub category: String,
33 pub cors_readable: bool,
35 pub default_for_category: bool,
37 pub access: String,
39}
40
41#[derive(Debug, Clone, Default)]
43pub struct BuildConfig {
44 pub google_api_key: Option<String>,
46 pub google_cx: Option<String>,
48 pub bing_api_key: Option<String>,
50}
51
52struct ClassEngine {
55 id: &'static str,
56 label: &'static str,
57 category: &'static str,
58 cors_readable: bool,
59 default_for_category: bool,
60 access: &'static str,
61}
62
63const CLASS_ENGINES: [ClassEngine; 3] = [
64 ClassEngine {
65 id: "google",
66 label: "Google",
67 category: "search",
68 cors_readable: false,
69 default_for_category: false,
70 access: "hybrid",
71 },
72 ClassEngine {
73 id: "bing",
74 label: "Bing",
75 category: "search",
76 cors_readable: false,
77 default_for_category: false,
78 access: "hybrid",
79 },
80 ClassEngine {
81 id: "duckduckgo",
82 label: "DuckDuckGo",
83 category: "search",
84 cors_readable: false,
85 default_for_category: true,
86 access: "html",
87 },
88];
89
90fn descriptor_entry(d: &EngineDescriptor) -> RegistryEntry {
91 RegistryEntry {
92 id: d.id.to_string(),
93 label: d.label.to_string(),
94 category: d.category.to_string(),
95 cors_readable: d.cors_readable,
96 default_for_category: d.default_for_category,
97 access: access_for(d.kind).to_string(),
98 }
99}
100
101pub fn get_registry() -> Vec<RegistryEntry> {
104 let mut entries = Vec::new();
105
106 for e in &CLASS_ENGINES {
107 entries.push(RegistryEntry {
108 id: e.id.to_string(),
109 label: e.label.to_string(),
110 category: e.category.to_string(),
111 cors_readable: e.cors_readable,
112 default_for_category: e.default_for_category,
113 access: e.access.to_string(),
114 });
115 }
116 for d in all_descriptor_engines() {
117 entries.push(descriptor_entry(&d));
118 }
119 for engine in SUPPORTED_PROVIDERS {
120 entries.push(RegistryEntry {
121 id: format!("wc:{engine}"),
122 label: format!("web-capture ({engine})"),
123 category: "search".to_string(),
124 cors_readable: engine == "wikipedia",
125 default_for_category: false,
126 access: "component".to_string(),
127 });
128 }
129
130 entries
131}
132
133pub fn get_provider_ids(category: Option<&str>) -> Vec<String> {
135 get_registry()
136 .into_iter()
137 .filter(|e| category.is_none_or(|c| e.category == c))
138 .map(|e| e.id)
139 .collect()
140}
141
142pub fn get_default_provider_ids() -> Vec<String> {
148 [
149 "duckduckgo",
150 "internet-archive",
151 "wikipedia",
152 "wikidata",
153 "wiktionary",
154 "wikinews",
155 ]
156 .iter()
157 .map(|s| s.to_string())
158 .collect()
159}
160
161pub fn is_known_category(category: &str) -> bool {
163 CATEGORIES.contains(&category)
164}
165
166pub fn build_providers(config: &BuildConfig) -> Vec<(String, Box<dyn SearchProvider>)> {
168 let mut providers: Vec<(String, Box<dyn SearchProvider>)> = Vec::new();
169
170 providers.push((
171 "google".to_string(),
172 Box::new(GoogleProvider::new(GoogleConfig {
173 api_key: config.google_api_key.clone(),
174 search_engine_id: config.google_cx.clone(),
175 })),
176 ));
177 providers.push((
178 "bing".to_string(),
179 Box::new(BingProvider::new(BingConfig {
180 api_key: config.bing_api_key.clone(),
181 })),
182 ));
183 providers.push((
184 "duckduckgo".to_string(),
185 Box::new(DuckDuckGoProvider::new()),
186 ));
187
188 for d in all_descriptor_engines() {
189 providers.push((d.id.to_string(), Box::new(GenericProvider::new(d))));
190 }
191
192 for engine in SUPPORTED_PROVIDERS {
193 providers.push((
194 format!("wc:{engine}"),
195 Box::new(WebCaptureProvider::new(engine)),
196 ));
197 }
198
199 providers
200}