Skip to main content

duckduckgo_core/search/
client.rs

1use std::path::PathBuf;
2use std::sync::Arc;
3
4use super::execute;
5use super::options::ClientOptions;
6use super::types::{SearchResponse, TimeFilter};
7use crate::Clock;
8use crate::Result;
9use crate::rate_limit::Limits;
10use crate::rate_limit::ProgressHook;
11use crate::region::Region;
12
13#[derive(Clone, Debug)]
14pub struct Client {
15    options: ClientOptions,
16}
17
18#[derive(Clone, Debug)]
19pub struct ClientBuilder {
20    options: ClientOptions,
21}
22
23#[derive(Clone, Debug)]
24pub struct SearchBuilder {
25    pub(crate) options: ClientOptions,
26    pub(crate) query: String,
27    pub(crate) page: usize,
28    pub(crate) time: Option<TimeFilter>,
29    pub(crate) sites: Vec<String>,
30}
31
32impl Client {
33    #[must_use]
34    pub fn builder() -> ClientBuilder {
35        ClientBuilder {
36            options: ClientOptions::default(),
37        }
38    }
39
40    #[must_use]
41    pub fn search(&self, query: impl Into<String>) -> SearchBuilder {
42        SearchBuilder {
43            options: self.options.clone(),
44            query: query.into(),
45            page: 1,
46            time: None,
47            sites: Vec::new(),
48        }
49    }
50}
51
52impl ClientBuilder {
53    pub fn region(mut self, region: Region) -> Self {
54        self.options.region = region;
55        self
56    }
57    pub fn num(mut self, num: usize) -> Self {
58        self.options.num = num;
59        self
60    }
61    pub fn safe(mut self, safe: bool) -> Self {
62        self.options.safe = safe;
63        self
64    }
65    pub fn timeout(mut self, seconds: u64) -> Self {
66        self.options.timeout = seconds;
67        self
68    }
69    pub fn proxy(mut self, proxy: Option<String>) -> Self {
70        self.options.proxy = proxy;
71        self
72    }
73    pub fn user_agent(mut self, value: Option<String>) -> Self {
74        self.options.user_agent = value;
75        self
76    }
77    pub fn retry(mut self, retry: u8) -> Self {
78        self.options.retry = retry;
79        self
80    }
81    pub fn no_wait(mut self, value: bool) -> Self {
82        self.options.no_wait = value;
83        self
84    }
85    pub fn no_rate_limit(mut self, value: bool) -> Self {
86        self.options.no_rate_limit = value;
87        self
88    }
89    pub fn state_dir(mut self, value: PathBuf) -> Self {
90        self.options.state_dir = value;
91        self
92    }
93    pub fn endpoint(mut self, value: String) -> Self {
94        self.options.endpoint = value;
95        self
96    }
97    pub fn limits(mut self, value: Limits) -> Self {
98        self.options.limits = value;
99        self
100    }
101    pub fn clock(mut self, value: Arc<dyn Clock>) -> Self {
102        self.options.clock = value;
103        self
104    }
105    /// Install a callback that fires before every cooldown / spacing
106    /// sleep cycle. Used by the CLI to emit `[INFO] rate-limit ...`
107    /// progress lines on stderr; library callers typically leave this
108    /// unset.
109    #[must_use]
110    pub fn on_rate_limit_progress(mut self, hook: ProgressHook) -> Self {
111        self.options.progress_hook = Some(hook);
112        self
113    }
114    pub fn build(self) -> Result<Client> {
115        Ok(Client {
116            options: self.options,
117        })
118    }
119}
120
121impl SearchBuilder {
122    #[must_use]
123    pub fn page(mut self, page: usize) -> Self {
124        self.page = page;
125        self
126    }
127    #[must_use]
128    pub fn time(mut self, time: Option<TimeFilter>) -> Self {
129        self.time = time;
130        self
131    }
132    #[must_use]
133    pub fn site(mut self, site: String) -> Self {
134        self.sites.push(site);
135        self
136    }
137    pub async fn send(self) -> Result<SearchResponse> {
138        execute::execute(self).await
139    }
140}