use serde::Serialize;
use super::base::SearchProvider;
use super::bing::{BingConfig, BingProvider};
use super::duckduckgo::DuckDuckGoProvider;
use super::engines::{access_for, all_descriptor_engines, EngineDescriptor};
use super::generic::GenericProvider;
use super::google::{GoogleConfig, GoogleProvider};
use super::web_capture::{WebCaptureProvider, SUPPORTED_PROVIDERS};
pub const CATEGORIES: [&str; 4] = ["search", "knowledge", "papers", "code"];
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RegistryEntry {
pub id: String,
pub label: String,
pub category: String,
pub cors_readable: bool,
pub default_for_category: bool,
pub access: String,
}
#[derive(Debug, Clone, Default)]
pub struct BuildConfig {
pub google_api_key: Option<String>,
pub google_cx: Option<String>,
pub bing_api_key: Option<String>,
}
struct ClassEngine {
id: &'static str,
label: &'static str,
category: &'static str,
cors_readable: bool,
default_for_category: bool,
access: &'static str,
}
const CLASS_ENGINES: [ClassEngine; 3] = [
ClassEngine {
id: "google",
label: "Google",
category: "search",
cors_readable: false,
default_for_category: false,
access: "hybrid",
},
ClassEngine {
id: "bing",
label: "Bing",
category: "search",
cors_readable: false,
default_for_category: false,
access: "hybrid",
},
ClassEngine {
id: "duckduckgo",
label: "DuckDuckGo",
category: "search",
cors_readable: false,
default_for_category: true,
access: "html",
},
];
fn descriptor_entry(d: &EngineDescriptor) -> RegistryEntry {
RegistryEntry {
id: d.id.to_string(),
label: d.label.to_string(),
category: d.category.to_string(),
cors_readable: d.cors_readable,
default_for_category: d.default_for_category,
access: access_for(d.kind).to_string(),
}
}
pub fn get_registry() -> Vec<RegistryEntry> {
let mut entries = Vec::new();
for e in &CLASS_ENGINES {
entries.push(RegistryEntry {
id: e.id.to_string(),
label: e.label.to_string(),
category: e.category.to_string(),
cors_readable: e.cors_readable,
default_for_category: e.default_for_category,
access: e.access.to_string(),
});
}
for d in all_descriptor_engines() {
entries.push(descriptor_entry(&d));
}
for engine in SUPPORTED_PROVIDERS {
entries.push(RegistryEntry {
id: format!("wc:{engine}"),
label: format!("web-capture ({engine})"),
category: "search".to_string(),
cors_readable: engine == "wikipedia",
default_for_category: false,
access: "component".to_string(),
});
}
entries
}
pub fn get_provider_ids(category: Option<&str>) -> Vec<String> {
get_registry()
.into_iter()
.filter(|e| category.is_none_or(|c| e.category == c))
.map(|e| e.id)
.collect()
}
pub fn get_default_provider_ids() -> Vec<String> {
[
"duckduckgo",
"internet-archive",
"wikipedia",
"wikidata",
"wiktionary",
"wikinews",
]
.iter()
.map(|s| s.to_string())
.collect()
}
pub fn is_known_category(category: &str) -> bool {
CATEGORIES.contains(&category)
}
pub fn build_providers(config: &BuildConfig) -> Vec<(String, Box<dyn SearchProvider>)> {
let mut providers: Vec<(String, Box<dyn SearchProvider>)> = Vec::new();
providers.push((
"google".to_string(),
Box::new(GoogleProvider::new(GoogleConfig {
api_key: config.google_api_key.clone(),
search_engine_id: config.google_cx.clone(),
})),
));
providers.push((
"bing".to_string(),
Box::new(BingProvider::new(BingConfig {
api_key: config.bing_api_key.clone(),
})),
));
providers.push((
"duckduckgo".to_string(),
Box::new(DuckDuckGoProvider::new()),
));
for d in all_descriptor_engines() {
providers.push((d.id.to_string(), Box::new(GenericProvider::new(d))));
}
for engine in SUPPORTED_PROVIDERS {
providers.push((
format!("wc:{engine}"),
Box::new(WebCaptureProvider::new(engine)),
));
}
providers
}