Spaces:
Running
Running
Merge pull request #470 from ddotthomas/FIX/463_results_from_different_search_engines_get_cached_as_the_same_key
Browse files- src/models/server_models.rs +20 -3
- src/server/routes/search.rs +73 -83
src/models/server_models.rs
CHANGED
@@ -1,7 +1,11 @@
|
|
1 |
//! This module provides the models to parse cookies and search parameters from the search
|
2 |
//! engine website.
|
|
|
|
|
3 |
use serde::Deserialize;
|
4 |
|
|
|
|
|
5 |
/// A named struct which deserializes all the user provided search parameters and stores them.
|
6 |
#[derive(Deserialize)]
|
7 |
pub struct SearchParams {
|
@@ -21,11 +25,24 @@ pub struct SearchParams {
|
|
21 |
#[derive(Deserialize)]
|
22 |
pub struct Cookie<'a> {
|
23 |
/// It stores the theme name used in the website.
|
24 |
-
pub theme:
|
25 |
/// It stores the colorscheme name used for the website theme.
|
26 |
-
pub colorscheme:
|
27 |
/// It stores the user selected upstream search engines selected from the UI.
|
28 |
-
pub engines: Vec
|
29 |
/// It stores the user selected safe search level from the UI.
|
30 |
pub safe_search_level: u8,
|
31 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
//! This module provides the models to parse cookies and search parameters from the search
|
2 |
//! engine website.
|
3 |
+
use std::borrow::Cow;
|
4 |
+
|
5 |
use serde::Deserialize;
|
6 |
|
7 |
+
use super::parser_models::Style;
|
8 |
+
|
9 |
/// A named struct which deserializes all the user provided search parameters and stores them.
|
10 |
#[derive(Deserialize)]
|
11 |
pub struct SearchParams {
|
|
|
25 |
#[derive(Deserialize)]
|
26 |
pub struct Cookie<'a> {
|
27 |
/// It stores the theme name used in the website.
|
28 |
+
pub theme: Cow<'a, str>,
|
29 |
/// It stores the colorscheme name used for the website theme.
|
30 |
+
pub colorscheme: Cow<'a, str>,
|
31 |
/// It stores the user selected upstream search engines selected from the UI.
|
32 |
+
pub engines: Cow<'a, Vec<Cow<'a, str>>>,
|
33 |
/// It stores the user selected safe search level from the UI.
|
34 |
pub safe_search_level: u8,
|
35 |
}
|
36 |
+
|
37 |
+
impl<'a> Cookie<'a> {
|
38 |
+
/// server_models::Cookie contructor function
|
39 |
+
pub fn build(style: &'a Style, mut engines: Vec<Cow<'a, str>>, safe_search_level: u8) -> Self {
|
40 |
+
engines.sort();
|
41 |
+
Self {
|
42 |
+
theme: Cow::Borrowed(&style.theme),
|
43 |
+
colorscheme: Cow::Borrowed(&style.colorscheme),
|
44 |
+
engines: Cow::Owned(engines),
|
45 |
+
safe_search_level,
|
46 |
+
}
|
47 |
+
}
|
48 |
+
}
|
src/server/routes/search.rs
CHANGED
@@ -6,14 +6,15 @@ use crate::{
|
|
6 |
handler::{file_path, FileType},
|
7 |
models::{
|
8 |
aggregation_models::SearchResults,
|
9 |
-
engine_models::
|
10 |
-
server_models::{
|
11 |
},
|
12 |
results::aggregator::aggregate,
|
13 |
};
|
14 |
use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
|
15 |
use regex::Regex;
|
16 |
use std::{
|
|
|
17 |
fs::File,
|
18 |
io::{BufRead, BufReader, Read},
|
19 |
};
|
@@ -48,16 +49,33 @@ pub async fn search(
|
|
48 |
.finish());
|
49 |
}
|
50 |
|
51 |
-
let
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
// .max(1) makes sure that the page >= 0.
|
63 |
let page = params.page.unwrap_or(1).max(1) - 1;
|
@@ -105,25 +123,19 @@ async fn results(
|
|
105 |
cache: &web::Data<SharedCache>,
|
106 |
query: &str,
|
107 |
page: u32,
|
108 |
-
|
109 |
-
safe_search: &Option<u8>,
|
110 |
) -> Result<SearchResults, Box<dyn std::error::Error>> {
|
111 |
// eagerly parse cookie value to evaluate safe search level
|
112 |
-
let
|
113 |
-
|
114 |
-
let cookie_value: Option<Cookie<'_>> = cookie_value
|
115 |
-
.as_ref()
|
116 |
-
.and_then(|cv| serde_json::from_str(cv.name_value().1).ok());
|
117 |
-
|
118 |
-
let safe_search_level = get_safesearch_level(
|
119 |
-
safe_search,
|
120 |
-
&cookie_value.as_ref().map(|cv| cv.safe_search_level),
|
121 |
-
config.safe_search,
|
122 |
-
);
|
123 |
|
124 |
let cache_key = format!(
|
125 |
-
"http://{}:{}/search?q={}&page={}&safesearch={}",
|
126 |
-
config.binding_ip,
|
|
|
|
|
|
|
|
|
|
|
127 |
);
|
128 |
|
129 |
// fetch the cached results json.
|
@@ -151,51 +163,28 @@ async fn results(
|
|
151 |
// default selected upstream search engines from the config file otherwise
|
152 |
// parse the non-empty cookie and grab the user selected engines from the
|
153 |
// UI and use that.
|
154 |
-
let mut results: SearchResults = match
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
.
|
160 |
-
.
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
true => {
|
176 |
-
let mut search_results = SearchResults::default();
|
177 |
-
search_results.set_no_engines_selected();
|
178 |
-
search_results
|
179 |
-
}
|
180 |
-
}
|
181 |
}
|
182 |
-
None => aggregate(
|
183 |
-
query,
|
184 |
-
page,
|
185 |
-
config.aggregator.random_delay,
|
186 |
-
config.debug,
|
187 |
-
&config
|
188 |
-
.upstream_search_engines
|
189 |
-
.clone()
|
190 |
-
.into_iter()
|
191 |
-
.filter_map(|(key, value)| value.then_some(key))
|
192 |
-
.map(|engine| EngineHandler::new(&engine))
|
193 |
-
.collect::<Result<Vec<EngineHandler>, error_stack::Report<EngineError>>>(
|
194 |
-
)?,
|
195 |
-
config.request_timeout,
|
196 |
-
safe_search_level,
|
197 |
-
)
|
198 |
-
.await?,
|
199 |
};
|
200 |
if results.engine_errors_info().is_empty()
|
201 |
&& results.results().is_empty()
|
@@ -237,23 +226,24 @@ fn is_match_from_filter_list(
|
|
237 |
Ok(false)
|
238 |
}
|
239 |
|
240 |
-
/// A helper function
|
241 |
-
///
|
|
|
242 |
///
|
243 |
/// # Argurments
|
244 |
///
|
245 |
-
/// * `
|
246 |
-
/// * `
|
247 |
-
/// * `
|
248 |
-
fn get_safesearch_level(
|
249 |
-
match
|
250 |
-
Some(
|
251 |
-
if *
|
252 |
-
|
253 |
} else {
|
254 |
-
*
|
255 |
}
|
256 |
}
|
257 |
-
None =>
|
258 |
}
|
259 |
}
|
|
|
6 |
handler::{file_path, FileType},
|
7 |
models::{
|
8 |
aggregation_models::SearchResults,
|
9 |
+
engine_models::EngineHandler,
|
10 |
+
server_models::{self, SearchParams},
|
11 |
},
|
12 |
results::aggregator::aggregate,
|
13 |
};
|
14 |
use actix_web::{get, http::header::ContentType, web, HttpRequest, HttpResponse};
|
15 |
use regex::Regex;
|
16 |
use std::{
|
17 |
+
borrow::Cow,
|
18 |
fs::File,
|
19 |
io::{BufRead, BufReader, Read},
|
20 |
};
|
|
|
49 |
.finish());
|
50 |
}
|
51 |
|
52 |
+
let cookie = req.cookie("appCookie");
|
53 |
+
|
54 |
+
// Get search settings using the user's cookie or from the server's config
|
55 |
+
let mut search_settings: server_models::Cookie<'_> = cookie
|
56 |
+
.and_then(|cookie_value| serde_json::from_str(cookie_value.value()).ok())
|
57 |
+
.unwrap_or_else(|| {
|
58 |
+
server_models::Cookie::build(
|
59 |
+
&config.style,
|
60 |
+
config
|
61 |
+
.upstream_search_engines
|
62 |
+
.iter()
|
63 |
+
.filter_map(|(engine, enabled)| {
|
64 |
+
enabled.then_some(Cow::Borrowed(engine.as_str()))
|
65 |
+
})
|
66 |
+
.collect(),
|
67 |
+
config.safe_search,
|
68 |
+
)
|
69 |
+
});
|
70 |
+
|
71 |
+
search_settings.safe_search_level = get_safesearch_level(
|
72 |
+
&Some(search_settings.safe_search_level),
|
73 |
+
¶ms.safesearch,
|
74 |
+
config.safe_search,
|
75 |
+
);
|
76 |
+
|
77 |
+
// Closure wrapping the results function capturing local references
|
78 |
+
let get_results = |page| results(&config, &cache, query, page, &search_settings);
|
79 |
|
80 |
// .max(1) makes sure that the page >= 0.
|
81 |
let page = params.page.unwrap_or(1).max(1) - 1;
|
|
|
123 |
cache: &web::Data<SharedCache>,
|
124 |
query: &str,
|
125 |
page: u32,
|
126 |
+
search_settings: &server_models::Cookie<'_>,
|
|
|
127 |
) -> Result<SearchResults, Box<dyn std::error::Error>> {
|
128 |
// eagerly parse cookie value to evaluate safe search level
|
129 |
+
let safe_search_level = search_settings.safe_search_level;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
|
131 |
let cache_key = format!(
|
132 |
+
"http://{}:{}/search?q={}&page={}&safesearch={}&engines={}",
|
133 |
+
config.binding_ip,
|
134 |
+
config.port,
|
135 |
+
query,
|
136 |
+
page,
|
137 |
+
safe_search_level,
|
138 |
+
search_settings.engines.join(",")
|
139 |
);
|
140 |
|
141 |
// fetch the cached results json.
|
|
|
163 |
// default selected upstream search engines from the config file otherwise
|
164 |
// parse the non-empty cookie and grab the user selected engines from the
|
165 |
// UI and use that.
|
166 |
+
let mut results: SearchResults = match search_settings.engines.is_empty() {
|
167 |
+
false => {
|
168 |
+
aggregate(
|
169 |
+
query,
|
170 |
+
page,
|
171 |
+
config.aggregator.random_delay,
|
172 |
+
config.debug,
|
173 |
+
&search_settings
|
174 |
+
.engines
|
175 |
+
.iter()
|
176 |
+
.filter_map(|engine| EngineHandler::new(&engine).ok())
|
177 |
+
.collect::<Vec<EngineHandler>>(),
|
178 |
+
config.request_timeout,
|
179 |
+
safe_search_level,
|
180 |
+
)
|
181 |
+
.await?
|
182 |
+
}
|
183 |
+
true => {
|
184 |
+
let mut search_results = SearchResults::default();
|
185 |
+
search_results.set_no_engines_selected();
|
186 |
+
search_results
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
};
|
189 |
if results.engine_errors_info().is_empty()
|
190 |
&& results.results().is_empty()
|
|
|
226 |
Ok(false)
|
227 |
}
|
228 |
|
229 |
+
/// A helper function to modify the safe search level based on the url params.
|
230 |
+
/// The `safe_search` is the one in the user's cookie or
|
231 |
+
/// the default set by the server config if the cookie was missing.
|
232 |
///
|
233 |
/// # Argurments
|
234 |
///
|
235 |
+
/// * `url_level` - Safe search level from the url.
|
236 |
+
/// * `safe_search` - User's cookie, or the safe search level set by the server
|
237 |
+
/// * `config_level` - Safe search level to fall back to
|
238 |
+
fn get_safesearch_level(cookie_level: &Option<u8>, url_level: &Option<u8>, config_level: u8) -> u8 {
|
239 |
+
match url_level {
|
240 |
+
Some(url_level) => {
|
241 |
+
if *url_level >= 3 {
|
242 |
+
config_level
|
243 |
} else {
|
244 |
+
*url_level
|
245 |
}
|
246 |
}
|
247 |
+
None => cookie_level.unwrap_or(config_level),
|
248 |
}
|
249 |
}
|